diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d534c1b3..61a2e7b2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,72 +1,44 @@ -name: Test +name: Rust Test on: [push, pull_request] -# This will cancel previous runs when a branch or PR is updated -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }} - cancel-in-progress: true - jobs: - test: - name: Test on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - timeout-minutes: 40 - env: - CACHED_PATH: /tmp/nix-cache - + test_ubuntu: + name: Test on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Rust + uses: dtolnay/rust-toolchain@1.66.0 + with: + target: x86_64-unknown-linux-gnu + + - name: Run tests + env: + RUST_TEST_THREADS: 1 + run: | + cargo test + + test_mac: + name: Test on macOS + runs-on: macos-latest strategy: - fail-fast: false matrix: - include: - - os: ubuntu-latest - target: x86_64-linux - - os: macos-latest - target: x86_64-darwin + target: [x86_64-apple-darwin, aarch64-apple-darwin] steps: - - name: Checkout - uses: actions/checkout@v3 - - - uses: cachix/install-nix-action@v22 - with: - nix_path: nixpkgs=channel:nixos-22.11 - github_access_token: ${{ secrets.GITHUB_TOKEN }} - - - uses: cachix/cachix-action@v12 - with: - name: barretenberg - - - name: Restore nix store cache - uses: actions/cache/restore@v3 - id: cache - with: - path: ${{ env.CACHED_PATH }} - key: ${{ runner.os }}-flake-${{ hashFiles('*.lock') }} - - # Based on https://github.com/marigold-dev/deku/blob/b5016f0cf4bf6ac48db9111b70dd7fb49b969dfd/.github/workflows/build.yml#L26 - - name: Copy cache into nix store - if: steps.cache.outputs.cache-hit == 'true' - # We don't check the signature because we're the one that created the cache - run: | - for narinfo in ${{ env.CACHED_PATH }}/*.narinfo; do - path=$(head -n 1 "$narinfo" | awk '{print $2}') - nix copy --no-check-sigs --from "file://${{ env.CACHED_PATH }}" "$path" - done - - - name: Run `nix flake check` - run: | - nix flake check -L - - - name: Export cache from nix store - if: ${{ always() && steps.cache.outputs.cache-hit != 'true' }} - run: | - nix copy --to "file:///tmp/nix-cache?compression=zstd¶llel-compression=true" .#native-cargo-artifacts - nix copy --to "file:///tmp/nix-cache?compression=zstd¶llel-compression=true" .#wasm-cargo-artifacts - - - uses: actions/cache/save@v3 - # Write a cache entry even if the tests fail but don't create any for the merge queue. - if: ${{ always() && steps.cache.outputs.cache-hit != 'true' }} - with: - path: ${{ env.CACHED_PATH }} - key: ${{ steps.cache.outputs.cache-primary-key }} + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Rust + uses: dtolnay/rust-toolchain@1.66.0 + with: + target: ${{ matrix.target }} + + - name: Run tests + env: + RUST_TEST_THREADS: 1 + run: | + cargo test diff --git a/Cargo.lock b/Cargo.lock index 6aab4e39..9c1c8a90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "acir" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86577747c44f23e2e8e6d972287d01341c0eea42a78ce15c5efd212a39d0fc27" +checksum = "2dab15381940b2eb3ecca70e78adcfb547df5b49123b2872c2333b0ee965beae" dependencies = [ "acir_field", "bincode", @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4239156a8eddd55b2ae8bd25aa169d012bae70e0fd7c635f08f68ada54a8cb6c" +checksum = "16ae84a2d0f6e5087a499c56d41ca8227fd26abea01b527694c601b230b27111" dependencies = [ "ark-bn254", "ark-ff", @@ -32,14 +32,13 @@ dependencies = [ [[package]] name = "acvm" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74351bab6e0fd2ec1bd631abc73260f374cc28d2baf85c0e11300c0c989d5e53" +checksum = "1cc5bd62182c728ec5d3a080319765b0c86f294fc74f90fd6657008ae789d797" dependencies = [ "acir", "acvm_blackbox_solver", "acvm_stdlib", - "async-trait", "brillig_vm", "indexmap", "num-bigint", @@ -52,40 +51,46 @@ name = "acvm-backend-barretenberg" version = "0.11.0" dependencies = [ "acvm", - "barretenberg-sys", - "bincode", - "bytesize", - "getrandom", - "pkg-config", + "base64", + "build-target", + "const_format", + "dirs 5.0.1", + "flate2", "reqwest", - "rust-embed", - "serde", - "serde-big-array", + "tar", + "tempfile", "thiserror", - "tokio", - "wasmer", ] [[package]] name = "acvm_blackbox_solver" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a362499180c6498acc0ebf77bd919be8ccd9adabc84a695d4af44ca180ba0709" +checksum = "b79e031466b5075260257a61359eb9775c5ef92dce27621af1c36bfd0a6eb511" dependencies = [ "acir", "blake2", + "flate2", + "getrandom", + "js-sys", "k256", "p256", + "pkg-config", + "reqwest", + "rust-embed", "sha2", "sha3", + "tar", "thiserror", + "wasm-bindgen-futures", + "wasmer", ] [[package]] name = "acvm_stdlib" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e485b3bc3331eaa10bc92fb092ca14275936c8935c3ae7ec89fb0bd48246ab42" +checksum = "1389b884c07b5eb0c15e5f5395317de060bcf1a6a5f476893c4d65f50de5de1f" dependencies = [ "acir", ] @@ -129,18 +134,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "aho-corasick" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] @@ -268,17 +264,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "async-trait" -version = "0.1.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.23", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -300,20 +285,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "barretenberg-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f8fd58d1ca43e920a1a3b55d52c65ac25cd29f2820d4b2b1c24adafa2c403c" -dependencies = [ - "bindgen", - "cc", - "color-eyre", - "link-cplusplus", - "pkg-config", - "thiserror", -] - [[package]] name = "base16ct" version = "0.1.1" @@ -342,32 +313,16 @@ dependencies = [ ] [[package]] -name = "bindgen" -version = "0.64.0" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 1.0.109", - "which", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "1.3.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" @@ -401,9 +356,9 @@ dependencies = [ [[package]] name = "brillig" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64df3df7d2d96fc2519e4dd64bc6bc23eee2949ee86725d9041ef7703c283ab" +checksum = "dd5fe44d05264a0d9a6d5c5dca8a6c976f3fcdfdfb0244d75e458bf13fcb8f21" dependencies = [ "acir_field", "serde", @@ -411,9 +366,9 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b306b3d79b6da192fd2ed68b94ab07712496f39bb5d50fedce44dac3f4953065" +checksum = "733be2c7fea117e0b0be985b9b99c15aeca01fb342528fac9c3f70a7f844ec50" dependencies = [ "acir", "acvm_blackbox_solver", @@ -431,6 +386,12 @@ dependencies = [ "serde", ] +[[package]] +name = "build-target" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b" + [[package]] name = "bumpalo" version = "3.13.0" @@ -471,27 +432,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" -[[package]] -name = "bytesize" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38fcc2979eff34a4b84e1cf9a1e3da42a7d44b3b690a40cdcb23e3d556cfb2e5" - [[package]] name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -499,54 +445,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "clang-sys" -version = "1.6.1" +name = "const-oid" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" -dependencies = [ - "glob", - "libc", - "libloading", -] +checksum = "6340df57935414636969091153f35f68d9f00bbc8fb4a9c6054706c213e6c6bc" [[package]] -name = "color-eyre" -version = "0.6.2" +name = "const_format" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +checksum = "c990efc7a285731f9a4378d81aff2f0e85a2c8781a05ef0f8baa8dac54d0ff48" dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", + "const_format_proc_macros", ] [[package]] -name = "color-spantrace" -version = "0.2.0" +name = "const_format_proc_macros" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +checksum = "e026b6ce194a874cb9cf32cd5772d1ef9767cc8fcb5765948d74f37a9d8b2bf6" dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", + "proc-macro2", + "quote", + "unicode-xid", ] -[[package]] -name = "const-oid" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6340df57935414636969091153f35f68d9f00bbc8fb4a9c6054706c213e6c6bc" - [[package]] name = "corosensei" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9847f90f32a50b0dcbd68bc23ff242798b13080b97b0569f6ed96a45ce4cf2cd" +checksum = "80128832c58ea9cbd041d2a759ec449224487b2c1e400453d99d244eead87a8e" dependencies = [ "autocfg", "cfg-if", @@ -723,9 +651,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ "darling_core", "darling_macro", @@ -733,9 +661,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", @@ -746,9 +674,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", @@ -757,9 +685,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.0" +version = "5.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" +checksum = "9b101bb8960ab42ada6ae98eb82afcea4452294294c45b681295af26610d6d28" dependencies = [ "cfg-if", "hashbrown 0.14.0", @@ -806,7 +734,16 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ - "dirs-sys", + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", ] [[package]] @@ -820,6 +757,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "ecdsa" version = "0.14.8" @@ -909,13 +858,24 @@ dependencies = [ ] [[package]] -name = "eyre" -version = "0.6.8" +name = "errno" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ - "indenter", - "once_cell", + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", ] [[package]] @@ -924,6 +884,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + [[package]] name = "ff" version = "0.12.1" @@ -934,6 +900,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "filetime" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "windows-sys 0.48.0", +] + [[package]] name = "flate2" version = "1.0.26" @@ -980,6 +958,12 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + [[package]] name = "futures-macro" version = "0.3.28" @@ -1010,8 +994,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", + "futures-io", "futures-macro", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -1043,8 +1029,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1064,19 +1052,13 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "globset" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick", "bstr", "fnv", "log", @@ -1209,7 +1191,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -1246,12 +1228,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - [[package]] name = "indexmap" version = "1.9.3" @@ -1319,12 +1295,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "leb128" version = "0.2.5" @@ -1338,23 +1308,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.9" +name = "linux-raw-sys" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" -dependencies = [ - "cc", -] +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lock_api" @@ -1420,12 +1377,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1452,16 +1403,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -1518,10 +1459,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] -name = "owo-colors" -version = "3.5.0" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "p256" @@ -1553,12 +1494,6 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "percent-encoding" version = "2.3.0" @@ -1567,9 +1502,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1724,7 +1659,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1733,7 +1668,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1761,11 +1696,11 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick", "memchr", "regex-automata", "regex-syntax", @@ -1773,20 +1708,20 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.0" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "region" @@ -1794,7 +1729,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "mach", "winapi", @@ -1945,12 +1880,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc_version" version = "0.4.0" @@ -1960,6 +1889,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustls" version = "0.21.3" @@ -2008,9 +1950,9 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -2044,9 +1986,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" @@ -2057,15 +1999,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-big-array" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" -dependencies = [ - "serde", -] - [[package]] name = "serde-wasm-bindgen" version = "0.4.5" @@ -2132,30 +2065,15 @@ dependencies = [ "keccak", ] -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - [[package]] name = "shellexpand" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" dependencies = [ - "dirs", + "dirs 4.0.0", ] -[[package]] -name = "shlex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" - [[package]] name = "signature" version = "1.6.4" @@ -2203,6 +2121,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -2259,11 +2187,35 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" -version = "0.12.8" +version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1c7f239eb94671427157bd93b3694320f3668d4e1eff08c7285366fd777fac" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" + +[[package]] +name = "tempfile" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.48.0", +] [[package]] name = "thiserror" @@ -2285,16 +2237,6 @@ dependencies = [ "syn 2.0.23", ] -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -2312,32 +2254,20 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", + "num_cpus", "pin-project-lite", - "socket2", - "tokio-macros", + "socket2 0.5.3", "windows-sys 0.48.0", ] -[[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.23", -] - [[package]] name = "tokio-rustls" version = "0.24.1" @@ -2398,28 +2328,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", ] [[package]] @@ -2461,6 +2369,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "untrusted" version = "0.7.1" @@ -2480,15 +2394,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" [[package]] name = "version_check" @@ -2612,9 +2520,9 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-encoder" -version = "0.29.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881" +checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" dependencies = [ "leb128", ] @@ -2643,6 +2551,8 @@ dependencies = [ "wasmer-derive", "wasmer-types", "wasmer-vm", + "wasmparser 0.83.0", + "wasmparser 0.95.0", "wat", "winapi", ] @@ -2666,7 +2576,7 @@ dependencies = [ "thiserror", "wasmer-types", "wasmer-vm", - "wasmparser", + "wasmparser 0.95.0", "winapi", ] @@ -2744,6 +2654,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "wasmparser" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" + [[package]] name = "wasmparser" version = "0.95.0" @@ -2756,9 +2672,9 @@ dependencies = [ [[package]] name = "wast" -version = "60.0.0" +version = "64.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd06cc744b536e30387e72a48fdd492105b9c938bb4f415c39c616a7a0a697ad" +checksum = "a259b226fd6910225aa7baeba82f9d9933b6d00f2ce1b49b80fa4214328237cc" dependencies = [ "leb128", "memchr", @@ -2768,9 +2684,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.66" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5abe520f0ab205366e9ac7d3e6b2fc71de44e32a2b58f2ec871b6b575bdcea3b" +checksum = "53253d920ab413fca1c7dc2161d601c79b4fdf631d0ba51dd4343bf9b556c3f6" dependencies = [ "wast", ] @@ -2804,17 +2720,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] - [[package]] name = "winapi" version = "0.3.9" @@ -2973,6 +2878,15 @@ dependencies = [ "tap", ] +[[package]] +name = "xattr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +dependencies = [ + "libc", +] + [[package]] name = "zeroize" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 5f6af444..0821641e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,35 +13,21 @@ license = "MIT OR Apache-2.0" crate-type = ["cdylib", "lib"] [dependencies] -acvm = { version = "0.22.0", features = ["bn254"] } -bincode = "1.3.3" -bytesize = "1.2" -reqwest = { version = "0.11.16", default-features = false, features = [ - "rustls-tls", -] } -serde = { version = "1.0.136", features = ["derive"] } -serde-big-array = "0.5.1" +acvm = { version = "0.23.0", features = ["bn254"] } thiserror = "1.0.21" +base64 = "0.21.2" -# Native -barretenberg-sys = { version = "0.2.0", optional = true } +dirs = "5.0.1" +tempfile = "3.6.0" -# Wasm -getrandom = { version = "0.2", optional = true } -rust-embed = { version = "6.6.0", optional = true, features = [ - "debug-embed", - "interpolate-folder-path", - "include-exclude", +## bb binary downloading +const_format = "0.2.30" +tar = "~0.4.15" +flate2 = "~1.0.1" +reqwest = { version = "0.11.16", default-features = false, features = [ + "rustls-tls", + "blocking", ] } -wasmer = { version = "3.3", optional = true } [build-dependencies] -pkg-config = "0.3" - -[dev-dependencies] -tokio = { version = "1.0", features = ["macros"] } - -[features] -default = ["native"] -native = ["dep:barretenberg-sys"] -wasm = ["dep:wasmer", "dep:rust-embed", "dep:getrandom"] +build-target = "0.4.0" diff --git a/build.rs b/build.rs index 38479209..b5995f27 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,4 @@ -use std::env; +use build_target::{Arch, Os}; // Useful for printing debugging messages during the build // macro_rules! p { @@ -8,24 +8,25 @@ use std::env; // } fn main() -> Result<(), String> { - let native_backend = env::var("CARGO_FEATURE_NATIVE").is_ok(); + // We need to inject which OS we're building for so that we can download the correct barretenberg binary. + let os = match build_target::target_os().unwrap() { + os @ (Os::Linux | Os::MacOs) => os, + Os::Windows => todo!("Windows is not currently supported"), + os_name => panic!("Unsupported OS {}", os_name), + }; - if native_backend { - Ok(()) - } else { - match env::var("BARRETENBERG_BIN_DIR") { - Ok(bindir) => { - println!("cargo:rustc-env=BARRETENBERG_BIN_DIR={bindir}"); - Ok(()) - } - Err(_) => { - if let Ok(bindir) = pkg_config::get_variable("barretenberg", "bindir") { - println!("cargo:rustc-env=BARRETENBERG_BIN_DIR={bindir}"); - Ok(()) - } else { - Err("Unable to locate barretenberg.wasm - Please set the BARRETENBERG_BIN_DIR env var to the directory where it exists".into()) - } - } - } - } + let arch = match build_target::target_arch().unwrap() { + arch @ (Arch::X86_64 | Arch::AARCH64) => arch, + arch_name => panic!("Unsupported Architecture {}", arch_name), + }; + + // Arm builds of linux are not supported + if let (Os::Linux, Arch::AARCH64) = (&os, &arch) { + panic!("ARM64 builds of linux are not supported") + }; + + println!("cargo:rustc-env=TARGET_OS={os}"); + println!("cargo:rustc-env=TARGET_ARCH={arch}"); + + Ok(()) } diff --git a/flake.lock b/flake.lock index 659daec5..23a701d4 100644 --- a/flake.lock +++ b/flake.lock @@ -10,15 +10,16 @@ ] }, "locked": { - "lastModified": 1688820427, - "narHash": "sha256-w7yMeYp50KrlTn23TTKfYmLOQL4uIgw0wSX67v2tvvc=", + "lastModified": 1693320399, + "narHash": "sha256-P6xsi4OzfVBWQF/gHt4u2dMyKOPbCMoJ7n9URzMvkik=", "owner": "AztecProtocol", "repo": "barretenberg", - "rev": "fdd46f77531a6fcc9d9b24a698c56590d54d487e", + "rev": "051449fe181bf53e2cfebc15c6b9bd01cc44fc50", "type": "github" }, "original": { "owner": "AztecProtocol", + "ref": "barretenberg-v0.4.6", "repo": "barretenberg", "type": "github" } diff --git a/flake.nix b/flake.nix index 0e9d89b0..9b62b7ff 100644 --- a/flake.nix +++ b/flake.nix @@ -38,7 +38,7 @@ }; barretenberg = { - url = "github:AztecProtocol/barretenberg"; + url = "github:AztecProtocol/barretenberg?ref=barretenberg-v0.4.6"; # 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 = { @@ -77,21 +77,14 @@ RUST_TEST_THREADS = "1"; }; - nativeEnvironment = sharedEnvironment // { - # rust-bindgen needs to know the location of libclang - LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; - }; - - wasmEnvironment = sharedEnvironment // { - # We set the environment variable because barretenberg must be compiled in a special way for wasm - BARRETENBERG_BIN_DIR = "${pkgs.barretenberg-wasm}/bin"; - }; - # We use `include_str!` macro to embed the solidity verifier template so we need to create a special - # source filter to include .sol files in addition to usual rust/cargo source files + # source filter to include .sol files in addition to usual rust/cargo source files. solidityFilter = path: _type: builtins.match ".*sol$" path != null; + # We use `.bytecode` and `.tr` files to test interactions with `bb` so we add a source filter to include these. + bytecodeFilter = path: _type: builtins.match ".*bytecode$" path != null; + witnessFilter = path: _type: builtins.match ".*tr$" path != null; sourceFilter = path: type: - (solidityFilter path type) || (craneLib.filterCargoSources path type); + (solidityFilter path type) || (bytecodeFilter path type)|| (witnessFilter path type) || (craneLib.filterCargoSources path type); # 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++ @@ -105,6 +98,12 @@ # Need libiconv and apple Security on Darwin. See https://github.com/ipetkov/crane/issues/156 pkgs.libiconv pkgs.darwin.apple_sdk.frameworks.Security + ] ++ [ + # Need to install various packages used by the `bb` binary. + pkgs.curl + stdenv.cc.cc.lib + pkgs.gcc.cc.lib + pkgs.gzip ]; commonArgs = { @@ -124,41 +123,65 @@ }; # Combine the environment and other configuration needed for crane to build with the native feature - nativeArgs = nativeEnvironment // commonArgs // { + nativeArgs = sharedEnvironment // commonArgs // { # Use our custom stdenv to build and test our Rust project inherit stdenv; - nativeBuildInputs = [ - # This provides the pkg-config tool to find barretenberg & other native libraries - pkgs.pkg-config - # This provides the `lld` linker to cargo - pkgs.llvmPackages.bintools + nativeBuildInputs = pkgs.lib.optionals stdenv.isLinux [ + # This is linux specific and used to patch the rpath and interpreter of the bb binary + pkgs.patchelf ]; buildInputs = [ pkgs.llvmPackages.openmp - pkgs.barretenberg ] ++ extraBuildInputs; }; + + # Conditionally download the binary based on whether it is linux or mac + bb_binary = let + platformSpecificUrl = if stdenv.hostPlatform.isLinux then + "https://github.com/AztecProtocol/barretenberg/releases/download/barretenberg-v0.4.6/barretenberg-x86_64-linux-gnu.tar.gz" + else if stdenv.hostPlatform.isDarwin then + "https://github.com/AztecProtocol/barretenberg/releases/download/barretenberg-v0.4.6/barretenberg-x86_64-apple-darwin.tar.gz" + else + throw "Unsupported platform"; - # Combine the environment and other configuration needed for crane to build with the wasm feature - wasmArgs = wasmEnvironment // commonArgs // { - # We disable the default "native" feature and enable the "wasm" feature - cargoExtraArgs = "--no-default-features --features='wasm'"; - - buildInputs = [ ] ++ extraBuildInputs; + platformSpecificHash = if stdenv.hostPlatform.isLinux then + "sha256:1p15v6rvf9195047pfbw8dns3z6s54q4c9hgbxan72lhjjgjz800" + else if stdenv.hostPlatform.isDarwin then + "sha256:03d9rsmhvzaz7ni8ac9hf3adc2dw57nv6q406v4l49g1rd354dm0" + else + throw "Unsupported platform"; + in builtins.fetchurl { + url = platformSpecificUrl; + sha256 = platformSpecificHash; }; + # The `port` is parameterized to support parallel test runs without colliding static servers networkTestArgs = port: { - # We provide `barretenberg-transcript00` from the overlay to the tests as a URL hosted via a static server - # This is necessary because the Nix sandbox has no network access and downloading during tests would fail - TRANSCRIPT_URL = "http://0.0.0.0:${toString port}/${builtins.baseNameOf pkgs.barretenberg-transcript00}"; + BB_BINARY_PATH = "./backend_binary"; + + BB_BINARY_URL = "http://0.0.0.0:${toString port}/${builtins.baseNameOf bb_binary}"; + + BARRETENBERG_TRANSCRIPT_URL = "http://0.0.0.0:${toString port}/${builtins.baseNameOf pkgs.barretenberg-transcript00}"; - # This copies the `barretenberg-transcript00` from the Nix store into this sandbox - # which avoids exposing the entire Nix store to the static server it starts - # The static server is moved to the background and killed after checks are completed preCheck = '' + echo "Extracting bb binary" + mkdir extracted + tar -xf ${bb_binary} -C extracted + cp extracted/bb ./backend_binary + + # Conditionally patch the binary for Linux + ${if stdenv.hostPlatform.isLinux then '' + echo "Patching bb binary for Linux" + patchelf --set-rpath "${stdenv.cc.cc.lib}/lib:${pkgs.gcc.cc.lib}/lib" ./backend_binary + patchelf --set-interpreter ${stdenv.cc.libc}/lib/ld-linux-x86-64.so.2 ./backend_binary + '' else if stdenv.hostPlatform.isDarwin then '' + '' else + throw "Unsupported platform" + } + cp ${pkgs.barretenberg-transcript00} . echo "Starting simple static server" ${pkgs.simple-http-server}/bin/simple-http-server --port ${toString port} --silent & @@ -172,14 +195,10 @@ # Build *just* the cargo dependencies, so we can reuse all of that work between runs native-cargo-artifacts = craneLib.buildDepsOnly nativeArgs; - wasm-cargo-artifacts = craneLib.buildDepsOnly wasmArgs; - + acvm-backend-barretenberg-native = craneLib.buildPackage (nativeArgs // { cargoArtifacts = native-cargo-artifacts; }); - acvm-backend-barretenberg-wasm = craneLib.buildPackage (wasmArgs // { - cargoArtifacts = native-cargo-artifacts; - }); in rec { checks = { @@ -201,45 +220,26 @@ # It's unclear why doCheck needs to be enabled for tests to run but not clippy doCheck = true; }); - - cargo-clippy-wasm = craneLib.cargoClippy (wasmArgs // { - # Crane appends "clippy" - pname = "wasm"; - - cargoArtifacts = wasm-cargo-artifacts; - - cargoClippyExtraArgs = "--all-targets -- -D warnings"; - }); - - cargo-test-wasm = craneLib.cargoTest (wasmArgs // (networkTestArgs 8001) // { - # Crane appends "test" - pname = "wasm"; - - cargoArtifacts = wasm-cargo-artifacts; - - # It's unclear why doCheck needs to be enabled for tests to run but not clippy - doCheck = true; - }); }; packages = { inherit acvm-backend-barretenberg-native; - inherit acvm-backend-barretenberg-wasm; default = acvm-backend-barretenberg-native; # We expose the `*-cargo-artifacts` derivations so we can cache our cargo dependencies in CI inherit native-cargo-artifacts; - inherit wasm-cargo-artifacts; }; # Setup the environment to match the stdenv from `nix build` & `nix flake check`, and # combine it with the environment settings, the inputs from our checks derivations, # and extra tooling via `nativeBuildInputs` - devShells.default = pkgs.mkShell.override { inherit stdenv; } (nativeEnvironment // wasmEnvironment // { + devShells.default = pkgs.mkShell.override { inherit stdenv; } (sharedEnvironment // { inputsFrom = builtins.attrValues checks; nativeBuildInputs = with pkgs; [ + curl + gzip which starship git diff --git a/src/1_mul.bytecode b/src/1_mul.bytecode new file mode 100644 index 00000000..fc187410 --- /dev/null +++ b/src/1_mul.bytecode @@ -0,0 +1 @@ +H4sIAAAAAAAA/+2Z326CMBTGP2SIyCTLsmw3u+ARWv5ouZuPMjN8/0fYyFo5MHbFV6KJJyG1jf16/vT8NPoG4B2/Fvw8KzvmYr4azUM7D+0Dsb+zDzuqeabdeeDqKkzYTG3tUftyhszFgx0jsZbY0dWss7WoTSj2HsW+QIyB0DiKPVPvCf7RScSa258JX8DLiVqDfu9UJjTZDl8udVeEHH1TRXYO+GuksW6p9lXVHopWl/pTFc3J1KqqT3ujja5N/VWYsmxNZQ7NqTmoRldlq891U56t8BP8NGXI8bOwfuoHYswRsS7M/PmGcYQhbFh+Y8Jmai8OYwe2WKzdYczRXATGneM5ehjH8Adj10hsGD/jNmC8JsYcE+vCzJ9vGMcYwoblNyZspvbiMN7YUYLvDmOO5iIw7gqYo4dxAn8wdo3EhvELbgPGG2LMCbEuzPz5hnGCYWOz/MaEzdReHMZbO6Zi7Q5jjuYiMO4KmKOHcQp/MHaNxIbxK24DxltizCmxLleev0vMITHmlOjXI7gfZn+aHvxeZPos/d2J1+437NXEnfAATI3ROeM8egWqryLtPOhm4F1+X3Fn/BoN4HTNOZXfdtwfcmP7BvHx78jZGwAA \ No newline at end of file diff --git a/src/barretenberg/composer.rs b/src/barretenberg/composer.rs deleted file mode 100644 index a564cfcf..00000000 --- a/src/barretenberg/composer.rs +++ /dev/null @@ -1,1024 +0,0 @@ -use acvm::async_trait; - -use super::crs::{download_crs, CRS}; -use super::{Barretenberg, Error, FIELD_BYTES}; -use crate::barretenberg_structures::{Assignments, ConstraintSystem}; - -const NUM_RESERVED_GATES: u32 = 4; // this must be >= num_roots_cut_out_of_vanishing_polynomial (found under prover settings in barretenberg) - -#[async_trait(?Send)] -pub(crate) trait Composer { - fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result; - - fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result; - - async fn get_crs(&self, constraint_system: &ConstraintSystem) -> Result { - let num_points = self.get_circuit_size(constraint_system)?; - - download_crs(num_points as usize).await - } - - async fn update_crs<'a>( - &self, - crs: &'a mut CRS, - constraint_system: &ConstraintSystem, - ) -> Result<&'a CRS, Error> { - let num_points = self.get_circuit_size(constraint_system)?; - - if crs.num_points < num_points as usize { - crs.update(num_points as usize).await?; - } - - Ok(crs) - } - - fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error>; - fn compute_verification_key(&self, crs: &CRS, proving_key: &[u8]) -> Result, Error>; - - fn create_proof_with_pk( - &self, - crs: &CRS, - constraint_system: &ConstraintSystem, - witness: Assignments, - proving_key: &[u8], - ) -> Result, Error>; - - fn verify_with_vk( - &self, - crs: &CRS, - constraint_system: &ConstraintSystem, - // XXX: Important: This assumes that the proof does not have the public inputs pre-pended to it - // This is not the case, if you take the proof directly from Barretenberg - proof: &[u8], - public_inputs: Assignments, - verification_key: &[u8], - ) -> Result; -} - -#[cfg(feature = "native")] -impl Composer for Barretenberg { - // XXX: There seems to be a bug in the C++ code - // where it causes a `HeapAccessOutOfBound` error - // for certain circuit sizes. - // - // This method calls the WASM for the circuit size - // if an error is returned, then the circuit size is defaulted to 2^19. - // - // This method is primarily used to determine how many group - // elements we need from the CRS. So using 2^19 on an error - // should be an overestimation. - fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { - let cs_buf = constraint_system.to_bytes(); - - let circuit_size; - unsafe { - circuit_size = - barretenberg_sys::composer::get_total_circuit_size(cs_buf.as_slice().as_ptr()); - } - - pow2ceil(circuit_size + NUM_RESERVED_GATES) - } - - fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { - let cs_buf = constraint_system.to_bytes(); - - let circuit_size; - unsafe { - circuit_size = - barretenberg_sys::composer::get_exact_circuit_size(cs_buf.as_slice().as_ptr()) - } - - Ok(circuit_size) - } - - fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error> { - let cs_buf = constraint_system.to_bytes(); - - let mut pk_addr: *mut u8 = std::ptr::null_mut(); - let pk_ptr = &mut pk_addr as *mut *mut u8; - - let pk_size; - unsafe { - pk_size = barretenberg_sys::composer::init_proving_key(&cs_buf, pk_ptr); - } - - let result; - unsafe { - result = Vec::from_raw_parts(pk_addr, pk_size, pk_size); - } - Ok(result) - } - - fn compute_verification_key(&self, crs: &CRS, proving_key: &[u8]) -> Result, Error> { - let CRS { - g1_data, g2_data, .. - } = crs; - let pippenger_ptr = self.get_pippenger(g1_data)?.pointer(); - - let mut vk_addr: *mut u8 = std::ptr::null_mut(); - let vk_ptr = &mut vk_addr as *mut *mut u8; - - let vk_size; - unsafe { - vk_size = barretenberg_sys::composer::init_verification_key( - pippenger_ptr, - g2_data, - proving_key, - vk_ptr, - ) - } - - let result; - unsafe { - result = Vec::from_raw_parts(vk_addr, vk_size, vk_size); - } - Ok(result.to_vec()) - } - - fn create_proof_with_pk( - &self, - crs: &CRS, - constraint_system: &ConstraintSystem, - witness: Assignments, - proving_key: &[u8], - ) -> Result, Error> { - let CRS { - g1_data, g2_data, .. - } = crs; - let pippenger_ptr = self.get_pippenger(g1_data)?.pointer(); - let cs_buf: Vec = constraint_system.to_bytes(); - let witness_buf = witness.to_bytes(); - - let mut proof_addr: *mut u8 = std::ptr::null_mut(); - let p_proof = &mut proof_addr as *mut *mut u8; - - let proof_size; - unsafe { - proof_size = barretenberg_sys::composer::create_proof_with_pk( - pippenger_ptr, - g2_data, - proving_key, - &cs_buf, - &witness_buf, - p_proof, - ); - } - - let result; - unsafe { - result = Vec::from_raw_parts(proof_addr, proof_size, proof_size); - } - - // Barretenberg returns proofs which are prepended with the public inputs. - // This behavior is nonstandard so we strip the public inputs from the proof. - Ok(remove_public_inputs( - constraint_system.public_inputs_size(), - &result, - )) - } - - fn verify_with_vk( - &self, - crs: &CRS, - constraint_system: &ConstraintSystem, - // XXX: Important: This assumes that the proof does not have the public inputs pre-pended to it - // This is not the case, if you take the proof directly from Barretenberg - proof: &[u8], - public_inputs: Assignments, - verification_key: &[u8], - ) -> Result { - let CRS { g2_data, .. } = crs; - - // Barretenberg expects public inputs to be prepended onto the proof - let proof = prepend_public_inputs(proof.to_vec(), public_inputs); - let cs_buf = constraint_system.to_bytes(); - - let verified; - unsafe { - verified = barretenberg_sys::composer::verify_with_vk( - g2_data, - verification_key, - &cs_buf, - &proof, - ); - } - Ok(verified) - } -} - -#[cfg(not(feature = "native"))] -impl Composer for Barretenberg { - // XXX: There seems to be a bug in the C++ code - // where it causes a `HeapAccessOutOfBound` error - // for certain circuit sizes. - // - // This method calls the WASM for the circuit size - // if an error is returned, then the circuit size is defaulted to 2^19. - // - // This method is primarily used to determine how many group - // elements we need from the CRS. So using 2^19 on an error - // should be an overestimation. - fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { - let cs_buf = constraint_system.to_bytes(); - let cs_ptr = self.allocate(&cs_buf)?; - - // This doesn't unwrap the result because we need to free even if there is a failure - let circuit_size = self.call("acir_proofs_get_total_circuit_size", &cs_ptr); - - self.free(cs_ptr)?; - - let size: u32 = circuit_size?.try_into()?; - - pow2ceil(size + NUM_RESERVED_GATES) - } - - fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { - let cs_buf = constraint_system.to_bytes(); - let cs_ptr = self.allocate(&cs_buf)?; - - // This doesn't unwrap the result because we need to free even if there is a failure - let circuit_size = self.call("acir_proofs_get_exact_circuit_size", &cs_ptr); - - self.free(cs_ptr)?; - - Ok(circuit_size?.try_into()?) - } - - fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error> { - let cs_buf = constraint_system.to_bytes(); - let cs_ptr = self.allocate(&cs_buf)?; - - // The proving key is not actually written to this pointer. - // `pk_ptr_ptr` is a pointer to a pointer which holds the proving key. - let pk_ptr_ptr: usize = 0; - - let pk_size = self.call_multiple( - "acir_proofs_init_proving_key", - vec![&cs_ptr, &pk_ptr_ptr.into()], - )?; - - // We then need to read the pointer at `pk_ptr_ptr` to get the key's location - // and then slice memory again at `pk_ptr` to get the proving key. - let pk_ptr = self.get_pointer(pk_ptr_ptr); - - Ok(self.read_memory_variable_length(pk_ptr, pk_size.try_into()?)) - } - - fn compute_verification_key(&self, crs: &CRS, proving_key: &[u8]) -> Result, Error> { - let CRS { - g1_data, g2_data, .. - } = crs; - let pippenger_ptr = self.get_pippenger(g1_data)?.pointer(); - - let g2_ptr = self.allocate(g2_data)?; - let pk_ptr = self.allocate(proving_key)?; - - // The verification key is not actually written to this pointer. - // `vk_ptr_ptr` is a pointer to a pointer which holds the verification key. - let vk_ptr_ptr: usize = 0; - - let vk_size = self.call_multiple( - "acir_proofs_init_verification_key", - vec![&pippenger_ptr, &g2_ptr, &pk_ptr, &vk_ptr_ptr.into()], - )?; - - // We then need to read the pointer at `vk_ptr_ptr` to get the key's location - // and then slice memory again at `vk_ptr` to get the verification key. - let vk_ptr = self.get_pointer(vk_ptr_ptr); - - Ok(self.read_memory_variable_length(vk_ptr, vk_size.try_into()?)) - } - - fn create_proof_with_pk( - &self, - crs: &CRS, - constraint_system: &ConstraintSystem, - witness: Assignments, - proving_key: &[u8], - ) -> Result, Error> { - let CRS { - g1_data, g2_data, .. - } = crs; - let pippenger_ptr = self.get_pippenger(g1_data)?.pointer(); - let cs_buf: Vec = constraint_system.to_bytes(); - let witness_buf = witness.to_bytes(); - - let cs_ptr = self.allocate(&cs_buf)?; - let witness_ptr = self.allocate(&witness_buf)?; - let g2_ptr = self.allocate(g2_data)?; - let pk_ptr = self.allocate(proving_key)?; - - // The proof data is not actually written to this pointer. - // `proof_ptr_ptr` is a pointer to a pointer which holds the proof data. - let proof_ptr_ptr: usize = 0; - - let proof_size = self.call_multiple( - "acir_proofs_new_proof", - vec![ - &pippenger_ptr, - &g2_ptr, - &pk_ptr, - &cs_ptr, - &witness_ptr, - &proof_ptr_ptr.into(), - ], - )?; - - // We then need to read the pointer at `proof_ptr_ptr` to get the proof's location - // and then slice memory again at `proof_ptr` to get the proof data. - let proof_ptr = self.get_pointer(proof_ptr_ptr); - - let result = self.read_memory_variable_length(proof_ptr, proof_size.try_into()?); - - // Barretenberg returns proofs which are prepended with the public inputs. - // This behavior is nonstandard so we strip the public inputs from the proof. - Ok(remove_public_inputs( - constraint_system.public_inputs_size(), - &result, - )) - } - - fn verify_with_vk( - &self, - crs: &CRS, - constraint_system: &ConstraintSystem, - // XXX: Important: This assumes that the proof does not have the public inputs pre-pended to it - // This is not the case, if you take the proof directly from Barretenberg - proof: &[u8], - public_inputs: Assignments, - verification_key: &[u8], - ) -> Result { - let CRS { g2_data, .. } = crs; - - // Barretenberg expects public inputs to be prepended onto the proof - let proof = prepend_public_inputs(proof.to_vec(), public_inputs); - let cs_buf = constraint_system.to_bytes(); - - let cs_ptr = self.allocate(&cs_buf)?; - let proof_ptr = self.allocate(&proof)?; - let g2_ptr = self.allocate(g2_data)?; - let vk_ptr = self.allocate(verification_key)?; - - // This doesn't unwrap the result because we need to free even if there is a failure - let verified = self.call_multiple( - "acir_proofs_verify_proof", - vec![&g2_ptr, &vk_ptr, &cs_ptr, &proof_ptr, &proof.len().into()], - ); - - self.free(proof_ptr)?; - - Ok(verified?.try_into()?) - } -} - -fn pow2ceil(v: u32) -> Result { - if v > (u32::MAX >> 1) { - Err(Error::Pow2CeilOverflow(v)) - } else { - let mut p = 1; - while p < v { - p <<= 1; - } - Ok(p) - } -} - -/// Removes the public inputs which are prepended to a proof by Barretenberg. -fn remove_public_inputs(num_pub_inputs: usize, proof: &[u8]) -> Vec { - // Barretenberg prepends the public inputs onto the proof so we need to remove - // the first `num_pub_inputs` field elements. - let num_bytes_to_remove = num_pub_inputs * FIELD_BYTES; - proof[num_bytes_to_remove..].to_vec() -} - -/// Prepends a set of public inputs to a proof. -fn prepend_public_inputs(proof: Vec, public_inputs: Assignments) -> Vec { - if public_inputs.is_empty() { - return proof; - } - - let public_inputs_bytes = public_inputs - .into_iter() - .flat_map(|assignment| assignment.to_be_bytes()); - - public_inputs_bytes.chain(proof.into_iter()).collect() -} - -#[cfg(test)] -mod test { - use acvm::FieldElement; - use tokio::test; - - use super::*; - use crate::barretenberg_structures::{ - BlockConstraint, Constraint, Keccak256Constraint, LogicConstraint, MemOpBarretenberg, - PedersenConstraint, RangeConstraint, SchnorrConstraint, - }; - - #[test] - async fn test_no_constraints_no_pub_inputs() -> Result<(), Error> { - let constraint_system = ConstraintSystem::new(); - - let case_1 = WitnessResult { - witness: vec![].into(), - public_inputs: Assignments::default(), - result: true, - }; - let test_cases = vec![case_1]; - - test_composer_with_pk_vk(constraint_system, test_cases).await - } - - #[test] - async fn test_a_single_constraint_no_pub_inputs() -> Result<(), Error> { - let constraint = Constraint { - a: 1, - b: 2, - c: 3, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::one(), - qo: -FieldElement::one(), - qc: FieldElement::zero(), - }; - - let constraint_system = ConstraintSystem::new() - .var_num(4) - .constraints(vec![constraint]); - - let case_1 = WitnessResult { - witness: vec![(-1_i128).into(), 2_i128.into(), 1_i128.into()].into(), - public_inputs: Assignments::default(), - result: true, - }; - let case_2 = WitnessResult { - witness: vec![ - FieldElement::zero(), - FieldElement::zero(), - FieldElement::zero(), - ] - .into(), - public_inputs: Assignments::default(), - result: true, - }; - let case_3 = WitnessResult { - witness: vec![10_i128.into(), (-3_i128).into(), 7_i128.into()].into(), - public_inputs: Assignments::default(), - result: true, - }; - let case_4 = WitnessResult { - witness: vec![ - FieldElement::zero(), - FieldElement::zero(), - FieldElement::one(), - ] - .into(), - public_inputs: Assignments::default(), - result: false, - }; - let case_5 = WitnessResult { - witness: vec![FieldElement::one(), 2_i128.into(), 6_i128.into()].into(), - public_inputs: Assignments::default(), - result: false, - }; - let test_cases = vec![case_1, case_2, case_3, case_4, case_5]; - - test_composer_with_pk_vk(constraint_system, test_cases).await - } - - #[test] - async fn test_a_single_constraint_with_pub_inputs() -> Result<(), Error> { - let constraint = Constraint { - a: 1, - b: 2, - c: 3, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::one(), - qo: -FieldElement::one(), - qc: FieldElement::zero(), - }; - - let constraint_system = ConstraintSystem::new() - .var_num(4) - .public_inputs(vec![1, 2]) - .constraints(vec![constraint]); - - // This fails because the constraint system requires public inputs, - // but none are supplied in public_inputs. So the verifier will not - // supply anything. - let _case_1 = WitnessResult { - witness: vec![(-1_i128).into(), 2_i128.into(), 1_i128.into()].into(), - public_inputs: Assignments::default(), - result: false, - }; - let case_2 = WitnessResult { - witness: vec![ - FieldElement::zero(), - FieldElement::zero(), - FieldElement::zero(), - ] - .into(), - public_inputs: vec![FieldElement::zero(), FieldElement::zero()].into(), - result: true, - }; - - let case_3 = WitnessResult { - witness: vec![FieldElement::one(), 2_i128.into(), 6_i128.into()].into(), - public_inputs: vec![FieldElement::one(), 3_i128.into()].into(), - result: false, - }; - - // Not enough public inputs - let _case_4 = WitnessResult { - witness: vec![ - FieldElement::one(), - FieldElement::from(2_i128), - FieldElement::from(6_i128), - ] - .into(), - public_inputs: vec![FieldElement::one()].into(), - result: false, - }; - - let case_5 = WitnessResult { - witness: vec![FieldElement::one(), 2_i128.into(), 3_i128.into()].into(), - public_inputs: vec![FieldElement::one(), 2_i128.into()].into(), - result: true, - }; - - let case_6 = WitnessResult { - witness: vec![FieldElement::one(), 2_i128.into(), 3_i128.into()].into(), - public_inputs: vec![FieldElement::one(), 3_i128.into()].into(), - result: false, - }; - let test_cases = vec![ - /*case_1,*/ case_2, case_3, /*case_4,*/ case_5, case_6, - ]; - - test_composer_with_pk_vk(constraint_system, test_cases).await - } - - #[test] - async fn test_multiple_constraints() -> Result<(), Error> { - let constraint = Constraint { - a: 1, - b: 2, - c: 3, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::one(), - qo: -FieldElement::one(), - qc: FieldElement::zero(), - }; - let constraint2 = Constraint { - a: 2, - b: 3, - c: 4, - qm: FieldElement::one(), - ql: FieldElement::zero(), - qr: FieldElement::zero(), - qo: -FieldElement::one(), - qc: FieldElement::one(), - }; - - let constraint_system = ConstraintSystem::new() - .var_num(5) - .public_inputs(vec![1]) - .constraints(vec![constraint, constraint2]); - - let case_1 = WitnessResult { - witness: vec![1_i128.into(), 1_i128.into(), 2_i128.into(), 3_i128.into()].into(), - public_inputs: vec![FieldElement::one()].into(), - result: true, - }; - let case_2 = WitnessResult { - witness: vec![1_i128.into(), 1_i128.into(), 2_i128.into(), 13_i128.into()].into(), - public_inputs: vec![FieldElement::one()].into(), - result: false, - }; - - test_composer_with_pk_vk(constraint_system, vec![case_1, case_2]).await - } - - #[test] - async fn test_schnorr_constraints() -> Result<(), Error> { - let mut signature_indices = [0i32; 64]; - for i in 13..(13 + 64) { - signature_indices[i - 13] = i as i32; - } - let result_index = signature_indices.last().unwrap() + 1; - - let constraint = SchnorrConstraint { - message: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - public_key_x: 11, - public_key_y: 12, - signature: signature_indices, - result: result_index, - }; - - let arith_constraint = Constraint { - a: result_index, - b: result_index, - c: result_index, - qm: FieldElement::zero(), - ql: FieldElement::zero(), - qr: FieldElement::zero(), - qo: FieldElement::one(), - qc: -FieldElement::one(), - }; - - let constraint_system = ConstraintSystem::new() - .var_num(80) - .schnorr_constraints(vec![constraint]) - .constraints(vec![arith_constraint]); - - let pub_x = FieldElement::from_hex( - "0x17cbd3ed3151ccfd170efe1d54280a6a4822640bf5c369908ad74ea21518a9c5", - ) - .unwrap(); - let pub_y = FieldElement::from_hex( - "0x0e0456e3795c1a31f20035b741cd6158929eeccd320d299cfcac962865a6bc74", - ) - .unwrap(); - - let sig: [i128; 64] = [ - 5, 202, 31, 146, 81, 242, 246, 69, 43, 107, 249, 153, 198, 44, 14, 111, 191, 121, 137, - 166, 160, 103, 18, 181, 243, 233, 226, 95, 67, 16, 37, 128, 85, 76, 19, 253, 30, 77, - 192, 53, 138, 205, 69, 33, 236, 163, 83, 194, 84, 137, 184, 221, 176, 121, 179, 27, 63, - 70, 54, 16, 176, 250, 39, 239, - ]; - let sig_as_scalars: Vec = sig.into_iter().map(FieldElement::from).collect(); - - let message: Vec = vec![ - 0_i128.into(), - 1_i128.into(), - 2_i128.into(), - 3_i128.into(), - 4_i128.into(), - 5_i128.into(), - 6_i128.into(), - 7_i128.into(), - 8_i128.into(), - 9_i128.into(), - ]; - let mut witness_values = Vec::new(); - witness_values.extend(message); - witness_values.push(pub_x); - witness_values.push(pub_y); - witness_values.extend(sig_as_scalars); - witness_values.push(FieldElement::zero()); - - let case_1 = WitnessResult { - witness: witness_values.into(), - public_inputs: Assignments::default(), - result: true, - }; - - test_composer_with_pk_vk(constraint_system, vec![case_1]).await - } - - #[test] - async fn test_keccak256_constraint() -> Result<(), Error> { - let input_value: u128 = 0xbd; - let input_index = 1; - - // 0x5a502f9fca467b266d5b7833651937e805270ca3f3af1c0dd2462dca4b3b1abf - let result_values: [u128; 32] = [ - 0x5a, 0x50, 0x2f, 0x9f, 0xca, 0x46, 0x7b, 0x26, 0x6d, 0x5b, 0x78, 0x33, 0x65, 0x19, - 0x37, 0xe8, 0x05, 0x27, 0x0c, 0xa3, 0xf3, 0xaf, 0x1c, 0x0d, 0xd2, 0x46, 0x2d, 0xca, - 0x4b, 0x3b, 0x1a, 0xbf, - ]; - let result_indices: Vec = (2i32..2 + result_values.len() as i32).collect(); - - let keccak_constraint = Keccak256Constraint { - inputs: vec![(input_index, 8)], - result: result_indices.clone().try_into().unwrap(), - }; - - let mut constraints = Vec::new(); - for (value, index) in result_values.iter().zip(&result_indices) { - let byte_constraint = Constraint { - a: *index, - b: *index, - c: *index, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: -FieldElement::from(*value), - }; - constraints.push(byte_constraint) - } - - let constraint_system = ConstraintSystem::new() - .var_num(100) - .keccak256_constraints(vec![keccak_constraint]) - .constraints(constraints); - - let witness_values: Vec<_> = std::iter::once(input_value) - .chain(result_values) - .map(FieldElement::from) - .collect(); - let case_1 = WitnessResult { - witness: witness_values.into(), - public_inputs: Assignments::default(), - result: true, - }; - - test_composer_with_pk_vk(constraint_system, vec![case_1]).await - } - - #[test] - async fn test_ped_constraints() -> Result<(), Error> { - let constraint = PedersenConstraint { - inputs: vec![1, 2], - hash_index: 0, - result_x: 3, - result_y: 4, - }; - - let x_constraint = Constraint { - a: 3, - b: 3, - c: 3, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: -FieldElement::from_hex( - "0x0c5e1ddecd49de44ed5e5798d3f6fb7c71fe3d37f5bee8664cf88a445b5ba0af", - ) - .unwrap(), - }; - let y_constraint = Constraint { - a: 4, - b: 4, - c: 4, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: -FieldElement::from_hex( - "0x230294a041e26fe80b827c2ef5cb8784642bbaa83842da2714d62b1f3c4f9752", - ) - .unwrap(), - }; - - let constraint_system = ConstraintSystem::new() - .var_num(100) - .pedersen_constraints(vec![constraint]) - .constraints(vec![x_constraint, y_constraint]); - - let scalar_0 = FieldElement::from_hex("0x00").unwrap(); - let scalar_1 = FieldElement::from_hex("0x01").unwrap(); - let witness_values = vec![scalar_0, scalar_1]; - - let case_1 = WitnessResult { - witness: witness_values.into(), - public_inputs: Assignments::default(), - result: true, - }; - - test_composer_with_pk_vk(constraint_system, vec![case_1]).await - } - - #[test] - async fn test_memory_constraints() -> Result<(), Error> { - let a0 = Constraint { - a: 2, - b: 0, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: FieldElement::zero(), - }; - let a1 = Constraint { - a: 3, - b: 0, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: FieldElement::zero(), - }; - - let r1 = Constraint { - a: 2, - b: 0, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: FieldElement::zero(), - }; - let r2 = Constraint { - a: 1, - b: 0, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: FieldElement::zero(), - }; - - let y_constraint = Constraint { - a: 2, - b: 0, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: FieldElement::zero(), - }; - let z_constraint = Constraint { - a: 3, - b: 0, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: FieldElement::zero(), - }; - - let op1 = MemOpBarretenberg { - index: r1, - value: y_constraint, - is_store: 0, - }; - let op2 = MemOpBarretenberg { - index: r2.clone(), - value: z_constraint, - is_store: 0, - }; - let block_constraint = BlockConstraint { - init: vec![a0, a1], - trace: vec![op1, op2], - is_ram: 0, - }; - - let two_field = FieldElement::one() + FieldElement::one(); - let result_constraint = Constraint { - a: 2, - b: 3, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::one(), - qo: FieldElement::zero(), - qc: -(two_field), - }; - let constraint_system = ConstraintSystem::new() - .var_num(4) - .block_constraints(vec![block_constraint]) - .constraints(vec![result_constraint]); - - let scalar_0 = FieldElement::zero(); - let scalar_1 = FieldElement::one(); - let witness_values = vec![scalar_0, scalar_1, scalar_1]; - - let case_1 = WitnessResult { - witness: witness_values.into(), - public_inputs: Assignments::default(), - result: true, - }; - - let bad_values = vec![scalar_0, scalar_1, scalar_1 + scalar_1]; - let case_2 = WitnessResult { - witness: bad_values.into(), - public_inputs: Assignments::default(), - result: false, - }; - - test_composer_with_pk_vk(constraint_system, vec![case_1, case_2]).await - } - - #[test] - async fn test_logic_constraints() -> Result<(), Error> { - /* - * constraints produced by Noir program: - * fn main(x : u32, y : pub u32) { - * let z = x ^ y; - * - * constrain z != 10; - * } - */ - let range_a = RangeConstraint { a: 1, num_bits: 32 }; - let range_b = RangeConstraint { a: 2, num_bits: 32 }; - - let logic_constraint = LogicConstraint { - a: 1, - b: 2, - result: 3, - num_bits: 32, - is_xor_gate: true, - }; - - let expr_a = Constraint { - a: 3, - b: 4, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: -FieldElement::one(), - qo: FieldElement::zero(), - qc: -FieldElement::from_hex("0x0a").unwrap(), - }; - let expr_b = Constraint { - a: 4, - b: 5, - c: 6, - qm: FieldElement::one(), - ql: FieldElement::zero(), - qr: FieldElement::zero(), - qo: -FieldElement::one(), - qc: FieldElement::zero(), - }; - let expr_c = Constraint { - a: 4, - b: 6, - c: 4, - qm: FieldElement::one(), - ql: FieldElement::zero(), - qr: FieldElement::zero(), - qo: -FieldElement::one(), - qc: FieldElement::zero(), - }; - let expr_d = Constraint { - a: 6, - b: 0, - c: 0, - qm: FieldElement::zero(), - ql: -FieldElement::one(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: FieldElement::one(), - }; - - let constraint_system = ConstraintSystem::new() - .var_num(7) - .public_inputs(vec![2]) - .range_constraints(vec![range_a, range_b]) - .logic_constraints(vec![logic_constraint]) - .constraints(vec![expr_a, expr_b, expr_c, expr_d]); - - let scalar_5 = FieldElement::from_hex("0x05").unwrap(); - let scalar_10 = FieldElement::from_hex("0x0a").unwrap(); - let scalar_15 = FieldElement::from_hex("0x0f").unwrap(); - let scalar_5_inverse = scalar_5.inverse(); - let witness_values = vec![ - scalar_5, - scalar_10, - scalar_15, - scalar_5, - scalar_5_inverse, - FieldElement::one(), - ]; - let case_1 = WitnessResult { - witness: witness_values.into(), - public_inputs: vec![scalar_10].into(), - result: true, - }; - - test_composer_with_pk_vk(constraint_system, vec![case_1]).await - } - - #[derive(Clone, Debug)] - struct WitnessResult { - witness: Assignments, - public_inputs: Assignments, - result: bool, - } - - async fn test_composer_with_pk_vk( - constraint_system: ConstraintSystem, - test_cases: Vec, - ) -> Result<(), Error> { - let bb = Barretenberg::new(); - let crs = bb.get_crs(&constraint_system).await?; - - let proving_key = bb.compute_proving_key(&constraint_system)?; - let verification_key = bb.compute_verification_key(&crs, &proving_key)?; - - for test_case in test_cases.into_iter() { - let proof = - bb.create_proof_with_pk(&crs, &constraint_system, test_case.witness, &proving_key)?; - let verified = bb.verify_with_vk( - &crs, - &constraint_system, - &proof, - test_case.public_inputs, - &verification_key, - )?; - assert_eq!(verified, test_case.result); - } - Ok(()) - } -} diff --git a/src/barretenberg/crs.rs b/src/barretenberg/crs.rs deleted file mode 100644 index 916c57e2..00000000 --- a/src/barretenberg/crs.rs +++ /dev/null @@ -1,177 +0,0 @@ -use bytesize::ByteSize; -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use std::env; - -use super::CRSError; -use crate::Error; - -// TODO(#175): Use manifest parsing in BB instead of hardcoding these -const G1_START: usize = 28; -const G2_START: usize = 28 + (5_040_001 * 64); -const G2_END: usize = G2_START + 128 - 1; - -const TRANSCRIPT_URL_ENV_VAR: &str = "TRANSCRIPT_URL"; -const TRANSCRIPT_URL_FALLBACK: &str = - "https://aztec-ignition.s3.amazonaws.com/MAIN%20IGNITION/monomial/transcript00.dat"; - -#[allow(clippy::upper_case_acronyms)] -#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] -pub(crate) struct CRS { - pub(crate) g1_data: Vec, - pub(crate) g2_data: Vec, - pub(crate) num_points: usize, -} - -impl CRS { - pub(crate) async fn update(&mut self, num_points: usize) -> Result<(), Error> { - // We already have some data, so start at the end of our list - let g1_start = G1_START + self.g1_data.len(); - // UltraPlonk requires a CRS equal to circuit size plus one! - // We need to bump our polynomial degrees by 1 to handle zero knowledge - let g1_end = G1_START + ((num_points + 1) * 64) - 1; - - // If the `g1_end` is <= the `g1_start`, we already have enough CRS - if g1_end > g1_start { - let mut g1_data = download(g1_start, g1_end).await?; - - self.g1_data.append(&mut g1_data); - self.num_points = num_points; - } - - Ok::<(), Error>(()) - } -} - -impl TryFrom<&[u8]> for CRS { - type Error = CRSError; - - fn try_from(value: &[u8]) -> Result { - bincode::deserialize(value).map_err(|source| CRSError::Deserialize { source }) - } -} - -impl TryFrom> for CRS { - type Error = CRSError; - - fn try_from(value: Vec) -> Result { - bincode::deserialize(&value).map_err(|source| CRSError::Deserialize { source }) - } -} - -impl TryFrom for Vec { - type Error = CRSError; - - fn try_from(value: CRS) -> Result { - bincode::serialize(&value).map_err(|source| CRSError::Serialize { source }) - } -} - -impl TryFrom<&CRS> for Vec { - type Error = CRSError; - - fn try_from(value: &CRS) -> Result { - bincode::serialize(value).map_err(|source| CRSError::Serialize { source }) - } -} - -async fn download(start: usize, end: usize) -> Result, CRSError> { - // TODO(#187): Allow downloading from more than just the first transcript - // We try to load a URL from the environment and otherwise fallback to a hardcoded URL to allow - // Nix to override the URL for testing in the sandbox, where there is no network access on Linux - let transcript_url = match env::var(TRANSCRIPT_URL_ENV_VAR) { - Ok(url) => url, - Err(_) => TRANSCRIPT_URL_FALLBACK.into(), - }; - - let client = Client::new(); - - let request = client - .get(&transcript_url) - .header(reqwest::header::RANGE, format!("bytes={start}-{end}")) - .build() - .map_err(|source| CRSError::Request { - url: transcript_url.to_string(), - source, - })?; - let response = client - .execute(request) - .await - .map_err(|source| CRSError::Fetch { - url: transcript_url.to_string(), - source, - })?; - let total_size = response.content_length().ok_or(CRSError::Length { - url: transcript_url.to_string(), - })?; - - // TODO(#195): We probably want to consider an injectable logger so we can have logging in JS - println!( - "\nDownloading the Ignite SRS ({})", - ByteSize(total_size).to_string_as(false) - ); - let crs_bytes = response - .bytes() - .await - .map_err(|source| CRSError::Download { source })?; - println!("Downloaded the SRS successfully!"); - - Ok(crs_bytes.into()) -} - -pub(crate) async fn download_crs(num_points: usize) -> Result { - // UltraPlonk requires a CRS equal to circuit size plus one! - // We need to bump our polynomial degrees by 1 to handle zero knowledge - let g1_end = G1_START + ((num_points + 1) * 64) - 1; - - let g1_data = download(G1_START, g1_end).await?; - let g2_data = download(G2_START, G2_END).await?; - - Ok::(CRS { - g1_data, - g2_data, - num_points, - }) -} - -#[cfg(test)] -mod tests { - use tokio::test; - - use super::download_crs; - use crate::Error; - - #[test] - async fn does_not_panic() -> Result<(), Error> { - use crate::Barretenberg; - - let backend = Barretenberg::default(); - let num_points = 4 * 1024; - - let crs = download_crs(num_points).await?; - - let _pippenger = backend.get_pippenger(&crs.g1_data)?; - - // TODO(#193) check that p_points memory is properly free - - Ok(()) - } - - #[test] - async fn crs_update() -> Result<(), Error> { - let partial_num_points = 2; - let full_num_points = 12; - - // Create a partial CRS - let mut partial_crs = download_crs(partial_num_points).await?; - - // Update the partial CRS to the full number of points - partial_crs.update(full_num_points).await?; - - // Fetch a full CRS to compare - let full_crs = download_crs(full_num_points).await?; - - assert_eq!(partial_crs, full_crs); - Ok(()) - } -} diff --git a/src/barretenberg/mod.rs b/src/barretenberg/mod.rs deleted file mode 100644 index cb0b37ed..00000000 --- a/src/barretenberg/mod.rs +++ /dev/null @@ -1,489 +0,0 @@ -// `acvm-backend-barretenberg` can either interact with the Barretenberg backend through a static library -// or through an embedded wasm binary. It does not make sense to include both of these backends at the same time. -// We then throw a compilation error if both flags are set. -#[cfg(all(feature = "native", feature = "wasm"))] -compile_error!("feature \"native\" and feature \"wasm\" cannot be enabled at the same time"); - -#[cfg(all(feature = "native", target_arch = "wasm32"))] -compile_error!("feature \"native\" cannot be enabled for a \"wasm32\" target"); - -#[cfg(all(feature = "wasm", target_arch = "wasm32"))] -compile_error!("feature \"wasm\" cannot be enabled for a \"wasm32\" target"); - -pub(crate) mod composer; -pub(crate) mod crs; -pub(crate) mod pedersen; -mod pippenger; -pub(crate) mod scalar_mul; -pub(crate) mod schnorr; - -use acvm::acir::BlackBoxFunc; -use thiserror::Error; - -#[cfg(feature = "native")] -#[derive(Debug, Error)] -pub(super) enum FeatureError { - #[error("Could not slice field element")] - FieldElementSlice { - source: std::array::TryFromSliceError, - }, - #[error("Expected a Vec of length {0} but it was {1}")] - FieldToArray(usize, usize), -} - -#[cfg(not(feature = "native"))] -#[derive(Debug, Error)] -pub(super) enum FeatureError { - #[error("Trying to call {name} resulted in an error")] - FunctionCallFailed { - name: String, - source: wasmer::RuntimeError, - }, - #[error("Could not find function export named {name}")] - InvalidExport { - name: String, - source: wasmer::ExportError, - }, - #[error("No value available when value was expected")] - NoValue, - #[error("Value expected to be i32")] - InvalidI32, - #[error("Could not convert value {value} from i32 to u32")] - InvalidU32 { - value: i32, - source: std::num::TryFromIntError, - }, - #[error("Could not convert value {value} from i32 to usize")] - InvalidUsize { - value: i32, - source: std::num::TryFromIntError, - }, - #[error("Value expected to be 0 or 1 representing a boolean")] - InvalidBool, -} - -#[derive(Debug, Error)] -pub(super) enum CRSError { - #[error("Failed to deserialize CRS")] - Deserialize { source: Box }, - #[error("Failed to serialize CRS")] - Serialize { source: Box }, - - #[error("Failed to build request '{url}' ({source})")] - Request { url: String, source: reqwest::Error }, - #[error("Failed to GET from '{url}' ({source})")] - Fetch { url: String, source: reqwest::Error }, - #[error("Failed to get content length from '{url}'")] - Length { url: String }, - #[error("Error while downloading file")] - Download { source: reqwest::Error }, -} - -#[allow(clippy::upper_case_acronyms)] -#[derive(Debug, Error)] -pub(super) enum Error { - #[error("The value {0} overflows in the pow2ceil function")] - Pow2CeilOverflow(u32), - - #[error("Malformed Black Box Function: {0} - {1}")] - MalformedBlackBoxFunc(BlackBoxFunc, String), - - #[error(transparent)] - FromFeature(#[from] FeatureError), - - #[error(transparent)] - CRS(#[from] CRSError), -} - -/// The number of bytes necessary to store a `FieldElement`. -const FIELD_BYTES: usize = 32; - -#[derive(Debug)] -pub struct Barretenberg { - #[cfg(not(feature = "native"))] - store: std::cell::RefCell, - #[cfg(not(feature = "native"))] - memory: wasmer::Memory, - #[cfg(not(feature = "native"))] - instance: wasmer::Instance, -} - -impl Default for Barretenberg { - fn default() -> Barretenberg { - Barretenberg::new() - } -} - -#[test] -fn smoke() -> Result<(), Error> { - use pedersen::Pedersen; - - let b = Barretenberg::new(); - let (x, y) = b.encrypt( - vec![acvm::FieldElement::zero(), acvm::FieldElement::one()], - 0, - )?; - dbg!(x.to_hex(), y.to_hex()); - Ok(()) -} - -#[cfg(feature = "native")] -mod native { - use super::{Barretenberg, Error, FeatureError}; - - impl Barretenberg { - pub(crate) fn new() -> Barretenberg { - Barretenberg {} - } - } - - pub(super) fn field_to_array(f: &acvm::FieldElement) -> Result<[u8; 32], Error> { - let v = f.to_be_bytes(); - let result: [u8; 32] = v - .try_into() - .map_err(|v: Vec| FeatureError::FieldToArray(32, v.len()))?; - Ok(result) - } -} - -#[cfg(not(feature = "native"))] -mod wasm { - use std::cell::RefCell; - - use wasmer::{ - imports, Function, FunctionEnv, FunctionEnvMut, Instance, Memory, MemoryType, Module, - Store, Value, WasmPtr, - }; - - use super::{Barretenberg, Error, FeatureError}; - - /// The number of bytes necessary to represent a pointer to memory inside the wasm. - pub(super) const POINTER_BYTES: usize = 4; - - /// The Barretenberg WASM gives us 1024 bytes of scratch space which we can use without - /// needing to allocate/free it ourselves. This can be useful for when we need to pass in several small variables - /// when calling functions on the wasm, however it's important to not overrun this scratch space as otherwise - /// the written data will begin to corrupt the stack. - /// - /// Using this scratch space isn't particularly safe if we have multiple threads interacting with the wasm however, - /// each thread could write to the same pointer address simultaneously. - pub(super) const WASM_SCRATCH_BYTES: usize = 1024; - - /// Embed the Barretenberg WASM file - #[derive(rust_embed::RustEmbed)] - #[folder = "$BARRETENBERG_BIN_DIR"] - #[include = "barretenberg.wasm"] - struct Wasm; - - impl Barretenberg { - pub(crate) fn new() -> Barretenberg { - let (instance, memory, store) = instance_load(); - Barretenberg { - memory, - instance, - store: RefCell::new(store), - } - } - } - - /// A wrapper around the arguments or return value from a WASM call. - /// Notice, `Option` is used because not every call returns a value, - /// some calls are simply made to free a pointer or manipulate the heap. - #[derive(Debug, Clone)] - pub(crate) struct WASMValue(Option); - - impl From for WASMValue { - fn from(value: usize) -> Self { - WASMValue(Some(Value::I32(value as i32))) - } - } - - impl From for WASMValue { - fn from(value: u32) -> Self { - WASMValue(Some(Value::I32(value as i32))) - } - } - - impl From for WASMValue { - fn from(value: i32) -> Self { - WASMValue(Some(Value::I32(value))) - } - } - - impl From for WASMValue { - fn from(value: Value) -> Self { - WASMValue(Some(value)) - } - } - - impl TryFrom for bool { - type Error = FeatureError; - - fn try_from(value: WASMValue) -> Result { - match value.try_into()? { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(FeatureError::InvalidBool), - } - } - } - - impl TryFrom for usize { - type Error = FeatureError; - - fn try_from(value: WASMValue) -> Result { - let value: i32 = value.try_into()?; - value - .try_into() - .map_err(|source| FeatureError::InvalidUsize { value, source }) - } - } - - impl TryFrom for u32 { - type Error = FeatureError; - - fn try_from(value: WASMValue) -> Result { - let value = value.try_into()?; - u32::try_from(value).map_err(|source| FeatureError::InvalidU32 { value, source }) - } - } - - impl TryFrom for i32 { - type Error = FeatureError; - - fn try_from(value: WASMValue) -> Result { - value.0.map_or(Err(FeatureError::NoValue), |val| { - val.i32().ok_or(FeatureError::InvalidI32) - }) - } - } - - impl TryFrom for Value { - type Error = FeatureError; - - fn try_from(value: WASMValue) -> Result { - value.0.ok_or(FeatureError::NoValue) - } - } - - impl Barretenberg { - /// Transfer bytes to WASM heap - pub(super) fn transfer_to_heap(&self, data: &[u8], offset: usize) { - let memory = &self.memory; - let store = self.store.borrow(); - let memory_view = memory.view(&store); - - memory_view.write(offset as u64, data).unwrap() - } - - // TODO: Consider making this Result-returning - pub(super) fn read_memory(&self, start: usize) -> [u8; SIZE] { - self.read_memory_variable_length(start, SIZE) - .try_into() - .expect("Read memory should be of the specified length") - } - - // TODO: Consider making this Result-returning - pub(crate) fn read_memory_variable_length(&self, offset: usize, length: usize) -> Vec { - let memory = &self.memory; - let store = &self.store.borrow(); - let memory_view = memory.view(&store); - - let mut buf = vec![0; length]; - - memory_view.read(offset as u64, &mut buf).unwrap(); - buf - } - - pub(crate) fn get_pointer(&self, ptr_ptr: usize) -> usize { - let ptr: [u8; POINTER_BYTES] = self.read_memory(ptr_ptr); - u32::from_le_bytes(ptr) as usize - } - - pub(super) fn call(&self, name: &str, param: &WASMValue) -> Result { - self.call_multiple(name, vec![param]) - } - - pub(crate) fn call_multiple( - &self, - name: &str, - params: Vec<&WASMValue>, - ) -> Result { - // We take in a reference to values, since they do not implement Copy. - // We then clone them inside of this function, so that the API does not have a bunch of Clones everywhere - - let mut args: Vec = vec![]; - for param in params.into_iter().cloned() { - args.push(param.try_into()?) - } - let func = self.instance.exports.get_function(name).map_err(|source| { - FeatureError::InvalidExport { - name: name.to_string(), - source, - } - })?; - let boxed_value = func - .call(&mut self.store.borrow_mut(), &args) - .map_err(|source| FeatureError::FunctionCallFailed { - name: name.to_string(), - source, - })?; - let option_value = boxed_value.first().cloned(); - - Ok(WASMValue(option_value)) - } - - /// Creates a pointer and allocates the bytes that the pointer references to, to the heap - pub(crate) fn allocate(&self, bytes: &[u8]) -> Result { - let ptr: i32 = self.call("bbmalloc", &bytes.len().into())?.try_into()?; - - let i32_bytes = ptr.to_be_bytes(); - let u32_bytes = u32::from_be_bytes(i32_bytes); - - self.transfer_to_heap(bytes, u32_bytes as usize); - Ok(ptr.into()) - } - - /// Frees a pointer. - /// Notice we consume the Value, if you clone the value before passing it to free - /// It most likely is a bug - pub(super) fn free(&self, pointer: WASMValue) -> Result<(), Error> { - self.call("bbfree", &pointer)?; - Ok(()) - } - } - - fn instance_load() -> (Instance, Memory, Store) { - let mut store = Store::default(); - - let mem_type = MemoryType::new(23, None, false); - let memory = Memory::new(&mut store, mem_type).unwrap(); - - let function_env = FunctionEnv::new(&mut store, memory.clone()); - let custom_imports = imports! { - "env" => { - "logstr" => Function::new_typed_with_env( - &mut store, - &function_env, - logstr, - ), - "set_data" => Function::new_typed(&mut store, set_data), - "get_data" => Function::new_typed(&mut store, get_data), - "env_load_verifier_crs" => Function::new_typed(&mut store, env_load_verifier_crs), - "env_load_prover_crs" => Function::new_typed(&mut store, env_load_prover_crs), - "memory" => memory.clone(), - }, - "wasi_snapshot_preview1" => { - "fd_read" => Function::new_typed(&mut store, fd_read), - "fd_close" => Function::new_typed(&mut store, fd_close), - "proc_exit" => Function::new_typed(&mut store, proc_exit), - "fd_fdstat_get" => Function::new_typed(&mut store, fd_fdstat_get), - "random_get" => Function::new_typed_with_env( - &mut store, - &function_env, - random_get - ), - "fd_seek" => Function::new_typed(&mut store, fd_seek), - "fd_write" => Function::new_typed(&mut store, fd_write), - "environ_sizes_get" => Function::new_typed(&mut store, environ_sizes_get), - "environ_get" => Function::new_typed(&mut store, environ_get), - "clock_time_get" => Function::new_typed(&mut store, clock_time_get), - }, - }; - - let module = Module::new(&store, Wasm::get("barretenberg.wasm").unwrap().data).unwrap(); - - ( - Instance::new(&mut store, &module, &custom_imports).unwrap(), - memory, - store, - ) - } - - fn logstr(mut env: FunctionEnvMut, ptr: i32) { - let (memory, store) = env.data_and_store_mut(); - let memory_view = memory.view(&store); - - let log_str_wasm_ptr: WasmPtr = WasmPtr::new(ptr as u32); - - match log_str_wasm_ptr.read_utf8_string_with_nul(&memory_view) { - Ok(log_string) => println!("{log_string}"), - Err(err) => println!("Error while reading log string from memory: {err}"), - }; - } - - // Based on https://github.com/wasmerio/wasmer/blob/2.3.0/lib/wasi/src/syscalls/mod.rs#L2537 - fn random_get(mut env: FunctionEnvMut, buf_ptr: i32, buf_len: i32) -> i32 { - let mut u8_buffer = vec![0; buf_len as usize]; - let res = getrandom::getrandom(&mut u8_buffer); - match res { - Ok(()) => { - let (memory, store) = env.data_and_store_mut(); - let memory_view = memory.view(&store); - match memory_view.write(buf_ptr as u64, u8_buffer.as_mut_slice()) { - Ok(_) => { - 0_i32 // __WASI_ESUCCESS - } - Err(_) => { - 29_i32 // __WASI_EIO - } - } - } - Err(_) => { - 29_i32 // __WASI_EIO - } - } - } - - fn clock_time_get(_: i32, _: i64, _: i32) -> i32 { - unimplemented!("clock_time_get is not implemented") - } - - fn proc_exit(_: i32) { - unimplemented!("proc_exit is not implemented") - } - - fn fd_write(_: i32, _: i32, _: i32, _: i32) -> i32 { - unimplemented!("fd_write is not implemented") - } - - fn fd_seek(_: i32, _: i64, _: i32, _: i32) -> i32 { - unimplemented!("fd_seek is not implemented") - } - - fn fd_read(_: i32, _: i32, _: i32, _: i32) -> i32 { - unimplemented!("fd_read is not implemented") - } - - fn fd_fdstat_get(_: i32, _: i32) -> i32 { - unimplemented!("fd_fdstat_get is not implemented") - } - - fn fd_close(_: i32) -> i32 { - unimplemented!("fd_close is not implemented") - } - - fn environ_sizes_get(_: i32, _: i32) -> i32 { - unimplemented!("environ_sizes_get is not implemented") - } - - fn environ_get(_: i32, _: i32) -> i32 { - unimplemented!("environ_get is not implemented") - } - - fn set_data(_: i32, _: i32, _: i32) { - unimplemented!("set_data is not implemented") - } - - fn get_data(_: i32, _: i32) -> i32 { - unimplemented!("get_data is not implemented") - } - - fn env_load_verifier_crs() -> i32 { - unimplemented!("env_load_verifier_crs is not implemented") - } - - fn env_load_prover_crs(_: i32) -> i32 { - unimplemented!("env_load_prover_crs is not implemented") - } -} diff --git a/src/barretenberg/pedersen.rs b/src/barretenberg/pedersen.rs deleted file mode 100644 index a925ca38..00000000 --- a/src/barretenberg/pedersen.rs +++ /dev/null @@ -1,203 +0,0 @@ -use acvm::FieldElement; - -use super::{Barretenberg, Error}; - -pub(crate) trait Pedersen { - fn compress_native( - &self, - left: &FieldElement, - right: &FieldElement, - ) -> Result; - fn compress_many(&self, inputs: Vec) -> Result; - fn encrypt( - &self, - inputs: Vec, - hash_index: u32, - ) -> Result<(FieldElement, FieldElement), Error>; -} - -#[cfg(feature = "native")] -impl Pedersen for Barretenberg { - fn compress_native( - &self, - left: &FieldElement, - right: &FieldElement, - ) -> Result { - use super::FeatureError; - - let result_bytes = barretenberg_sys::pedersen::compress_native( - left.to_be_bytes() - .as_slice() - .try_into() - .map_err(|source| FeatureError::FieldElementSlice { source })?, - right - .to_be_bytes() - .as_slice() - .try_into() - .map_err(|source| FeatureError::FieldElementSlice { source })?, - ); - - Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) - } - - #[allow(dead_code)] - fn compress_many(&self, inputs: Vec) -> Result { - use super::native::field_to_array; - - let mut inputs_buf = Vec::new(); - for f in inputs { - inputs_buf.push(field_to_array(&f)?); - } - let result_bytes = barretenberg_sys::pedersen::compress_many(&inputs_buf); - - Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) - } - - fn encrypt( - &self, - inputs: Vec, - hash_index: u32, - ) -> Result<(FieldElement, FieldElement), Error> { - use super::native::field_to_array; - - let mut inputs_buf = Vec::new(); - for f in inputs { - inputs_buf.push(field_to_array(&f)?); - } - let (point_x_bytes, point_y_bytes) = - barretenberg_sys::pedersen::encrypt(&inputs_buf, hash_index); - - let point_x = FieldElement::from_be_bytes_reduce(&point_x_bytes); - let point_y = FieldElement::from_be_bytes_reduce(&point_y_bytes); - - Ok((point_x, point_y)) - } -} - -#[cfg(not(feature = "native"))] -impl Pedersen for Barretenberg { - fn compress_native( - &self, - left: &FieldElement, - right: &FieldElement, - ) -> Result { - use super::FIELD_BYTES; - - let lhs_ptr: usize = 0; - let rhs_ptr: usize = lhs_ptr + FIELD_BYTES; - let result_ptr: usize = rhs_ptr + FIELD_BYTES; - - self.transfer_to_heap(&left.to_be_bytes(), lhs_ptr); - self.transfer_to_heap(&right.to_be_bytes(), rhs_ptr); - - self.call_multiple( - "pedersen_plookup_compress_fields", - vec![&lhs_ptr.into(), &rhs_ptr.into(), &result_ptr.into()], - )?; - - let result_bytes: [u8; FIELD_BYTES] = self.read_memory(result_ptr); - Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) - } - - #[allow(dead_code)] - fn compress_many(&self, inputs: Vec) -> Result { - use super::FIELD_BYTES; - use crate::barretenberg_structures::Assignments; - - let input_buf = Assignments::from(inputs).to_bytes(); - let input_ptr = self.allocate(&input_buf)?; - let result_ptr: usize = 0; - - self.call_multiple( - "pedersen_plookup_compress", - vec![&input_ptr, &result_ptr.into()], - )?; - - let result_bytes: [u8; FIELD_BYTES] = self.read_memory(result_ptr); - Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) - } - - fn encrypt( - &self, - inputs: Vec, - hash_index: u32, - ) -> Result<(FieldElement, FieldElement), Error> { - use super::FIELD_BYTES; - use crate::barretenberg_structures::Assignments; - - let input_buf = Assignments::from(inputs).to_bytes(); - let input_ptr = self.allocate(&input_buf)?; - let result_ptr: usize = 0; - - self.call_multiple( - "pedersen_plookup_commit_with_hash_index", - vec![&input_ptr, &result_ptr.into(), &hash_index.into()], - )?; - - let result_bytes: [u8; 2 * FIELD_BYTES] = self.read_memory(result_ptr); - let (point_x_bytes, point_y_bytes) = result_bytes.split_at(FIELD_BYTES); - - let point_x = FieldElement::from_be_bytes_reduce(point_x_bytes); - let point_y = FieldElement::from_be_bytes_reduce(point_y_bytes); - - Ok((point_x, point_y)) - } -} - -#[test] -fn basic_interop() -> Result<(), Error> { - // Expected values were taken from Barretenberg by running `crypto::pedersen::compress_native` - // printing the result in hex to `std::cout` and copying - struct Test<'a> { - input_left: FieldElement, - input_right: FieldElement, - expected_hex: &'a str, - } - - let tests = vec![ - Test { - input_left: FieldElement::zero(), - input_right: FieldElement::one(), - expected_hex: "0x0c5e1ddecd49de44ed5e5798d3f6fb7c71fe3d37f5bee8664cf88a445b5ba0af", - }, - Test { - input_left: FieldElement::one(), - input_right: FieldElement::one(), - expected_hex: "0x0e1793a0c122887bcb53c84776f4704c26bc093b25eaa9c7847a672c65e314ae", - }, - Test { - input_left: FieldElement::one(), - input_right: FieldElement::zero(), - expected_hex: "0x0c93b3f27730b2e331e634af15bc9d5a769688921f30b36ca926b35a96b3306c", - }, - ]; - - let barretenberg = Barretenberg::new(); - for test in tests { - let expected = FieldElement::from_hex(test.expected_hex).unwrap(); - - let got = barretenberg.compress_native(&test.input_left, &test.input_right)?; - let got_many = barretenberg.compress_many(vec![test.input_left, test.input_right])?; - assert_eq!(got, expected); - assert_eq!(got, got_many); - } - Ok(()) -} - -#[test] -fn pedersen_hash_to_point() -> Result<(), Error> { - let barretenberg = Barretenberg::new(); - let (x, y) = barretenberg.encrypt(vec![FieldElement::zero(), FieldElement::one()], 0)?; - let expected_x = FieldElement::from_hex( - "0x0c5e1ddecd49de44ed5e5798d3f6fb7c71fe3d37f5bee8664cf88a445b5ba0af", - ) - .unwrap(); - let expected_y = FieldElement::from_hex( - "0x230294a041e26fe80b827c2ef5cb8784642bbaa83842da2714d62b1f3c4f9752", - ) - .unwrap(); - - assert_eq!(expected_x.to_hex(), x.to_hex()); - assert_eq!(expected_y.to_hex(), y.to_hex()); - Ok(()) -} diff --git a/src/barretenberg/pippenger.rs b/src/barretenberg/pippenger.rs deleted file mode 100644 index af50c1fa..00000000 --- a/src/barretenberg/pippenger.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::{Barretenberg, Error}; - -pub(crate) struct Pippenger { - #[cfg(feature = "native")] - pippenger_ptr: *mut std::os::raw::c_void, - #[cfg(not(feature = "native"))] - pippenger_ptr: super::wasm::WASMValue, -} - -#[cfg(feature = "native")] -impl Pippenger { - pub(crate) fn pointer(&self) -> *mut std::os::raw::c_void { - self.pippenger_ptr - } -} - -#[cfg(not(feature = "native"))] -impl Pippenger { - pub(crate) fn pointer(&self) -> super::wasm::WASMValue { - self.pippenger_ptr.clone() - } -} - -#[cfg(feature = "native")] -impl Barretenberg { - pub(crate) fn get_pippenger(&self, crs_data: &[u8]) -> Result { - let pippenger_ptr = barretenberg_sys::pippenger::new(crs_data); - - Ok(Pippenger { pippenger_ptr }) - } -} - -#[cfg(not(feature = "native"))] -impl Barretenberg { - pub(crate) fn get_pippenger(&self, crs_data: &[u8]) -> Result { - use super::FIELD_BYTES; - - let num_points = crs_data.len() / (2 * FIELD_BYTES); - - let crs_ptr = self.allocate(crs_data)?; - - // This doesn't unwrap the result because we need to free even if there is a failure - let pippenger_ptr = self.call_multiple("new_pippenger", vec![&crs_ptr, &num_points.into()]); - - self.free(crs_ptr)?; - - Ok(Pippenger { - pippenger_ptr: pippenger_ptr?, - }) - } -} diff --git a/src/barretenberg/scalar_mul.rs b/src/barretenberg/scalar_mul.rs deleted file mode 100644 index af5e10ea..00000000 --- a/src/barretenberg/scalar_mul.rs +++ /dev/null @@ -1,66 +0,0 @@ -use acvm::FieldElement; - -use super::{Barretenberg, Error, FIELD_BYTES}; - -pub(crate) trait ScalarMul { - fn fixed_base(&self, input: &FieldElement) -> Result<(FieldElement, FieldElement), Error>; -} - -#[cfg(feature = "native")] -impl ScalarMul for Barretenberg { - fn fixed_base(&self, input: &FieldElement) -> Result<(FieldElement, FieldElement), Error> { - use super::native::field_to_array; - - let result_bytes = barretenberg_sys::schnorr::construct_public_key(&field_to_array(input)?); - - let (pubkey_x_bytes, pubkey_y_bytes) = result_bytes.split_at(FIELD_BYTES); - assert!(pubkey_x_bytes.len() == FIELD_BYTES); - assert!(pubkey_y_bytes.len() == FIELD_BYTES); - - let pubkey_x = FieldElement::from_be_bytes_reduce(pubkey_x_bytes); - let pubkey_y = FieldElement::from_be_bytes_reduce(pubkey_y_bytes); - Ok((pubkey_x, pubkey_y)) - } -} - -#[cfg(not(feature = "native"))] -impl ScalarMul for Barretenberg { - fn fixed_base(&self, input: &FieldElement) -> Result<(FieldElement, FieldElement), Error> { - let lhs_ptr: usize = 0; - let result_ptr: usize = lhs_ptr + FIELD_BYTES; - self.transfer_to_heap(&input.to_be_bytes(), lhs_ptr); - - self.call_multiple( - "compute_public_key", - vec![&lhs_ptr.into(), &result_ptr.into()], - )?; - - let result_bytes: [u8; 2 * FIELD_BYTES] = self.read_memory(result_ptr); - let (pubkey_x_bytes, pubkey_y_bytes) = result_bytes.split_at(FIELD_BYTES); - - assert!(pubkey_x_bytes.len() == FIELD_BYTES); - assert!(pubkey_y_bytes.len() == FIELD_BYTES); - - let pubkey_x = FieldElement::from_be_bytes_reduce(pubkey_x_bytes); - let pubkey_y = FieldElement::from_be_bytes_reduce(pubkey_y_bytes); - Ok((pubkey_x, pubkey_y)) - } -} - -#[cfg(test)] -mod test { - use super::*; - #[test] - fn smoke_test() -> Result<(), Error> { - let barretenberg = Barretenberg::new(); - let input = FieldElement::one(); - - let res = barretenberg.fixed_base(&input)?; - let x = "0000000000000000000000000000000000000000000000000000000000000001"; - let y = "0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c"; - - assert_eq!(x, res.0.to_hex()); - assert_eq!(y, res.1.to_hex()); - Ok(()) - } -} diff --git a/src/barretenberg/schnorr.rs b/src/barretenberg/schnorr.rs deleted file mode 100644 index cc5c7f69..00000000 --- a/src/barretenberg/schnorr.rs +++ /dev/null @@ -1,199 +0,0 @@ -use super::{Barretenberg, Error}; - -pub(crate) trait SchnorrSig { - fn construct_signature( - &self, - message: &[u8], - private_key: [u8; 32], - ) -> Result<([u8; 32], [u8; 32]), Error>; - fn construct_public_key(&self, private_key: [u8; 32]) -> Result<[u8; 64], Error>; - fn verify_signature( - &self, - pub_key: [u8; 64], - sig_s: [u8; 32], - sig_e: [u8; 32], - message: &[u8], - ) -> Result; -} - -#[cfg(feature = "native")] -impl SchnorrSig for Barretenberg { - fn construct_signature( - &self, - message: &[u8], - private_key: [u8; 32], - ) -> Result<([u8; 32], [u8; 32]), Error> { - Ok(barretenberg_sys::schnorr::construct_signature( - message, - private_key, - )) - } - - fn construct_public_key(&self, private_key: [u8; 32]) -> Result<[u8; 64], Error> { - Ok(barretenberg_sys::schnorr::construct_public_key( - &private_key, - )) - } - - fn verify_signature( - &self, - pub_key: [u8; 64], - sig_s: [u8; 32], - sig_e: [u8; 32], - message: &[u8], - ) -> Result { - Ok(barretenberg_sys::schnorr::verify_signature( - pub_key, sig_s, sig_e, message, - )) - - // Note, currently for Barretenberg plonk, if the signature fails - // then the whole circuit fails. - } -} - -#[cfg(not(feature = "native"))] -impl SchnorrSig for Barretenberg { - fn construct_signature( - &self, - message: &[u8], - private_key: [u8; 32], - ) -> Result<([u8; 32], [u8; 32]), Error> { - use super::{wasm::WASM_SCRATCH_BYTES, FIELD_BYTES}; - - let sig_s_ptr: usize = 0; - let sig_e_ptr: usize = sig_s_ptr + FIELD_BYTES; - let private_key_ptr: usize = sig_e_ptr + FIELD_BYTES; - let message_ptr: usize = private_key_ptr + private_key.len(); - assert!( - message_ptr + message.len() < WASM_SCRATCH_BYTES, - "Message overran wasm scratch space" - ); - - self.transfer_to_heap(&private_key, private_key_ptr); - self.transfer_to_heap(message, message_ptr); - self.call_multiple( - "construct_signature", - vec![ - &message_ptr.into(), - &message.len().into(), - &private_key_ptr.into(), - &sig_s_ptr.into(), - &sig_e_ptr.into(), - ], - )?; - - let sig_s: [u8; FIELD_BYTES] = self.read_memory(sig_s_ptr); - let sig_e: [u8; FIELD_BYTES] = self.read_memory(sig_e_ptr); - - Ok((sig_s, sig_e)) - } - - #[allow(dead_code)] - fn construct_public_key(&self, private_key: [u8; 32]) -> Result<[u8; 64], Error> { - use super::FIELD_BYTES; - - let private_key_ptr: usize = 0; - let result_ptr: usize = private_key_ptr + FIELD_BYTES; - - self.transfer_to_heap(&private_key, private_key_ptr); - - self.call_multiple( - "compute_public_key", - vec![&private_key_ptr.into(), &result_ptr.into()], - )?; - - Ok(self.read_memory(result_ptr)) - } - - fn verify_signature( - &self, - pub_key: [u8; 64], - sig_s: [u8; 32], - sig_e: [u8; 32], - message: &[u8], - ) -> Result { - use super::wasm::WASM_SCRATCH_BYTES; - - let public_key_ptr: usize = 0; - let sig_s_ptr: usize = public_key_ptr + pub_key.len(); - let sig_e_ptr: usize = sig_s_ptr + sig_s.len(); - let message_ptr: usize = sig_e_ptr + sig_e.len(); - assert!( - message_ptr + message.len() < WASM_SCRATCH_BYTES, - "Message overran wasm scratch space" - ); - - self.transfer_to_heap(&pub_key, public_key_ptr); - self.transfer_to_heap(&sig_s, sig_s_ptr); - self.transfer_to_heap(&sig_e, sig_e_ptr); - self.transfer_to_heap(message, message_ptr); - - let verified = self.call_multiple( - "verify_signature", - vec![ - &message_ptr.into(), - &message.len().into(), - &public_key_ptr.into(), - &sig_s_ptr.into(), - &sig_e_ptr.into(), - ], - )?; - - // Note, currently for Barretenberg plonk, if the signature fails - // then the whole circuit fails. - Ok(verified.try_into()?) - } -} - -#[test] -fn basic_interop() -> Result<(), Error> { - let barretenberg = Barretenberg::new(); - - // First case should pass, standard procedure for Schnorr - let private_key = [2; 32]; - let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - - let public_key = barretenberg.construct_public_key(private_key)?; - let (sig_s, sig_e) = barretenberg.construct_signature(&message, private_key)?; - let valid_signature = barretenberg.verify_signature(public_key, sig_s, sig_e, &message)?; - assert!(valid_signature); - - // Should fail, since the messages are different - let private_key = [2; 32]; - let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - - let public_key = barretenberg.construct_public_key(private_key)?; - let (sig_s, sig_e) = barretenberg.construct_signature(&message, private_key)?; - let valid_signature = barretenberg.verify_signature(public_key, sig_s, sig_e, &[0, 2])?; - assert!(!valid_signature); - - // Should fail, since the signature is not valid - let private_key = [2; 32]; - let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let sig_s = [1; 32]; - let sig_e = [1; 32]; - - let public_key = barretenberg.construct_public_key(private_key)?; - let valid_signature = barretenberg.verify_signature(public_key, sig_s, sig_e, &message)?; - assert!(!valid_signature); - - // Should fail, since the public key does not match - let private_key_a = [1; 32]; - let private_key_b = [2; 32]; - let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - - let public_key_b = barretenberg.construct_public_key(private_key_b)?; - let (sig_s, sig_e) = barretenberg.construct_signature(&message, private_key_a)?; - let valid_signature = barretenberg.verify_signature(public_key_b, sig_s, sig_e, &message)?; - assert!(!valid_signature); - - // Test the first case again, to check if memory is being freed and overwritten properly - let private_key = [2; 32]; - let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - - let public_key = barretenberg.construct_public_key(private_key)?; - let (sig_s, sig_e) = barretenberg.construct_signature(&message, private_key)?; - let valid_signature = barretenberg.verify_signature(public_key, sig_s, sig_e, &message)?; - assert!(valid_signature); - Ok(()) -} diff --git a/src/barretenberg_structures.rs b/src/barretenberg_structures.rs deleted file mode 100644 index 629470f9..00000000 --- a/src/barretenberg_structures.rs +++ /dev/null @@ -1,1455 +0,0 @@ -use std::collections::BTreeMap; - -use acvm::acir::circuit::opcodes::{BlackBoxFuncCall, FunctionInput}; -use acvm::acir::circuit::{Circuit, Opcode}; -use acvm::acir::native_types::Expression; -use acvm::acir::BlackBoxFunc; -use acvm::FieldElement; -use serde::{Deserialize, Serialize}; -use serde_big_array::BigArray; - -use crate::{BackendError, Error}; - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub(crate) struct Assignments(Vec); - -// This is a separate impl so the constructor can get the wasm_bindgen macro in the future -impl Assignments { - #[allow(dead_code)] - pub(crate) fn new() -> Assignments { - Assignments::default() - } -} - -impl Assignments { - pub(crate) fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let witness_len = self.0.len() as u32; - buffer.extend_from_slice(&witness_len.to_be_bytes()); - - for assignment in self.0.iter() { - buffer.extend_from_slice(&assignment.to_be_bytes()); - } - - buffer - } - - pub(crate) fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl IntoIterator for Assignments { - type Item = FieldElement; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl From> for Assignments { - fn from(w: Vec) -> Assignments { - Assignments(w) - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct Constraint { - pub(crate) a: i32, - pub(crate) b: i32, - pub(crate) c: i32, - pub(crate) qm: FieldElement, - pub(crate) ql: FieldElement, - pub(crate) qr: FieldElement, - pub(crate) qo: FieldElement, - pub(crate) qc: FieldElement, -} - -impl Default for Constraint { - fn default() -> Self { - Constraint { - a: 0, - b: 0, - c: 0, - qm: FieldElement::zero(), - ql: FieldElement::zero(), - qr: FieldElement::zero(), - qo: FieldElement::zero(), - qc: FieldElement::zero(), - } - } -} - -impl Constraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - // serialize Wires - buffer.extend_from_slice(&self.a.to_be_bytes()); - buffer.extend_from_slice(&self.b.to_be_bytes()); - buffer.extend_from_slice(&self.c.to_be_bytes()); - - // serialize selectors - buffer.extend_from_slice(&self.qm.to_be_bytes()); - buffer.extend_from_slice(&self.ql.to_be_bytes()); - buffer.extend_from_slice(&self.qr.to_be_bytes()); - buffer.extend_from_slice(&self.qo.to_be_bytes()); - buffer.extend_from_slice(&self.qc.to_be_bytes()); - - buffer - } - - fn set_linear_term(&mut self, x: FieldElement, witness: i32) { - if self.a == 0 || self.a == witness { - self.a = witness; - self.ql = x; - } else if self.b == 0 || self.b == witness { - self.b = witness; - self.qr = x; - } else if self.c == 0 || self.c == witness { - self.c = witness; - self.qo = x; - } else { - unreachable!("Cannot assign linear term to a constrain of width 3"); - } - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct RangeConstraint { - pub(crate) a: i32, - pub(crate) num_bits: i32, -} - -impl RangeConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - // Serializing Wires - buffer.extend_from_slice(&self.a.to_be_bytes()); - buffer.extend_from_slice(&self.num_bits.to_be_bytes()); - - buffer - } -} -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct EcdsaConstraint { - pub(crate) hashed_message: Vec, - // Required until Serde adopts const generics: https://github.com/serde-rs/serde/issues/1937 - #[serde(with = "BigArray")] - pub(crate) signature: [i32; 64], - pub(crate) public_key_x: [i32; 32], - pub(crate) public_key_y: [i32; 32], - pub(crate) result: i32, -} - -impl EcdsaConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let message_len = (self.hashed_message.len()) as u32; - buffer.extend_from_slice(&message_len.to_be_bytes()); - for constraint in self.hashed_message.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - let sig_len = (self.signature.len()) as u32; - buffer.extend_from_slice(&sig_len.to_be_bytes()); - for sig_byte in self.signature.iter() { - buffer.extend_from_slice(&sig_byte.to_be_bytes()); - } - - let pub_key_x_len = (self.public_key_x.len()) as u32; - buffer.extend_from_slice(&pub_key_x_len.to_be_bytes()); - for x_byte in self.public_key_x.iter() { - buffer.extend_from_slice(&x_byte.to_be_bytes()); - } - - let pub_key_y_len = (self.public_key_y.len()) as u32; - buffer.extend_from_slice(&pub_key_y_len.to_be_bytes()); - for y_byte in self.public_key_y.iter() { - buffer.extend_from_slice(&y_byte.to_be_bytes()); - } - - buffer.extend_from_slice(&self.result.to_be_bytes()); - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct SchnorrConstraint { - pub(crate) message: Vec, - // Required until Serde adopts const generics: https://github.com/serde-rs/serde/issues/1937 - #[serde(with = "BigArray")] - pub(crate) signature: [i32; 64], - pub(crate) public_key_x: i32, - pub(crate) public_key_y: i32, - pub(crate) result: i32, -} - -impl SchnorrConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let message_len = (self.message.len()) as u32; - buffer.extend_from_slice(&message_len.to_be_bytes()); - for constraint in self.message.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - let sig_len = (self.signature.len()) as u32; - buffer.extend_from_slice(&sig_len.to_be_bytes()); - for sig_byte in self.signature.iter() { - buffer.extend_from_slice(&sig_byte.to_be_bytes()); - } - - buffer.extend_from_slice(&self.public_key_x.to_be_bytes()); - buffer.extend_from_slice(&self.public_key_y.to_be_bytes()); - buffer.extend_from_slice(&self.result.to_be_bytes()); - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct Sha256Constraint { - pub(crate) inputs: Vec<(i32, i32)>, - pub(crate) result: [i32; 32], -} - -impl Sha256Constraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let inputs_len = self.inputs.len() as u32; - buffer.extend_from_slice(&inputs_len.to_be_bytes()); - for constraint in self.inputs.iter() { - buffer.extend_from_slice(&constraint.0.to_be_bytes()); - buffer.extend_from_slice(&constraint.1.to_be_bytes()); - } - - let result_len = self.result.len() as u32; - buffer.extend_from_slice(&result_len.to_be_bytes()); - for constraint in self.result.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - buffer - } -} -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct Blake2sConstraint { - pub(crate) inputs: Vec<(i32, i32)>, - pub(crate) result: [i32; 32], -} - -impl Blake2sConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let inputs_len = self.inputs.len() as u32; - buffer.extend_from_slice(&inputs_len.to_be_bytes()); - for constraint in self.inputs.iter() { - buffer.extend_from_slice(&constraint.0.to_be_bytes()); - buffer.extend_from_slice(&constraint.1.to_be_bytes()); - } - - let result_len = self.result.len() as u32; - buffer.extend_from_slice(&result_len.to_be_bytes()); - for constraint in self.result.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - buffer - } -} -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct HashToFieldConstraint { - pub(crate) inputs: Vec<(i32, i32)>, - pub(crate) result: i32, -} - -impl HashToFieldConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let inputs_len = self.inputs.len() as u32; - buffer.extend_from_slice(&inputs_len.to_be_bytes()); - for constraint in self.inputs.iter() { - buffer.extend_from_slice(&constraint.0.to_be_bytes()); - buffer.extend_from_slice(&constraint.1.to_be_bytes()); - } - - buffer.extend_from_slice(&self.result.to_be_bytes()); - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct Keccak256Constraint { - pub(crate) inputs: Vec<(i32, i32)>, - pub(crate) result: [i32; 32], -} - -impl Keccak256Constraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let inputs_len = self.inputs.len() as u32; - buffer.extend_from_slice(&inputs_len.to_be_bytes()); - for constraint in self.inputs.iter() { - buffer.extend_from_slice(&constraint.0.to_be_bytes()); - buffer.extend_from_slice(&constraint.1.to_be_bytes()); - } - - let result_len = self.result.len() as u32; - buffer.extend_from_slice(&result_len.to_be_bytes()); - for constraint in self.result.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct Keccak256VarConstraint { - pub(crate) inputs: Vec<(i32, i32)>, - pub(crate) result: [i32; 32], - pub(crate) var_message_size: i32, -} - -impl Keccak256VarConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let inputs_len = self.inputs.len() as u32; - buffer.extend_from_slice(&inputs_len.to_be_bytes()); - for constraint in self.inputs.iter() { - buffer.extend_from_slice(&constraint.0.to_be_bytes()); - buffer.extend_from_slice(&constraint.1.to_be_bytes()); - } - - let result_len = self.result.len() as u32; - buffer.extend_from_slice(&result_len.to_be_bytes()); - for constraint in self.result.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - buffer.extend_from_slice(&self.var_message_size.to_be_bytes()); - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct PedersenConstraint { - pub(crate) inputs: Vec, - pub(crate) hash_index: u32, - pub(crate) result_x: i32, - pub(crate) result_y: i32, -} - -impl PedersenConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let inputs_len = self.inputs.len() as u32; - buffer.extend_from_slice(&inputs_len.to_be_bytes()); - for constraint in self.inputs.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - buffer.extend_from_slice(&self.hash_index.to_be_bytes()); - - buffer.extend_from_slice(&self.result_x.to_be_bytes()); - buffer.extend_from_slice(&self.result_y.to_be_bytes()); - - buffer - } -} -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct FixedBaseScalarMulConstraint { - pub(crate) scalar: i32, - pub(crate) pubkey_x: i32, - pub(crate) pubkey_y: i32, -} - -impl FixedBaseScalarMulConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - // Serializing Wires - buffer.extend_from_slice(&self.scalar.to_be_bytes()); - buffer.extend_from_slice(&self.pubkey_x.to_be_bytes()); - buffer.extend_from_slice(&self.pubkey_y.to_be_bytes()); - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct LogicConstraint { - pub(crate) a: i32, - pub(crate) b: i32, - pub(crate) result: i32, - pub(crate) num_bits: i32, - pub(crate) is_xor_gate: bool, -} - -impl LogicConstraint { - pub(crate) fn and(a: i32, b: i32, result: i32, num_bits: i32) -> LogicConstraint { - LogicConstraint { - a, - b, - result, - num_bits, - is_xor_gate: false, - } - } - pub(crate) fn xor(a: i32, b: i32, result: i32, num_bits: i32) -> LogicConstraint { - LogicConstraint { - a, - b, - result, - num_bits, - is_xor_gate: true, - } - } - - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - // Serializing Wires - buffer.extend_from_slice(&self.a.to_be_bytes()); - buffer.extend_from_slice(&self.b.to_be_bytes()); - buffer.extend_from_slice(&self.result.to_be_bytes()); - buffer.extend_from_slice(&self.num_bits.to_be_bytes()); - buffer.extend_from_slice(&i32::to_be_bytes(self.is_xor_gate as i32)); - - buffer - } -} - -#[derive(Clone, Hash, Debug, Default, Serialize, Deserialize)] -pub(super) struct ConstraintSystem { - var_num: u32, - public_inputs: Vec, - - logic_constraints: Vec, - range_constraints: Vec, - sha256_constraints: Vec, - schnorr_constraints: Vec, - ecdsa_secp256k1_constraints: Vec, - ecdsa_secp256r1_constraints: Vec, - blake2s_constraints: Vec, - block_constraints: Vec, - keccak_constraints: Vec, - keccak_var_constraints: Vec, - pedersen_constraints: Vec, - hash_to_field_constraints: Vec, - fixed_base_scalar_mul_constraints: Vec, - recursion_constraints: Vec, - constraints: Vec, -} - -// This is a separate impl so the constructor can get the wasm_bindgen macro in the future -impl ConstraintSystem { - #[allow(dead_code)] - pub(crate) fn new() -> Self { - ConstraintSystem::default() - } -} - -// Builder-style impl, but we use all data types that can be defaulted so we don't need a separate builder struct -#[allow(dead_code)] -#[cfg(test)] -impl ConstraintSystem { - pub(crate) fn var_num(mut self, var_num: u32) -> Self { - self.var_num = var_num; - self - } - - pub(crate) fn public_inputs(mut self, public_inputs: Vec) -> Self { - self.public_inputs = public_inputs; - self - } - - pub(crate) fn logic_constraints(mut self, logic_constraints: Vec) -> Self { - self.logic_constraints = logic_constraints; - self - } - - pub(crate) fn range_constraints(mut self, range_constraints: Vec) -> Self { - self.range_constraints = range_constraints; - self - } - - pub(crate) fn sha256_constraints(mut self, sha256_constraints: Vec) -> Self { - self.sha256_constraints = sha256_constraints; - self - } - - pub(crate) fn schnorr_constraints( - mut self, - schnorr_constraints: Vec, - ) -> Self { - self.schnorr_constraints = schnorr_constraints; - self - } - - pub(crate) fn ecdsa_secp256k1_constraints( - mut self, - ecdsa_secp256k1_constraints: Vec, - ) -> Self { - self.ecdsa_secp256k1_constraints = ecdsa_secp256k1_constraints; - self - } - - pub(crate) fn ecdsa_secp256r1_constraints( - mut self, - ecdsa_secp256r1_constraints: Vec, - ) -> Self { - self.ecdsa_secp256r1_constraints = ecdsa_secp256r1_constraints; - self - } - - pub(crate) fn blake2s_constraints( - mut self, - blake2s_constraints: Vec, - ) -> Self { - self.blake2s_constraints = blake2s_constraints; - self - } - - pub(crate) fn keccak256_constraints( - mut self, - keccak256_constraints: Vec, - ) -> Self { - self.keccak_constraints = keccak256_constraints; - self - } - - pub(crate) fn pedersen_constraints( - mut self, - pedersen_constraints: Vec, - ) -> Self { - self.pedersen_constraints = pedersen_constraints; - self - } - - pub(crate) fn hash_to_field_constraints( - mut self, - hash_to_field_constraints: Vec, - ) -> Self { - self.hash_to_field_constraints = hash_to_field_constraints; - self - } - - pub(crate) fn fixed_base_scalar_mul_constraints( - mut self, - fixed_base_scalar_mul_constraints: Vec, - ) -> Self { - self.fixed_base_scalar_mul_constraints = fixed_base_scalar_mul_constraints; - self - } - - pub(crate) fn recursion_constraints( - mut self, - recursion_constraints: Vec, - ) -> Self { - self.recursion_constraints = recursion_constraints; - self - } - - pub(crate) fn constraints(mut self, constraints: Vec) -> Self { - self.constraints = constraints; - self - } - - pub(crate) fn block_constraints(mut self, block_constraints: Vec) -> Self { - self.block_constraints = block_constraints; - self - } -} - -impl ConstraintSystem { - pub(crate) fn public_inputs_size(&self) -> usize { - self.public_inputs.len() - } - - pub(crate) fn to_bytes(&self) -> Vec { - let mut buffer: Vec = Vec::new(); - - // Push lengths onto the buffer - buffer.extend_from_slice(&self.var_num.to_be_bytes()); - - let pi_len = self.public_inputs.len() as u32; - buffer.extend_from_slice(&pi_len.to_be_bytes()); - for pub_input in self.public_inputs.iter() { - buffer.extend_from_slice(&pub_input.to_be_bytes()); - } - - // Serialize each Logic constraint - let logic_constraints_len = self.logic_constraints.len() as u32; - buffer.extend_from_slice(&logic_constraints_len.to_be_bytes()); - for constraint in self.logic_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Range constraint - let range_constraints_len = self.range_constraints.len() as u32; - buffer.extend_from_slice(&range_constraints_len.to_be_bytes()); - for constraint in self.range_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Sha256 constraint - let sha256_constraints_len = self.sha256_constraints.len() as u32; - buffer.extend_from_slice(&sha256_constraints_len.to_be_bytes()); - for constraint in self.sha256_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Schnorr constraint - let schnorr_len = self.schnorr_constraints.len() as u32; - buffer.extend_from_slice(&schnorr_len.to_be_bytes()); - for constraint in self.schnorr_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each ECDSA constraint - let ecdsa_k1_len = self.ecdsa_secp256k1_constraints.len() as u32; - buffer.extend_from_slice(&ecdsa_k1_len.to_be_bytes()); - for constraint in self.ecdsa_secp256k1_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - let ecdsa_r1_len = self.ecdsa_secp256r1_constraints.len() as u32; - buffer.extend_from_slice(&ecdsa_r1_len.to_be_bytes()); - for constraint in self.ecdsa_secp256r1_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Blake2s constraint - let blake2s_len = self.blake2s_constraints.len() as u32; - buffer.extend_from_slice(&blake2s_len.to_be_bytes()); - for constraint in self.blake2s_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Keccak constraint - let keccak_len = self.keccak_constraints.len() as u32; - buffer.extend_from_slice(&keccak_len.to_be_bytes()); - for constraint in self.keccak_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Keccak Var constraint - let keccak_var_len = self.keccak_var_constraints.len() as u32; - buffer.extend_from_slice(&keccak_var_len.to_be_bytes()); - for constraint in self.keccak_var_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Pedersen constraint - let pedersen_len = self.pedersen_constraints.len() as u32; - buffer.extend_from_slice(&pedersen_len.to_be_bytes()); - for constraint in self.pedersen_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each HashToField constraint - let h2f_len = self.hash_to_field_constraints.len() as u32; - buffer.extend_from_slice(&h2f_len.to_be_bytes()); - for constraint in self.hash_to_field_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each HashToField constraint - let fixed_base_scalar_mul_len = self.fixed_base_scalar_mul_constraints.len() as u32; - buffer.extend_from_slice(&fixed_base_scalar_mul_len.to_be_bytes()); - for constraint in self.fixed_base_scalar_mul_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - let recursion_constraints_len = self.recursion_constraints.len() as u32; - buffer.extend_from_slice(&recursion_constraints_len.to_be_bytes()); - for constraint in self.recursion_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Arithmetic constraint - let constraints_len = self.constraints.len() as u32; - buffer.extend_from_slice(&constraints_len.to_be_bytes()); - for constraint in self.constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - // Serialize each Block constraint - let len = self.block_constraints.len() as u32; - buffer.extend_from_slice(&len.to_be_bytes()); - for constraint in self.block_constraints.iter() { - buffer.extend(&constraint.to_bytes()); - } - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct MemOpBarretenberg { - pub(crate) is_store: i8, - pub(crate) index: Constraint, - pub(crate) value: Constraint, -} -impl MemOpBarretenberg { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - buffer.extend_from_slice(&self.is_store.to_be_bytes()); - buffer.extend_from_slice(&self.index.to_bytes()); - buffer.extend_from_slice(&self.value.to_bytes()); - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct BlockConstraint { - pub(crate) init: Vec, - pub(crate) trace: Vec, - pub(crate) is_ram: i8, -} - -impl BlockConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let len = self.init.len() as u32; - buffer.extend_from_slice(&len.to_be_bytes()); - for value in self.init.iter() { - buffer.extend_from_slice(&value.to_bytes()); - } - - let len = self.trace.len() as u32; - buffer.extend_from_slice(&len.to_be_bytes()); - for op in self.trace.iter() { - buffer.extend_from_slice(&op.to_bytes()); - } - buffer.extend_from_slice(&self.is_ram.to_be_bytes()); - - buffer - } -} - -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] -pub(crate) struct RecursionConstraint { - pub(crate) key: Vec, // UP size is 115 - pub(crate) proof: Vec, // UP size is 94 - pub(crate) public_inputs: Vec, - pub(crate) key_hash: i32, - pub(crate) input_aggregation_object: [i32; 16], - pub(crate) output_aggregation_object: [i32; 16], - pub(crate) nested_aggregation_object: [i32; 16], -} - -impl RecursionConstraint { - fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let vk_len = (self.key.len()) as u32; - buffer.extend_from_slice(&vk_len.to_be_bytes()); - for constraint in self.key.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - let proof_len = (self.proof.len()) as u32; - buffer.extend_from_slice(&proof_len.to_be_bytes()); - for constraint in self.proof.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - let public_inputs_len = (self.public_inputs.len()) as u32; - buffer.extend_from_slice(&public_inputs_len.to_be_bytes()); - for constraint in self.public_inputs.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - buffer.extend_from_slice(&self.key_hash.to_be_bytes()); - - // The aggregation objects are both array's in barretenberg - // Thus, we do not need to write the length - for constraint in self.input_aggregation_object.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - for constraint in self.output_aggregation_object.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - for constraint in self.nested_aggregation_object.iter() { - buffer.extend_from_slice(&constraint.to_be_bytes()); - } - - buffer - } -} - -impl TryFrom<&Circuit> for ConstraintSystem { - type Error = BackendError; - /// Converts an `IR` into the `StandardFormat` constraint system - fn try_from(circuit: &Circuit) -> Result { - // Create constraint system - let mut constraints: Vec = Vec::new(); - let mut range_constraints: Vec = Vec::new(); - let mut logic_constraints: Vec = Vec::new(); - let mut sha256_constraints: Vec = Vec::new(); - let mut blake2s_constraints: Vec = Vec::new(); - let block_constraints: Vec = Vec::new(); - let mut keccak_constraints: Vec = Vec::new(); - let mut keccak_var_constraints: Vec = Vec::new(); - let mut pedersen_constraints: Vec = Vec::new(); - let mut schnorr_constraints: Vec = Vec::new(); - let mut ecdsa_secp256k1_constraints: Vec = Vec::new(); - let mut ecdsa_secp256r1_constraints: Vec = Vec::new(); - let mut fixed_base_scalar_mul_constraints: Vec = Vec::new(); - let mut hash_to_field_constraints: Vec = Vec::new(); - let mut recursion_constraints: Vec = Vec::new(); - - let mut blocks: BTreeMap = BTreeMap::new(); - for gate in circuit.opcodes.iter() { - match gate { - Opcode::Arithmetic(expression) => { - let constraint = serialize_arithmetic_gates(expression); - constraints.push(constraint); - } - Opcode::BlackBoxFuncCall(gadget_call) => { - match gadget_call { - BlackBoxFuncCall::RANGE { input } => { - let witness = input.witness; - let num_bits = input.num_bits; - - let range_constraint = RangeConstraint { - a: witness.witness_index() as i32, - num_bits: num_bits as i32, - }; - range_constraints.push(range_constraint); - } - BlackBoxFuncCall::AND { lhs, rhs, output } - | BlackBoxFuncCall::XOR { lhs, rhs, output } => { - let witness_lhs = lhs.witness; - let witness_rhs = rhs.witness; - - assert_eq!(lhs.num_bits, rhs.num_bits); - let num_bits = rhs.num_bits; - - match gadget_call { - BlackBoxFuncCall::AND { .. } => { - let and = LogicConstraint::and( - witness_lhs.witness_index() as i32, - witness_rhs.witness_index() as i32, - output.witness_index() as i32, - num_bits as i32, - ); - logic_constraints.push(and); - } - BlackBoxFuncCall::XOR { .. } => { - let xor = LogicConstraint::xor( - witness_lhs.witness_index() as i32, - witness_rhs.witness_index() as i32, - output.witness_index() as i32, - num_bits as i32, - ); - logic_constraints.push(xor); - } - _ => unreachable!("expected either an AND or XOR opcode"), - } - } - BlackBoxFuncCall::SHA256 { inputs, outputs } => { - let mut sha256_inputs: Vec<(i32, i32)> = Vec::new(); - for input in inputs.iter() { - let witness_index = input.witness.witness_index() as i32; - let num_bits = input.num_bits as i32; - sha256_inputs.push((witness_index, num_bits)); - } - - assert_eq!(outputs.len(), 32); - - let mut outputs_iter = outputs.iter(); - let mut result = [0i32; 32]; - for (i, res) in result.iter_mut().enumerate() { - let out_byte = outputs_iter.next().ok_or_else(|| { - Error::MalformedBlackBoxFunc( - BlackBoxFunc::SHA256, - format!("Missing rest of output. Tried to get byte {i} but failed"), - ) - })?; - - let out_byte_index = out_byte.witness_index() as i32; - *res = out_byte_index - } - let sha256_constraint = Sha256Constraint { - inputs: sha256_inputs, - result, - }; - - sha256_constraints.push(sha256_constraint); - } - BlackBoxFuncCall::Blake2s { inputs, outputs } => { - let mut blake2s_inputs: Vec<(i32, i32)> = Vec::new(); - for input in inputs.iter() { - let witness_index = input.witness.witness_index() as i32; - let num_bits = input.num_bits as i32; - blake2s_inputs.push((witness_index, num_bits)); - } - - assert_eq!(outputs.len(), 32); - - let mut outputs_iter = outputs.iter(); - let mut result = [0i32; 32]; - for (i, res) in result.iter_mut().enumerate() { - let out_byte = - outputs_iter.next().ok_or_else(|| { - Error::MalformedBlackBoxFunc( - BlackBoxFunc::Blake2s, - format!("Missing rest of output. Tried to get byte {i} but failed"), - ) - })?; - - let out_byte_index = out_byte.witness_index() as i32; - *res = out_byte_index - } - let blake2s_constraint = Blake2sConstraint { - inputs: blake2s_inputs, - result, - }; - - blake2s_constraints.push(blake2s_constraint); - } - BlackBoxFuncCall::SchnorrVerify { - public_key_x, - public_key_y, - signature, - message: message_inputs, - output, - } => { - let public_key_x = public_key_x.witness.witness_index() as i32; - let public_key_y = public_key_y.witness.witness_index() as i32; - - let mut signature_iter = signature.iter(); - let mut signature = [0i32; 64]; - for (i, sig) in signature.iter_mut().enumerate() { - let sig_byte = - signature_iter.next().ok_or_else(||Error::MalformedBlackBoxFunc( - BlackBoxFunc::SchnorrVerify, - format!("Missing rest of signature. Tried to get byte {i} but failed"), - ))?; - let sig_byte_index = sig_byte.witness.witness_index() as i32; - *sig = sig_byte_index - } - - // The rest of the input is the message - let mut message = Vec::new(); - for msg in message_inputs.iter() { - let msg_byte_index = msg.witness.witness_index() as i32; - message.push(msg_byte_index); - } - - // result - let result = output.witness_index() as i32; - - let constraint = SchnorrConstraint { - message, - signature, - public_key_x, - public_key_y, - result, - }; - - schnorr_constraints.push(constraint); - } - BlackBoxFuncCall::Pedersen { - inputs: gadget_call_inputs, - domain_separator, - outputs, - } => { - let mut inputs = Vec::new(); - for scalar in gadget_call_inputs.iter() { - let scalar_index = scalar.witness.witness_index() as i32; - inputs.push(scalar_index); - } - - let result_x = outputs.0.witness_index() as i32; - let result_y = outputs.1.witness_index() as i32; - - let constraint = PedersenConstraint { - inputs, - hash_index: *domain_separator, - result_x, - result_y, - }; - - pedersen_constraints.push(constraint); - } - BlackBoxFuncCall::HashToField128Security { inputs, output } => { - let mut hash_to_field_inputs: Vec<(i32, i32)> = Vec::new(); - for input in inputs.iter() { - let witness_index = input.witness.witness_index() as i32; - let num_bits = input.num_bits as i32; - hash_to_field_inputs.push((witness_index, num_bits)); - } - - let result = output.witness_index() as i32; - - let hash_to_field_constraint = HashToFieldConstraint { - inputs: hash_to_field_inputs, - result, - }; - - hash_to_field_constraints.push(hash_to_field_constraint); - } - BlackBoxFuncCall::EcdsaSecp256k1 { - public_key_x: public_key_x_inputs, - public_key_y: public_key_y_inputs, - signature: signature_inputs, - hashed_message: hashed_message_inputs, - output, - } => { - // public key x - let mut public_key_x_inputs = public_key_x_inputs.iter(); - let mut public_key_x = [0i32; 32]; - for (i, pkx) in public_key_x.iter_mut().enumerate() { - let x_byte = public_key_x_inputs - .next() - .ok_or_else(|| Error::MalformedBlackBoxFunc( - BlackBoxFunc::EcdsaSecp256k1, - format!("Missing rest of `x` component for public key. Tried to get byte {i} but failed"), - ))?; - let x_byte_index = x_byte.witness.witness_index() as i32; - *pkx = x_byte_index; - } - - // public key y - let mut public_key_y_inputs = public_key_y_inputs.iter(); - let mut public_key_y = [0i32; 32]; - for (i, pky) in public_key_y.iter_mut().enumerate() { - let y_byte = public_key_y_inputs - .next() - .ok_or_else(|| Error::MalformedBlackBoxFunc( - BlackBoxFunc::EcdsaSecp256k1, - format!("Missing rest of `y` component for public key. Tried to get byte {i} but failed"), - ))?; - let y_byte_index = y_byte.witness.witness_index() as i32; - *pky = y_byte_index; - } - - // signature - let mut signature_inputs = signature_inputs.iter(); - let mut signature = [0i32; 64]; - for (i, sig) in signature.iter_mut().enumerate() { - let sig_byte = - signature_inputs.next().ok_or_else(|| Error::MalformedBlackBoxFunc( - BlackBoxFunc::EcdsaSecp256k1, - format!("Missing rest of signature. Tried to get byte {i} but failed"), - ))?; - let sig_byte_index = sig_byte.witness.witness_index() as i32; - *sig = sig_byte_index; - } - - // The rest of the input is the message - let mut hashed_message = Vec::new(); - for msg in hashed_message_inputs.iter() { - let msg_byte_index = msg.witness.witness_index() as i32; - hashed_message.push(msg_byte_index); - } - - // result - let result = output.witness_index() as i32; - - let constraint = EcdsaConstraint { - hashed_message, - signature, - public_key_x, - public_key_y, - result, - }; - - ecdsa_secp256k1_constraints.push(constraint); - } - BlackBoxFuncCall::EcdsaSecp256r1 { - public_key_x: public_key_x_inputs, - public_key_y: public_key_y_inputs, - signature: signature_inputs, - hashed_message: hashed_message_inputs, - output, - } => { - // public key x - let mut public_key_x_inputs = public_key_x_inputs.iter(); - let mut public_key_x = [0i32; 32]; - for (i, pkx) in public_key_x.iter_mut().enumerate() { - let x_byte = public_key_x_inputs - .next() - .ok_or_else(|| Error::MalformedBlackBoxFunc( - BlackBoxFunc::EcdsaSecp256r1, - format!("Missing rest of `x` component for public key. Tried to get byte {i} but failed"), - ))?; - let x_byte_index = x_byte.witness.witness_index() as i32; - *pkx = x_byte_index; - } - - // public key y - let mut public_key_y_inputs = public_key_y_inputs.iter(); - let mut public_key_y = [0i32; 32]; - for (i, pky) in public_key_y.iter_mut().enumerate() { - let y_byte = public_key_y_inputs - .next() - .ok_or_else(|| Error::MalformedBlackBoxFunc( - BlackBoxFunc::EcdsaSecp256r1, - format!("Missing rest of `y` component for public key. Tried to get byte {i} but failed"), - ))?; - let y_byte_index = y_byte.witness.witness_index() as i32; - *pky = y_byte_index; - } - - // signature - let mut signature_inputs = signature_inputs.iter(); - let mut signature = [0i32; 64]; - for (i, sig) in signature.iter_mut().enumerate() { - let sig_byte = - signature_inputs.next().ok_or_else(|| Error::MalformedBlackBoxFunc( - BlackBoxFunc::EcdsaSecp256r1, - format!("Missing rest of signature. Tried to get byte {i} but failed"), - ))?; - let sig_byte_index = sig_byte.witness.witness_index() as i32; - *sig = sig_byte_index; - } - - // The rest of the input is the message - let mut hashed_message = Vec::new(); - for msg in hashed_message_inputs.iter() { - let msg_byte_index = msg.witness.witness_index() as i32; - hashed_message.push(msg_byte_index); - } - - // result - let result = output.witness_index() as i32; - - let constraint = EcdsaConstraint { - hashed_message, - signature, - public_key_x, - public_key_y, - result, - }; - - ecdsa_secp256r1_constraints.push(constraint); - } - BlackBoxFuncCall::FixedBaseScalarMul { input, outputs } => { - let scalar = input.witness.witness_index() as i32; - - let pubkey_x = outputs.0.witness_index() as i32; - let pubkey_y = outputs.1.witness_index() as i32; - - let fixed_base_scalar_mul = FixedBaseScalarMulConstraint { - scalar, - pubkey_x, - pubkey_y, - }; - - fixed_base_scalar_mul_constraints.push(fixed_base_scalar_mul); - } - BlackBoxFuncCall::Keccak256 { inputs, outputs } => { - let mut keccak_inputs: Vec<(i32, i32)> = Vec::new(); - for input in inputs.iter() { - let witness_index = input.witness.witness_index() as i32; - let num_bits = input.num_bits as i32; - keccak_inputs.push((witness_index, num_bits)); - } - - assert_eq!(outputs.len(), 32); - - let mut outputs_iter = outputs.iter(); - let mut result = [0i32; 32]; - for (i, res) in result.iter_mut().enumerate() { - let out_byte = - outputs_iter.next().ok_or_else(|| { - Error::MalformedBlackBoxFunc( - BlackBoxFunc::Keccak256, - format!("Missing rest of output. Tried to get byte {i} but failed"), - ) - })?; - - let out_byte_index = out_byte.witness_index() as i32; - *res = out_byte_index - } - let keccak_constraint = Keccak256Constraint { - inputs: keccak_inputs, - result, - }; - - keccak_constraints.push(keccak_constraint); - } - BlackBoxFuncCall::Keccak256VariableLength { - inputs, - var_message_size, - outputs, - } => { - let mut keccak_inputs: Vec<(i32, i32)> = Vec::new(); - for input in inputs.iter() { - let witness_index = input.witness.witness_index() as i32; - let num_bits = input.num_bits as i32; - keccak_inputs.push((witness_index, num_bits)); - } - - let var_message_size = var_message_size.witness.witness_index() as i32; - - assert_eq!(outputs.len(), 32); - - let mut outputs_iter = outputs.iter(); - let mut result = [0i32; 32]; - for (i, res) in result.iter_mut().enumerate() { - let out_byte = - outputs_iter.next().ok_or_else(|| { - Error::MalformedBlackBoxFunc( - BlackBoxFunc::Keccak256, - format!("Missing rest of output. Tried to get byte {i} but failed"), - ) - })?; - - let out_byte_index = out_byte.witness_index() as i32; - *res = out_byte_index - } - let keccak_var_constraint = Keccak256VarConstraint { - inputs: keccak_inputs, - var_message_size, - result, - }; - - keccak_var_constraints.push(keccak_var_constraint); - } - BlackBoxFuncCall::RecursiveAggregation { - verification_key: key_inputs, - proof: proof_inputs, - public_inputs: public_inputs_inputs, - key_hash, - input_aggregation_object, - output_aggregation_object, - } => { - let mut key_inputs = key_inputs.iter(); - let mut key_array = [0i32; 114]; - for (i, vk_witness) in key_array.iter_mut().enumerate() { - let vk_field = key_inputs.next().unwrap_or_else(|| { - panic!( - "missing rest of vkey. Tried to get field {i} but failed" - ) - }); - let vk_field_index = vk_field.witness.witness_index() as i32; - *vk_witness = vk_field_index; - } - let key = key_array.to_vec(); - - let mut proof = Vec::new(); - for proof_field in proof_inputs.iter() { - let proof_field_index = proof_field.witness.witness_index() as i32; - proof.push(proof_field_index); - } - - let mut public_inputs = Vec::new(); - for public_input in public_inputs_inputs.iter() { - let public_input_field_index = - public_input.witness.witness_index() as i32; - public_inputs.push(public_input_field_index); - } - - // key_hash - let key_hash = key_hash.witness.witness_index() as i32; - - let input_agg_obj_inputs = - if let Some(input_aggregation_object) = input_aggregation_object { - input_aggregation_object.clone() - } else { - vec![FunctionInput::dummy(); output_aggregation_object.len()] - }; - - // input_aggregation_object - let mut input_agg_obj_inputs = input_agg_obj_inputs.iter(); - let mut input_aggregation_object = [0i32; 16]; - for (i, var) in input_aggregation_object.iter_mut().enumerate() { - let var_field = input_agg_obj_inputs.next().unwrap_or_else(|| panic!("missing rest of output aggregation object. Tried to get byte {i} but failed")); - let var_field_index = var_field.witness.witness_index() as i32; - *var = var_field_index; - } - - // nested_aggregation_object - let mut nested_aggregation_object: [i32; 16] = [0; 16]; - if key[5] == 1 { - nested_aggregation_object = key[6..22].try_into().expect("missing nested aggregation object. verification key most likely malformed"); - } - - // output_aggregation_object - let mut outputs_iter = output_aggregation_object.iter(); - let mut output_aggregation_object = [0i32; 16]; - for (i, var) in output_aggregation_object.iter_mut().enumerate() { - let var_field = outputs_iter.next().unwrap_or_else(|| panic!("missing rest of output aggregation object. Tried to get byte {i} but failed")); - let var_field_index = var_field.witness_index() as i32; - *var = var_field_index; - } - - let recursion_constraint = RecursionConstraint { - key, - proof, - public_inputs, - key_hash, - input_aggregation_object, - output_aggregation_object, - nested_aggregation_object, - }; - - recursion_constraints.push(recursion_constraint); - } - }; - } - Opcode::Directive(_) | Opcode::Brillig(_) => { - // Directives, Oracles and Brillig are only needed by the pwg - } - Opcode::MemoryOp { block_id, op } => { - let block = blocks - .get_mut(&block_id.0) - .expect("memory operation on an uninitialized block"); - - let index = serialize_arithmetic_gates(&op.index); - let value = serialize_arithmetic_gates(&op.value); - let bb_op = MemOpBarretenberg { - is_store: op.operation.to_const().unwrap().to_u128() as i8, - index, - value, - }; - block.trace.push(bb_op); - } - Opcode::MemoryInit { block_id, init } => { - let init = init - .iter() - .map(|w| { - let mut constraint = Constraint::default(); - constraint.set_linear_term(FieldElement::one(), w.as_usize() as i32); - constraint - }) - .collect(); - let block = BlockConstraint { - init, - trace: Vec::new(), - is_ram: 1, - }; - blocks.insert(block_id.0, block); - } - } - } - - // Create constraint system - Ok(ConstraintSystem { - var_num: circuit.current_witness_index + 1, // number of witnesses is the witness index + 1; - public_inputs: circuit.public_inputs().indices(), - logic_constraints, - range_constraints, - sha256_constraints, - pedersen_constraints, - schnorr_constraints, - ecdsa_secp256k1_constraints, - ecdsa_secp256r1_constraints, - blake2s_constraints, - block_constraints, - keccak_constraints, - keccak_var_constraints, - hash_to_field_constraints, - constraints, - fixed_base_scalar_mul_constraints, - recursion_constraints, - }) - } -} - -#[allow(non_snake_case)] -fn serialize_arithmetic_gates(gate: &Expression) -> Constraint { - let mut cs = Constraint::default(); - // check mul gate - if !gate.mul_terms.is_empty() { - let mul_term = &gate.mul_terms[0]; - cs.qm = mul_term.0; - - // Get wL term - let wL = &mul_term.1; - cs.a = wL.witness_index() as i32; - - // Get wR term - let wR = &mul_term.2; - cs.b = wR.witness_index() as i32; - } - - for term in &gate.linear_combinations { - cs.set_linear_term(term.0, term.1.witness_index() as i32); - } - - // Add the qc term - cs.qc = gate.q_c; - cs -} - -#[cfg(test)] -mod tests { - use crate::barretenberg_structures::serialize_arithmetic_gates; - use acvm::acir::native_types::{Expression, Witness}; - use acvm::FieldElement; - - #[test] - fn serialize_expression() { - let x1 = Witness::new(1); - let x3 = Witness::new(3); - let two = FieldElement::one() + FieldElement::one(); - let e = Expression { - mul_terms: vec![(FieldElement::one(), x1, x1)], - linear_combinations: vec![(two, x1), (-FieldElement::one(), x3)], - q_c: FieldElement::one(), - }; - let constrain = serialize_arithmetic_gates(&e); - assert_eq!(constrain.a, 1); - assert_eq!(constrain.b, 1); - assert_eq!(constrain.c, 3); - - let x2 = Witness::new(2); - let x8 = Witness::new(8); - let e = Expression { - mul_terms: vec![(-FieldElement::one(), x1, x2)], - linear_combinations: vec![(-FieldElement::one(), x8)], - q_c: FieldElement::zero(), - }; - let constrain = serialize_arithmetic_gates(&e); - assert_eq!(constrain.a, 1); - assert_eq!(constrain.b, 2); - assert_eq!(constrain.c, 8); - - let e = Expression { - mul_terms: vec![], - linear_combinations: vec![(FieldElement::one(), x8)], - q_c: FieldElement::zero(), - }; - let constrain = serialize_arithmetic_gates(&e); - assert_eq!(constrain.a, 8); - assert_eq!(constrain.b, 0); - assert_eq!(constrain.c, 0); - - let e = Expression { - mul_terms: vec![(FieldElement::one(), x1, x2)], - linear_combinations: vec![ - (FieldElement::one(), x8), - (two, x2), - (-FieldElement::one(), x1), - ], - q_c: FieldElement::zero(), - }; - let constrain = serialize_arithmetic_gates(&e); - assert_eq!(constrain.a, 1); - assert_eq!(constrain.b, 2); - assert_eq!(constrain.c, 8); - } -} diff --git a/src/bb/contract.rs b/src/bb/contract.rs new file mode 100644 index 00000000..07131861 --- /dev/null +++ b/src/bb/contract.rs @@ -0,0 +1,75 @@ +use super::{assert_binary_exists, get_binary_path, CliShimError}; + +/// VerifyCommand will call the barretenberg binary +/// to return a solidity library with the verification key +/// that can be used to verify proofs on-chain. +/// +/// This does not return a Solidity file that is able +/// to verify a proof. See acvm_interop/contract.sol for the +/// remaining logic that is missing. +pub(crate) struct ContractCommand { + pub(crate) verbose: bool, + pub(crate) path_to_crs: String, + pub(crate) path_to_vk: String, + pub(crate) path_to_contract: String, +} + +impl ContractCommand { + pub(crate) fn run(self) -> Result<(), CliShimError> { + assert_binary_exists(); + let mut command = std::process::Command::new(get_binary_path()); + + command + .arg("contract") + .arg("-c") + .arg(self.path_to_crs) + .arg("-k") + .arg(self.path_to_vk) + .arg("-o") + .arg(self.path_to_contract); + + if self.verbose { + command.arg("-v"); + } + + let output = command.output().expect("Failed to execute command"); + if output.status.success() { + Ok(()) + } else { + Err(CliShimError(String::from_utf8(output.stderr).unwrap())) + } + } +} + +#[test] +fn contract_command() { + use tempfile::tempdir; + + let path_to_1_mul = "./src/1_mul.bytecode"; + + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory_path = temp_directory.path(); + let path_to_crs = temp_directory_path.join("crs"); + let path_to_vk = temp_directory_path.join("vk"); + let path_to_contract = temp_directory_path.join("contract"); + + let write_vk_command = super::WriteVkCommand { + verbose: true, + path_to_bytecode: path_to_1_mul.to_string(), + path_to_vk_output: path_to_vk.to_str().unwrap().to_string(), + is_recursive: false, + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + }; + + assert!(write_vk_command.run().is_ok()); + + let contract_command = ContractCommand { + verbose: true, + path_to_vk: path_to_vk.to_str().unwrap().to_string(), + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + path_to_contract: path_to_contract.to_str().unwrap().to_string(), + }; + + assert!(contract_command.run().is_ok()); + drop(temp_directory); +} diff --git a/src/bb/gates.rs b/src/bb/gates.rs new file mode 100644 index 00000000..c9db7034 --- /dev/null +++ b/src/bb/gates.rs @@ -0,0 +1,71 @@ +use super::{assert_binary_exists, get_binary_path}; + +/// GatesCommand will call the barretenberg binary +/// to return the number of gates needed to create a proof +/// for the given bytecode. +pub(crate) struct GatesCommand { + pub(crate) path_to_crs: String, + pub(crate) path_to_bytecode: String, +} + +impl GatesCommand { + pub(crate) fn run(self) -> u32 { + assert_binary_exists(); + let output = std::process::Command::new(get_binary_path()) + .arg("gates") + .arg("-c") + .arg(self.path_to_crs) + .arg("-b") + .arg(self.path_to_bytecode) + .output() + .expect("Failed to execute command"); + + if !output.status.success() { + panic!( + "gates command encountered an error: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + // Note: barretenberg includes the newline, so that subsequent prints to stdout + // are not on the same line as the gates output. + + // Ensure we got the expected number of bytes + if output.stdout.len() != 8 { + panic!("Unexpected 8 bytes, received {}", output.stdout.len()); + } + + // Convert bytes to u64 in little-endian format + let value = u64::from_le_bytes([ + output.stdout[0], + output.stdout[1], + output.stdout[2], + output.stdout[3], + output.stdout[4], + output.stdout[5], + output.stdout[6], + output.stdout[7], + ]); + + value as u32 + } +} + +#[test] +fn gate_command() { + use tempfile::tempdir; + + let path_to_1_mul = "./src/1_mul.bytecode"; + + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory_path = temp_directory.path(); + let path_to_crs = temp_directory_path.join("crs"); + + let gate_command = GatesCommand { + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + path_to_bytecode: path_to_1_mul.to_string(), + }; + + let output = gate_command.run(); + assert_eq!(output, 2775); + drop(temp_directory); +} diff --git a/src/bb/mod.rs b/src/bb/mod.rs new file mode 100644 index 00000000..373e021a --- /dev/null +++ b/src/bb/mod.rs @@ -0,0 +1,123 @@ +// Reference: https://github.com/AztecProtocol/aztec-packages/blob/master/circuits/cpp/barretenberg/cpp/src/barretenberg/bb/main.cpp + +mod contract; +mod gates; +mod prove; +mod prove_and_verify; +mod verify; +mod write_vk; + +use std::{io::Cursor, path::PathBuf}; + +use const_format::formatcp; +pub(crate) use contract::ContractCommand; +pub(crate) use gates::GatesCommand; +pub(crate) use prove::ProveCommand; +pub(crate) use verify::VerifyCommand; +pub(crate) use write_vk::WriteVkCommand; + +#[derive(Debug, thiserror::Error)] +#[error("Error communicating with barretenberg binary {0}")] +pub(crate) struct CliShimError(String); + +const USERNAME: &str = "AztecProtocol"; +const REPO: &str = "barretenberg"; +const VERSION: &str = "0.4.6"; +const TAG: &str = formatcp!("barretenberg-v{}", VERSION); +const DEST_FOLDER: &str = ".nargo/backends/acvm-backend-barretenberg"; +const BINARY_NAME: &str = "backend_binary"; + +const API_URL: &str = formatcp!( + "https://github.com/{}/{}/releases/download/{}", + USERNAME, + REPO, + TAG +); + +fn get_bb_download_url() -> String { + if let Ok(path) = std::env::var("BB_BINARY_URL") { + return path; + } + + let target_os = env!("TARGET_OS"); + let target_arch = env!("TARGET_ARCH"); + + let archive_name = match target_os { + "linux" => "barretenberg-x86_64-linux-gnu.tar.gz", + "macos" => match target_arch { + "aarch64" => "barretenberg-aarch64-apple-darwin.tar.gz", + "x86_64" => "barretenberg-x86_64-apple-darwin.tar.gz", + arch => panic!("unsupported arch {arch}"), + }, + os => panic!("Unsupported OS {os}"), + }; + + format!("{API_URL}/{archive_name}") +} + +/// Returns the path to the binary that was set by the `NARGO_BINARIES_PATH` environment variable +fn get_binary_path() -> PathBuf { + match std::env::var("BB_BINARY_PATH") { + Ok(path) => PathBuf::from(path), + Err(_) => dirs::home_dir() + .unwrap() + .join(formatcp!("{}/{}", DEST_FOLDER, BINARY_NAME)), + } +} + +fn assert_binary_exists() { + if !get_binary_path().exists() { + download_bb_binary() + } +} + +fn download_bb_binary() { + use flate2::read::GzDecoder; + use tar::Archive; + use tempfile::tempdir; + + // Create directory to place binary in. + std::fs::create_dir_all(get_binary_path().parent().unwrap()).unwrap(); + + // Download sources + let compressed_file: Cursor> = download_binary_from_url(&get_bb_download_url()) + .unwrap_or_else(|error| panic!("\n\nDownload error: {error}\n\n")); + + // Unpack the tarball + let gz_decoder = GzDecoder::new(compressed_file); + let mut archive = Archive::new(gz_decoder); + + let temp_directory = tempdir().expect("could not create a temporary directory"); + archive.unpack(&temp_directory).unwrap(); + let binary_path = temp_directory.path().join("bb"); + + // Rename the binary to the desired name + std::fs::copy(binary_path, get_binary_path()).unwrap(); + + drop(temp_directory); +} + +/// Try to download the specified URL into a buffer which is returned. +fn download_binary_from_url(url: &str) -> Result>, String> { + let response = reqwest::blocking::get(url).map_err(|error| error.to_string())?; + + let bytes = response.bytes().unwrap(); + + // TODO: Check SHA of downloaded binary + + Ok(Cursor::new(bytes.to_vec())) +} + +#[test] +fn no_command_provided_works() { + // This is a simple test to check that the binaries work + + assert_binary_exists(); + + let output = std::process::Command::new(get_binary_path()) + .output() + .expect("Failed to execute command"); + + let stderr = String::from_utf8_lossy(&output.stderr); + assert_eq!(stderr, "No command provided.\n"); +} diff --git a/src/bb/prove.rs b/src/bb/prove.rs new file mode 100644 index 00000000..3c3dbd1f --- /dev/null +++ b/src/bb/prove.rs @@ -0,0 +1,77 @@ +use super::{assert_binary_exists, get_binary_path, CliShimError}; + +/// ProveCommand will call the barretenberg binary +/// to create a proof, given the witness and the bytecode. +/// +/// Note:Internally barretenberg will create and discard the +/// proving key, so this is not returned. +/// +/// The proof will be written to the specified output file. +pub(crate) struct ProveCommand { + pub(crate) verbose: bool, + pub(crate) path_to_crs: String, + pub(crate) is_recursive: bool, + pub(crate) path_to_bytecode: String, + pub(crate) path_to_witness: String, + pub(crate) path_to_proof: String, +} + +impl ProveCommand { + pub(crate) fn run(self) -> Result<(), CliShimError> { + assert_binary_exists(); + let mut command = std::process::Command::new(get_binary_path()); + + command + .arg("prove") + .arg("-c") + .arg(self.path_to_crs) + .arg("-b") + .arg(self.path_to_bytecode) + .arg("-w") + .arg(self.path_to_witness) + .arg("-o") + .arg(self.path_to_proof); + + if self.verbose { + command.arg("-v"); + } + if self.is_recursive { + command.arg("-r"); + } + + let output = command.output().expect("Failed to execute command"); + + if output.status.success() { + Ok(()) + } else { + Err(CliShimError(String::from_utf8(output.stderr).unwrap())) + } + } +} + +#[test] +fn prove_command() { + use tempfile::tempdir; + + let path_to_1_mul = "./src/1_mul.bytecode"; + let path_to_1_mul_witness = "./src/witness.tr"; + + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory_path = temp_directory.path(); + + let path_to_crs = temp_directory_path.join("crs"); + let path_to_proof = temp_directory_path.join("1_mul").with_extension("proof"); + + let prove_command = ProveCommand { + verbose: true, + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + is_recursive: false, + path_to_bytecode: path_to_1_mul.to_string(), + path_to_witness: path_to_1_mul_witness.to_string(), + path_to_proof: path_to_proof.to_str().unwrap().to_string(), + }; + + let proof_created = prove_command.run(); + assert!(proof_created.is_ok()); + drop(temp_directory); +} diff --git a/src/bb/prove_and_verify.rs b/src/bb/prove_and_verify.rs new file mode 100644 index 00000000..f877909f --- /dev/null +++ b/src/bb/prove_and_verify.rs @@ -0,0 +1,68 @@ +use super::{assert_binary_exists, get_binary_path}; + +/// ProveAndVerifyCommand will call the barretenberg binary +/// to create a proof and then verify the proof once created. +/// +/// Note: Functions like this are useful for testing. In a real workflow, +/// ProveCommand and VerifyCommand will be used separately. +#[allow(dead_code)] +struct ProveAndVerifyCommand { + verbose: bool, + path_to_crs: String, + is_recursive: bool, + path_to_bytecode: String, + path_to_witness: String, +} + +#[allow(dead_code)] +impl ProveAndVerifyCommand { + fn run(self) -> bool { + assert_binary_exists(); + let mut command = std::process::Command::new(get_binary_path()); + + command + .arg("prove_and_verify") + .arg("-c") + .arg(self.path_to_crs) + .arg("-b") + .arg(self.path_to_bytecode) + .arg("-w") + .arg(self.path_to_witness); + if self.verbose { + command.arg("-v"); + } + if self.is_recursive { + command.arg("-r"); + } + + command + .output() + .expect("Failed to execute command") + .status + .success() + } +} + +#[test] +fn prove_and_verify_command() { + use tempfile::tempdir; + + let path_to_1_mul = "./src/1_mul.bytecode"; + let path_to_1_mul_witness = "./src/witness.tr"; + + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory_path = temp_directory.path(); + let path_to_crs = temp_directory_path.join("crs"); + + let prove_and_verify_command = ProveAndVerifyCommand { + verbose: true, + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + is_recursive: false, + path_to_bytecode: path_to_1_mul.to_string(), + path_to_witness: path_to_1_mul_witness.to_string(), + }; + + let output = prove_and_verify_command.run(); + assert!(output); + drop(temp_directory); +} diff --git a/src/bb/verify.rs b/src/bb/verify.rs new file mode 100644 index 00000000..5ac40f81 --- /dev/null +++ b/src/bb/verify.rs @@ -0,0 +1,87 @@ +use super::{assert_binary_exists, get_binary_path}; + +/// VerifyCommand will call the barretenberg binary +/// to verify a proof +pub(crate) struct VerifyCommand { + pub(crate) verbose: bool, + pub(crate) path_to_crs: String, + pub(crate) is_recursive: bool, + pub(crate) path_to_proof: String, + pub(crate) path_to_vk: String, +} + +impl VerifyCommand { + pub(crate) fn run(self) -> bool { + assert_binary_exists(); + let mut command = std::process::Command::new(get_binary_path()); + + command + .arg("verify") + .arg("-c") + .arg(self.path_to_crs) + .arg("-p") + .arg(self.path_to_proof) + .arg("-k") + .arg(self.path_to_vk); + + if self.verbose { + command.arg("-v"); + } + if self.is_recursive { + command.arg("-r"); + } + + let output = command.output().expect("Failed to execute command"); + output.status.success() + } +} + +#[test] +fn verify_command() { + use tempfile::tempdir; + + use crate::bb::{ProveCommand, WriteVkCommand}; + + let path_to_1_mul = "./src/1_mul.bytecode"; + let path_to_1_mul_witness = "./src/witness.tr"; + + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory_path = temp_directory.path(); + + let path_to_crs = temp_directory_path.join("crs"); + let path_to_proof = temp_directory_path.join("1_mul").with_extension("proof"); + let path_to_vk = temp_directory_path.join("vk"); + + let write_vk_command = WriteVkCommand { + verbose: true, + path_to_bytecode: path_to_1_mul.to_string(), + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + is_recursive: false, + path_to_vk_output: path_to_vk.to_str().unwrap().to_string(), + }; + + let vk_written = write_vk_command.run(); + assert!(vk_written.is_ok()); + + let prove_command = ProveCommand { + verbose: true, + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + is_recursive: false, + path_to_bytecode: path_to_1_mul.to_string(), + path_to_witness: path_to_1_mul_witness.to_string(), + path_to_proof: path_to_proof.to_str().unwrap().to_string(), + }; + prove_command.run().unwrap(); + + let verify_command = VerifyCommand { + verbose: true, + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + is_recursive: false, + path_to_proof: path_to_proof.to_str().unwrap().to_string(), + path_to_vk: path_to_vk.to_str().unwrap().to_string(), + }; + + let verified = verify_command.run(); + assert!(verified); + drop(temp_directory); +} diff --git a/src/bb/write_vk.rs b/src/bb/write_vk.rs new file mode 100644 index 00000000..e330d58b --- /dev/null +++ b/src/bb/write_vk.rs @@ -0,0 +1,66 @@ +use super::{assert_binary_exists, get_binary_path, CliShimError}; + +/// WriteCommand will call the barretenberg binary +/// to write a verification key to a file +pub(crate) struct WriteVkCommand { + pub(crate) verbose: bool, + pub(crate) path_to_crs: String, + pub(crate) is_recursive: bool, + pub(crate) path_to_bytecode: String, + pub(crate) path_to_vk_output: String, +} + +impl WriteVkCommand { + pub(crate) fn run(self) -> Result<(), CliShimError> { + assert_binary_exists(); + let mut command = std::process::Command::new(get_binary_path()); + + command + .arg("write_vk") + .arg("-c") + .arg(self.path_to_crs) + .arg("-b") + .arg(self.path_to_bytecode) + .arg("-o") + .arg(self.path_to_vk_output); + + if self.verbose { + command.arg("-v"); + } + if self.is_recursive { + command.arg("-r"); + } + + let output = command.output().expect("Failed to execute command"); + + if output.status.success() { + Ok(()) + } else { + Err(CliShimError(String::from_utf8(output.stderr).unwrap())) + } + } +} + +#[test] +fn write_vk_command() { + use tempfile::tempdir; + + let path_to_1_mul = "./src/1_mul.bytecode"; + + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory_path = temp_directory.path(); + let path_to_crs = temp_directory_path.join("crs"); + let path_to_vk = temp_directory_path.join("vk"); + + let write_vk_command = WriteVkCommand { + verbose: true, + path_to_bytecode: path_to_1_mul.to_string(), + path_to_crs: path_to_crs.to_str().unwrap().to_string(), + is_recursive: false, + path_to_vk_output: path_to_vk.to_str().unwrap().to_string(), + }; + + let vk_written = write_vk_command.run(); + assert!(vk_written.is_ok()); + drop(temp_directory); +} diff --git a/src/common_reference_string.rs b/src/common_reference_string.rs deleted file mode 100644 index 15be2d32..00000000 --- a/src/common_reference_string.rs +++ /dev/null @@ -1,34 +0,0 @@ -use acvm::{acir::circuit::Circuit, async_trait, CommonReferenceString}; - -use crate::{barretenberg::composer::Composer, BackendError, Barretenberg}; - -// TODO(#185): Ensure CRS download works in JS -#[async_trait(?Send)] -impl CommonReferenceString for Barretenberg { - type Error = BackendError; - - async fn generate_common_reference_string( - &self, - circuit: &Circuit, - ) -> Result, Self::Error> { - let constraint_system = &circuit.try_into()?; - let common_reference_string = self.get_crs(constraint_system).await?.try_into()?; - // Separated to have nicer coercion on error types - Ok(common_reference_string) - } - - async fn update_common_reference_string( - &self, - common_reference_string: Vec, - circuit: &Circuit, - ) -> Result, Self::Error> { - let mut crs = common_reference_string.try_into()?; - let constraint_system = &circuit.try_into()?; - let common_reference_string = self - .update_crs(&mut crs, constraint_system) - .await? - .try_into()?; - // Separated to have nicer coercion on error types - Ok(common_reference_string) - } -} diff --git a/src/lib.rs b/src/lib.rs index b0c41135..46867a6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,15 +13,21 @@ compile_error!("feature \"native\" cannot be enabled for a \"wasm32\" target"); #[cfg(all(feature = "wasm", target_arch = "wasm32"))] compile_error!("feature \"wasm\" cannot be enabled for a \"wasm32\" target"); -mod barretenberg; -mod barretenberg_structures; -mod common_reference_string; +mod bb; mod proof_system; -mod pwg; mod smart_contract; -pub use barretenberg::Barretenberg; -use barretenberg::{CRSError, Error, FeatureError}; +/// The number of bytes necessary to store a `FieldElement`. +const FIELD_BYTES: usize = 32; + +#[derive(Debug, Default)] +pub struct Barretenberg; + +impl Barretenberg { + pub fn new() -> Barretenberg { + Barretenberg + } +} impl acvm::Backend for Barretenberg {} @@ -29,14 +35,6 @@ impl acvm::Backend for Barretenberg {} #[error(transparent)] pub struct BackendError(#[from] Error); -impl From for BackendError { - fn from(value: FeatureError) -> Self { - value.into() - } -} - -impl From for BackendError { - fn from(value: CRSError) -> Self { - value.into() - } -} +#[allow(clippy::upper_case_acronyms)] +#[derive(Debug, thiserror::Error)] +enum Error {} diff --git a/src/proof_system.rs b/src/proof_system.rs index 6ba945a1..33ec8457 100644 --- a/src/proof_system.rs +++ b/src/proof_system.rs @@ -1,11 +1,15 @@ +use std::fs::File; +use std::io::{Read, Write}; +use std::path::Path; + use acvm::acir::circuit::Opcode; use acvm::acir::{circuit::Circuit, native_types::WitnessMap, BlackBoxFunc}; use acvm::FieldElement; use acvm::{Language, ProofSystemCompiler}; +use tempfile::tempdir; -use crate::barretenberg::composer::Composer; -use crate::barretenberg_structures::Assignments; -use crate::{BackendError, Barretenberg}; +use crate::bb::{GatesCommand, ProveCommand, VerifyCommand, WriteVkCommand}; +use crate::{BackendError, Barretenberg, FIELD_BYTES}; impl ProofSystemCompiler for Barretenberg { type Error = BackendError; @@ -15,10 +19,23 @@ impl ProofSystemCompiler for Barretenberg { } fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { - Ok(Composer::get_exact_circuit_size( - self, - &circuit.try_into()?, - )?) + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory = temp_directory.path(); + let temp_dir_path_str = temp_directory.to_str().unwrap(); + + // Create a temporary file for the circuit + // + let circuit_path = temp_directory.join("circuit").with_extension("bytecode"); + let serialized_circuit = serialize_circuit(circuit); + write_to_file(serialized_circuit.as_bytes(), &circuit_path); + + let number_of_gates_needed = GatesCommand { + path_to_crs: temp_dir_path_str.to_string(), + path_to_bytecode: circuit_path.as_os_str().to_str().unwrap().to_string(), + } + .run(); + + Ok(number_of_gates_needed) } fn supports_opcode(&self, opcode: &Opcode) -> bool { @@ -46,57 +63,115 @@ impl ProofSystemCompiler for Barretenberg { } } - fn preprocess( - &self, - common_reference_string: &[u8], - circuit: &Circuit, - ) -> Result<(Vec, Vec), Self::Error> { - let crs = common_reference_string.try_into()?; - let constraint_system = &circuit.try_into()?; - - let proving_key = self.compute_proving_key(constraint_system)?; - let verification_key = self.compute_verification_key(&crs, &proving_key)?; - - Ok((proving_key, verification_key)) - } - fn prove_with_pk( &self, - common_reference_string: &[u8], + _common_reference_string: &[u8], circuit: &Circuit, witness_values: WitnessMap, - proving_key: &[u8], - _is_recursive: bool, + _proving_key: &[u8], + is_recursive: bool, ) -> Result, Self::Error> { - let crs = common_reference_string.try_into()?; - let assignments = flatten_witness_map(circuit, witness_values); - - Ok(self.create_proof_with_pk(&crs, &circuit.try_into()?, assignments, proving_key)?) + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory = temp_directory.path(); + let temp_dir_path_str = temp_directory.to_str().unwrap(); + + // Create a temporary file for the witness + let serialized_witnesses: Vec = witness_values + .try_into() + .expect("could not serialize witness map"); + let witness_path = temp_directory.join("witness").with_extension("tr"); + write_to_file(&serialized_witnesses, &witness_path); + + // Create a temporary file for the circuit + // + let circuit_path = temp_directory.join("circuit").with_extension("bytecode"); + let serialized_circuit = serialize_circuit(circuit); + write_to_file(serialized_circuit.as_bytes(), &circuit_path); + + let proof_path = temp_directory.join("proof").with_extension("proof"); + + // Create proof and store it in the specified path + ProveCommand { + verbose: true, + path_to_crs: temp_dir_path_str.to_string(), + is_recursive, + path_to_bytecode: circuit_path.as_os_str().to_str().unwrap().to_string(), + path_to_witness: witness_path.as_os_str().to_str().unwrap().to_string(), + path_to_proof: proof_path.as_os_str().to_str().unwrap().to_string(), + } + .run() + .expect("prove command failed"); + + let proof_with_public_inputs = + read_bytes_from_file(proof_path.as_os_str().to_str().unwrap()).unwrap(); + + // Barretenberg return the proof prepended with the public inputs. + // + // This is not how the API expects the proof to be formatted, + // so we remove the public inputs from the proof. + // + // TODO: As noted in the verification procedure, this is an abstraction leak + // TODO: and will need modifications to barretenberg + let proof = + remove_public_inputs(circuit.public_inputs().0.len(), &proof_with_public_inputs); + Ok(proof) } fn verify_with_vk( &self, - common_reference_string: &[u8], + _common_reference_string: &[u8], proof: &[u8], public_inputs: WitnessMap, circuit: &Circuit, - verification_key: &[u8], - _is_recursive: bool, + _verification_key: &[u8], + is_recursive: bool, ) -> Result { - let crs = common_reference_string.try_into()?; + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory = temp_directory.path(); + let temp_dir_path = temp_directory.to_str().unwrap(); + // Unlike when proving, we omit any unassigned witnesses. // Witness values should be ordered by their index but we skip over any indices without an assignment. let flattened_public_inputs: Vec = public_inputs.into_iter().map(|(_, el)| el).collect(); - Ok(Composer::verify_with_vk( - self, - &crs, - &circuit.try_into()?, - proof, - flattened_public_inputs.into(), - verification_key, - )?) + // Barretenberg expects the proof to be prepended with the public inputs. + // + // TODO: This is an abstraction leak and barretenberg's API should accept the public inputs + // TODO: separately and then prepend them internally + let proof_with_public_inputs = + prepend_public_inputs(proof.to_vec(), flattened_public_inputs.to_vec()); + + // Create a temporary file for the proof + let proof_path = temp_directory.join("proof").with_extension("proof"); + write_to_file(&proof_with_public_inputs, &proof_path); + + // Create a temporary file for the circuit + let circuit_path = temp_directory.join("circuit").with_extension("bytecode"); + let serialized_circuit = serialize_circuit(circuit); + write_to_file(serialized_circuit.as_bytes(), &circuit_path); + + // Create the verification key and write it to the specified path + let vk_path = temp_directory.join("vk"); + WriteVkCommand { + verbose: false, + path_to_crs: temp_dir_path.to_string(), + is_recursive, + path_to_bytecode: circuit_path.as_os_str().to_str().unwrap().to_string(), + path_to_vk_output: vk_path.as_os_str().to_str().unwrap().to_string(), + } + .run() + .expect("write vk command failed"); + + // Verify the proof + Ok(VerifyCommand { + verbose: false, + path_to_crs: temp_dir_path.to_string(), + is_recursive, + path_to_proof: proof_path.as_os_str().to_str().unwrap().to_string(), + path_to_vk: vk_path.as_os_str().to_str().unwrap().to_string(), + } + .run()) } fn proof_as_fields( @@ -116,20 +191,59 @@ impl ProofSystemCompiler for Barretenberg { } } -/// Flatten a witness map into a vector of witness assignments. -fn flatten_witness_map(circuit: &Circuit, witness_values: WitnessMap) -> Assignments { - let num_witnesses = circuit.num_vars(); - - // Note: The witnesses are sorted via their witness index - // witness_values may not have all the witness indexes, e.g for unused witness which are not solved by the solver - let witness_assignments: Vec = (1..num_witnesses) - .map(|witness_index| { - // Get the value if it exists. If i does not, then we fill it with the zero value - witness_values - .get_index(witness_index) - .map_or(FieldElement::zero(), |field| *field) - }) - .collect(); - - witness_assignments.into() +pub(super) fn write_to_file(bytes: &[u8], path: &Path) -> String { + let display = path.display(); + + let mut file = match File::create(path) { + Err(why) => panic!("couldn't create {display}: {why}"), + Ok(file) => file, + }; + + match file.write_all(bytes) { + Err(why) => panic!("couldn't write to {display}: {why}"), + Ok(_) => display.to_string(), + } +} + +pub(super) fn read_bytes_from_file(path: &str) -> std::io::Result> { + // Open the file for reading. + let mut file = File::open(path)?; + + // Create a buffer to store the bytes. + let mut buffer = Vec::new(); + + // Read bytes from the file. + file.read_to_end(&mut buffer)?; + + Ok(buffer) +} + +/// Removes the public inputs which are prepended to a proof by Barretenberg. +fn remove_public_inputs(num_pub_inputs: usize, proof: &[u8]) -> Vec { + // Barretenberg prepends the public inputs onto the proof so we need to remove + // the first `num_pub_inputs` field elements. + let num_bytes_to_remove = num_pub_inputs * FIELD_BYTES; + proof[num_bytes_to_remove..].to_vec() +} + +/// Prepends a set of public inputs to a proof. +fn prepend_public_inputs(proof: Vec, public_inputs: Vec) -> Vec { + if public_inputs.is_empty() { + return proof; + } + + let public_inputs_bytes = public_inputs + .into_iter() + .flat_map(|assignment| assignment.to_be_bytes()); + + public_inputs_bytes.chain(proof.into_iter()).collect() +} + +// TODO: See nargo/src/artifacts/mod.rs +// TODO: This method should live in ACVM and be the default method for serializing/deserializing circuits +pub(super) fn serialize_circuit(circuit: &Circuit) -> String { + use base64::Engine; + let mut circuit_bytes: Vec = Vec::new(); + circuit.write(&mut circuit_bytes).unwrap(); + base64::engine::general_purpose::STANDARD.encode(circuit_bytes) } diff --git a/src/pwg.rs b/src/pwg.rs deleted file mode 100644 index d10737d0..00000000 --- a/src/pwg.rs +++ /dev/null @@ -1,58 +0,0 @@ -use acvm::acir::BlackBoxFunc; -use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; - -use crate::barretenberg::pedersen::Pedersen; -use crate::barretenberg::scalar_mul::ScalarMul; -use crate::barretenberg::schnorr::SchnorrSig; -use crate::Barretenberg; - -impl BlackBoxFunctionSolver for Barretenberg { - fn schnorr_verify( - &self, - public_key_x: &FieldElement, - public_key_y: &FieldElement, - signature: &[u8], - message: &[u8], - ) -> Result { - // In barretenberg, if the signature fails, then the whole thing fails. - - let pub_key: Vec = public_key_x - .to_be_bytes() - .into_iter() - .chain(public_key_y.to_be_bytes()) - .collect(); - let pub_key: [u8; 64] = pub_key.try_into().unwrap(); - - let sig_s: [u8; 32] = signature[0..32].try_into().unwrap(); - let sig_e: [u8; 32] = signature[32..64].try_into().unwrap(); - - let valid_signature = self - .verify_signature(pub_key, sig_s, sig_e, message) - .map_err(|err| { - BlackBoxResolutionError::Failed(BlackBoxFunc::SchnorrVerify, err.to_string()) - })?; - if !valid_signature { - dbg!("signature has failed to verify"); - } - - Ok(valid_signature) - } - - fn pedersen( - &self, - inputs: &[FieldElement], - domain_separator: u32, - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - self.encrypt(inputs.to_vec(), domain_separator) - .map_err(|err| BlackBoxResolutionError::Failed(BlackBoxFunc::Pedersen, err.to_string())) - } - - fn fixed_base_scalar_mul( - &self, - input: &FieldElement, - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - self.fixed_base(input).map_err(|err| { - BlackBoxResolutionError::Failed(BlackBoxFunc::FixedBaseScalarMul, err.to_string()) - }) - } -} diff --git a/src/smart_contract.rs b/src/smart_contract.rs index aeb053a0..b1a028f1 100644 --- a/src/smart_contract.rs +++ b/src/smart_contract.rs @@ -1,76 +1,65 @@ +use super::proof_system::{serialize_circuit, write_to_file}; +use crate::{ + bb::{ContractCommand, WriteVkCommand}, + proof_system::read_bytes_from_file, + BackendError, Barretenberg, +}; use acvm::{acir::circuit::Circuit, SmartContract}; - -use crate::{barretenberg::crs::CRS, BackendError, Barretenberg}; +use tempfile::tempdir; /// Embed the Solidity verifier file const ULTRA_VERIFIER_CONTRACT: &str = include_str!("contract.sol"); -#[cfg(feature = "native")] impl SmartContract for Barretenberg { type Error = BackendError; fn eth_contract_from_vk( &self, - common_reference_string: &[u8], - _circuit: &Circuit, - verification_key: &[u8], + _common_reference_string: &[u8], + circuit: &Circuit, + _verification_key: &[u8], ) -> Result { - use std::slice; - - let CRS { g2_data, .. } = common_reference_string.try_into()?; - - let mut contract_ptr: *mut u8 = std::ptr::null_mut(); - let p_contract_ptr = &mut contract_ptr as *mut *mut u8; - let verification_key = verification_key.to_vec(); - let sc_as_bytes; - let contract_size; - unsafe { - contract_size = barretenberg_sys::composer::get_solidity_verifier( - &g2_data, - &verification_key, - p_contract_ptr, - ); - sc_as_bytes = slice::from_raw_parts(contract_ptr, contract_size) - }; - - let verification_key_library: String = sc_as_bytes.iter().map(|b| *b as char).collect(); - Ok(format!( - "{verification_key_library}{ULTRA_VERIFIER_CONTRACT}" - )) - } -} - -#[cfg(not(feature = "native"))] -impl SmartContract for Barretenberg { - type Error = BackendError; - - fn eth_contract_from_vk( - &self, - common_reference_string: &[u8], - _circuit: &Circuit, - verification_key: &[u8], - ) -> Result { - let CRS { g2_data, .. } = common_reference_string.try_into()?; - - let g2_ptr = self.allocate(&g2_data)?; - let vk_ptr = self.allocate(verification_key)?; - - // The smart contract string is not actually written to this pointer. - // `contract_ptr_ptr` is a pointer to a pointer which holds the smart contract string. - let contract_ptr_ptr: usize = 0; - - let contract_size = self.call_multiple( - "acir_proofs_get_solidity_verifier", - vec![&g2_ptr, &vk_ptr, &contract_ptr_ptr.into()], - )?; - - // We then need to read the pointer at `contract_ptr_ptr` to get the smart contract's location - // and then slice memory again at `contract_ptr_ptr` to get the smart contract string. - let contract_ptr = self.get_pointer(contract_ptr_ptr); - - let sc_as_bytes = self.read_memory_variable_length(contract_ptr, contract_size.try_into()?); - - let verification_key_library: String = sc_as_bytes.iter().map(|b| *b as char).collect(); + let temp_directory = tempdir().expect("could not create a temporary directory"); + let temp_directory_path = temp_directory.path(); + let temp_dir_path = temp_directory_path.to_str().unwrap(); + + // Create a temporary file for the circuit + let circuit_path = temp_directory_path + .join("circuit") + .with_extension("bytecode"); + let serialized_circuit = serialize_circuit(circuit); + write_to_file(serialized_circuit.as_bytes(), &circuit_path); + + // Create the verification key and write it to the specified path + let vk_path = temp_directory_path.join("vk").to_str().unwrap().to_string(); + WriteVkCommand { + verbose: false, + path_to_crs: temp_dir_path.to_string(), + is_recursive: false, + path_to_bytecode: circuit_path.as_os_str().to_str().unwrap().to_string(), + path_to_vk_output: vk_path.clone(), + } + .run() + .expect("write vk command failed"); + + let path_to_contract = temp_directory_path + .join("contract") + .to_str() + .unwrap() + .to_string(); + ContractCommand { + verbose: false, + path_to_crs: temp_dir_path.to_string(), + path_to_vk: vk_path, + path_to_contract: path_to_contract.clone(), + } + .run() + .expect("contract command failed"); + + let verification_key_library_bytes = read_bytes_from_file(&path_to_contract).unwrap(); + let verification_key_library = String::from_utf8(verification_key_library_bytes).unwrap(); + + drop(temp_directory); Ok(format!( "{verification_key_library}{ULTRA_VERIFIER_CONTRACT}" )) @@ -79,52 +68,41 @@ impl SmartContract for Barretenberg { #[cfg(test)] mod tests { - use acvm::{acir::circuit::Circuit, SmartContract}; - use tokio::test; + use std::collections::BTreeSet; - use crate::BackendError; + use acvm::{ + acir::{ + circuit::{Circuit, Opcode, PublicInputs}, + native_types::{Expression, Witness}, + }, + SmartContract, + }; #[test] - async fn test_smart_contract() -> Result<(), BackendError> { - use crate::barretenberg::composer::Composer; - use crate::barretenberg_structures::{Constraint, ConstraintSystem}; + fn test_smart_contract() { use crate::Barretenberg; - use acvm::FieldElement; - - let constraint = Constraint { - a: 1, - b: 2, - c: 3, - qm: FieldElement::zero(), - ql: FieldElement::one(), - qr: FieldElement::one(), - qo: -FieldElement::one(), - qc: FieldElement::zero(), - }; - let constraint_system = ConstraintSystem::new() - .var_num(4) - .public_inputs(vec![1, 2]) - .constraints(vec![constraint]); + let expression = &(Witness(1) + Witness(2)) - &Expression::from(Witness(3)); + let constraint = Opcode::Arithmetic(expression); - let bb = Barretenberg::new(); - let crs = bb.get_crs(&constraint_system).await?; - - let proving_key = bb.compute_proving_key(&constraint_system)?; - let verification_key = bb.compute_verification_key(&crs, &proving_key)?; + let circuit = Circuit { + current_witness_index: 4, + opcodes: vec![constraint], + private_parameters: BTreeSet::from([Witness(1), Witness(2)]), + public_parameters: PublicInputs::default(), + return_values: PublicInputs::default(), + }; - let common_reference_string: Vec = crs.try_into()?; + let bb = Barretenberg; - let contract = bb.eth_contract_from_vk( - &common_reference_string, - &Circuit::default(), - &verification_key, - )?; + let common_reference_string = Vec::new(); + let verification_key = Vec::new(); + let contract = bb + .eth_contract_from_vk(&common_reference_string, &circuit, &verification_key) + .unwrap(); assert!(contract.contains("contract BaseUltraVerifier")); assert!(contract.contains("contract UltraVerifier")); assert!(contract.contains("library UltraVerificationKey")); - - Ok(()) } } diff --git a/src/witness.tr b/src/witness.tr new file mode 100644 index 00000000..e01c75d8 Binary files /dev/null and b/src/witness.tr differ