diff --git a/.circleci/config.yml b/.circleci/config.yml index 770bf274d3..8e8840ccac 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -276,7 +276,6 @@ jobs: - run: name: "Test" command: cond_spot_run_test_script ./scripts/bin-test.sh barretenberg-x86_64-linux-clang-assert - - *save_logs benchmark-aggregator: docker: @@ -314,6 +313,17 @@ jobs: name: "Test" command: cond_spot_run_tests bb.js + acir-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build and test" + command: cond_spot_run_build acir-tests 32 + # These machines cost a fortune (10x other machines). # There is a branch coming for github actions that will build mac stuff on releases. # I'll leave this here for now, just in case proves useful to be able to do CI mac builds on branches, @@ -450,6 +460,11 @@ workflows: requires: - bb-js <<: *defaults + - acir-tests: + requires: + - x86_64-linux-clang-assert + - bb-js + <<: *defaults #- circuits-wasm-linux-clang-builder-runner: *notmaster - circuits-x86_64-linux-clang-builder-runner: *notmaster #- circuits-wasm-tests: diff --git a/.gitignore b/.gitignore index 4bc42395e4..77989f790d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ node_modules ts/dest .tsbuildinfo .idea -cmake-build-debug +cmake-build-debug \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 0134c08493..cc597845c6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -113,10 +113,7 @@ "**/.pnp.*": true, "**/msgpack-c/**": true }, - "typescript.tsdk": "ts/.yarn/sdks/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, - "eslint.nodePath": "ts/.yarn/sdks", - "prettier.prettierPath": "ts/.yarn/sdks/prettier/index.js", "[cpp]": { // doesn't conflict with barratenberg.code-workspace settings. "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" diff --git a/acir_tests/.dockerignore b/acir_tests/.dockerignore new file mode 100644 index 0000000000..e0bcbb7295 --- /dev/null +++ b/acir_tests/.dockerignore @@ -0,0 +1,2 @@ +acir_tests +acir-to-bberg-circuit/target \ No newline at end of file diff --git a/acir_tests/.gitignore b/acir_tests/.gitignore new file mode 100644 index 0000000000..47b24c40c7 --- /dev/null +++ b/acir_tests/.gitignore @@ -0,0 +1 @@ +acir_tests \ No newline at end of file diff --git a/acir_tests/Dockerfile b/acir_tests/Dockerfile new file mode 100644 index 0000000000..9c8f64d447 --- /dev/null +++ b/acir_tests/Dockerfile @@ -0,0 +1,18 @@ +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/barretenberg-x86_64-linux-clang-assert +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/bb.js + +FROM rust:alpine as atbbc +RUN apk update && apk add musl-dev +WORKDIR /usr/src/barretenberg/acir_tests +COPY acir-to-bberg-circuit acir-to-bberg-circuit +RUN cd acir-to-bberg-circuit && cargo build --release + +FROM node:18-alpine +RUN apk update && apk add git bash curl +COPY --from=0 /usr/src/barretenberg/cpp/build /usr/src/barretenberg/cpp/build +COPY --from=1 /usr/src/barretenberg/ts /usr/src/barretenberg/ts +COPY --from=2 /usr/src/barretenberg/acir_tests/acir-to-bberg-circuit /usr/src/barretenberg/acir_tests/acir-to-bberg-circuit +WORKDIR /usr/src/barretenberg/acir_tests +COPY . . +RUN ./run_acir_tests.sh +RUN BB=../ts/dest/main.js ./run_acir_tests.sh \ No newline at end of file diff --git a/acir_tests/acir-to-bberg-circuit/.gitignore b/acir_tests/acir-to-bberg-circuit/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/acir_tests/acir-to-bberg-circuit/.gitignore @@ -0,0 +1 @@ +/target diff --git a/acir_tests/acir-to-bberg-circuit/Cargo.lock b/acir_tests/acir-to-bberg-circuit/Cargo.lock new file mode 100644 index 0000000000..2b176895f3 --- /dev/null +++ b/acir_tests/acir-to-bberg-circuit/Cargo.lock @@ -0,0 +1,1054 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "acir" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0f4d70cd78f13cc17b2b16953af71d1a4fd0aa923cc35e6741c1f810eccdad" +dependencies = [ + "acir_field 0.15.1", + "brillig_vm 0.15.1", + "flate2", + "rmp-serde", + "serde", + "thiserror", +] + +[[package]] +name = "acir" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed559b3e6e10a04b2a1af7a8b0f23d4bbaf4a87a6c8ac9946583f8945c53ce5" +dependencies = [ + "acir_field 0.16.0", + "brillig_vm 0.16.0", + "flate2", + "rmp-serde", + "serde", + "thiserror", +] + +[[package]] +name = "acir-to-bberg-circuit" +version = "0.1.0" +dependencies = [ + "acvm 0.16.0", + "base64", + "flate2", + "noirc_abi", + "serde", + "serde-big-array", + "serde_json", +] + +[[package]] +name = "acir_field" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74a1bdec0ba9ddb54d3337bb487a889dd212211a7daf6fe9fb175adf107eecdc" +dependencies = [ + "ark-bn254", + "ark-ff", + "cfg-if", + "hex", + "num-bigint", + "serde", +] + +[[package]] +name = "acir_field" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29adbffe34f7ae42e080833364f66ea0e933ca4aa3880e12444780538e1f6767" +dependencies = [ + "ark-bn254", + "ark-ff", + "cfg-if", + "hex", + "num-bigint", + "serde", +] + +[[package]] +name = "acvm" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e27004072f628c96c5666068c0d9efae134423331859b60923265a017a5920b" +dependencies = [ + "acir 0.15.1", + "acvm_stdlib 0.15.1", + "async-trait", + "blake2", + "indexmap 1.9.3", + "k256", + "num-bigint", + "num-traits", + "sha2", + "sha3", + "thiserror", +] + +[[package]] +name = "acvm" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4808764cc92ba018210ec2f276f6d90908263af33f9a8abea6ae4139ba49aa0" +dependencies = [ + "acir 0.16.0", + "acvm_stdlib 0.16.0", + "async-trait", + "blake2", + "indexmap 1.9.3", + "k256", + "num-bigint", + "num-traits", + "sha2", + "sha3", + "thiserror", +] + +[[package]] +name = "acvm_stdlib" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a16b18f0dc47de9c3f60eb320dda05b31355d7d4f76239f75852cc5a518db69e" +dependencies = [ + "acir 0.15.1", +] + +[[package]] +name = "acvm_stdlib" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b0fea96f9ddc8866782636f1317aa0ac958ab7bc628fa9620a4915cc667edc" +dependencies = [ + "acir 0.16.0", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "async-trait" +version = "0.1.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79fa67157abdfd688a259b6648808757db9347af834624f27ec646da976aee5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brillig_vm" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae057025d1898257631c65c63071209dc41093cf9c0d77cdaae976798fa18b93" +dependencies = [ + "acir_field 0.15.1", + "serde", +] + +[[package]] +name = "brillig_vm" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9400d1493af661cba05923a5b4a78e3aeaeb4210b321831fc0461b01203191e" +dependencies = [ + "acir_field 0.16.0", + "blake2", + "k256", + "serde", + "sha2", + "sha3", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6340df57935414636969091153f35f68d9f00bbc8fb4a9c6054706c213e6c6bc" + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + +[[package]] +name = "iter-extended" +version = "0.7.1" +source = "git+https://github.com/noir-lang/noir.git#e5773e47c212c7c8fa1a7d7456893b508cdb400c" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "noirc_abi" +version = "0.7.1" +source = "git+https://github.com/noir-lang/noir.git#e5773e47c212c7c8fa1a7d7456893b508cdb400c" +dependencies = [ + "acvm 0.15.1", + "iter-extended", + "serde", + "serde_json", + "thiserror", + "toml", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "paste" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "rmp" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.166" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8" +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_derive" +version = "1.0.166" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "serde_json" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "toml" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-ident" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] diff --git a/acir_tests/acir-to-bberg-circuit/Cargo.toml b/acir_tests/acir-to-bberg-circuit/Cargo.toml new file mode 100644 index 0000000000..4b7fc0638b --- /dev/null +++ b/acir_tests/acir-to-bberg-circuit/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "acir-to-bberg-circuit" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.136", features = ["derive"] } +serde_json = "1.0" +serde-big-array = "0.5.1" +flate2 = "1.0" +base64 = "0.13" + +acvm = { version = "0.16.0", features = ["bn254"] } +noirc_abi = { git = "https://github.com/noir-lang/noir.git" } diff --git a/acir_tests/acir-to-bberg-circuit/README.md b/acir_tests/acir-to-bberg-circuit/README.md new file mode 100644 index 0000000000..46ac73fcd8 --- /dev/null +++ b/acir_tests/acir-to-bberg-circuit/README.md @@ -0,0 +1,24 @@ +# ACIR to bb.js circuit + +Convert an ACIR circuit generated by Noir. + +How to use the repo: + +1. Install the binary using the command below +``` +cargo install --path=. +``` + +2. Then enter your Noir project directory + +3. Compile a circuit using nargo. +``` +nargo compile test +``` + +4. Then run the command below +``` +acir-to-bberg-circuit +``` + +The default path will be `./target/main.json`, and it will change the JSON file directly. It should be noted that it will also overwrite the proving key and verification key to be empty if exist in the original build artifact. \ No newline at end of file diff --git a/acir_tests/acir-to-bberg-circuit/src/barretenberg_structures.rs b/acir_tests/acir-to-bberg-circuit/src/barretenberg_structures.rs new file mode 100644 index 0000000000..cba6104934 --- /dev/null +++ b/acir_tests/acir-to-bberg-circuit/src/barretenberg_structures.rs @@ -0,0 +1,1302 @@ +use acvm::acir::circuit::opcodes::{BlackBoxFuncCall, FunctionInput, MemoryBlock}; +use acvm::acir::circuit::{Circuit, Opcode}; +use acvm::acir::native_types::Expression; +use acvm::FieldElement; +use serde::{Deserialize, Serialize}; +use serde_big_array::BigArray; + +#[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 struct ConstraintSystem { + var_num: u32, + public_inputs: Vec, + + logic_constraints: Vec, + range_constraints: Vec, + sha256_constraints: Vec, + schnorr_constraints: Vec, + ecdsa_secp256k1_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 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 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_len = self.ecdsa_secp256k1_constraints.len() as u32; + buffer.extend_from_slice(&ecdsa_len.to_be_bytes()); + for constraint in self.ecdsa_secp256k1_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 + } + + fn from_memory_block(b: &MemoryBlock, is_ram_block: bool) -> BlockConstraint { + let mut init = Vec::new(); + let mut trace = Vec::new(); + let len = b.len as usize; + for op in b.trace.iter().take(len) { + assert_eq!(op.operation, Expression::one()); + init.push(serialize_arithmetic_gates(&op.value)); + } + for op in b.trace.iter().skip(len) { + 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, + }; + trace.push(bb_op); + } + let is_ram = i8::from(is_ram_block); + BlockConstraint { + init, + trace, + is_ram, + } + } +} + +#[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 = String; + /// 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 mut 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 fixed_base_scalar_mul_constraints: Vec = Vec::new(); + let mut hash_to_field_constraints: Vec = Vec::new(); + let mut recursion_constraints: Vec = Vec::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(|| { + 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(|| { + 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, + } => { + // pub_key_x + let public_key_x = public_key_x.witness.witness_index() as i32; + // pub_key_y + let public_key_y = public_key_y.witness.witness_index() as i32; + // signature + 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(|| 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(|| 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(|| 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(|| 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::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(|| { + 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(|| { + 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::Block(_) => { + // Block is managed by ACVM + } + Opcode::RAM(block) => { + block_constraints.push(BlockConstraint::from_memory_block(block, true)) + } + Opcode::ROM(block) => { + block_constraints.push(BlockConstraint::from_memory_block(block, false)) + } + } + } + + // 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, + 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/acir_tests/acir-to-bberg-circuit/src/main.rs b/acir_tests/acir-to-bberg-circuit/src/main.rs new file mode 100644 index 0000000000..f85d7871ee --- /dev/null +++ b/acir_tests/acir-to-bberg-circuit/src/main.rs @@ -0,0 +1,81 @@ +use acvm::acir::circuit::Circuit; +use noirc_abi::Abi; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::{fs::File, io::Write, path::Path}; + +use flate2::write::GzEncoder; +use flate2::Compression; + +mod barretenberg_structures; +use barretenberg_structures::ConstraintSystem; + +pub fn main() { + let path_string = std::env::args() + .nth(1) + .unwrap_or("./target/main.json".to_owned()); + let circuit_path = Path::new(&path_string); + + let circuit_bytes = std::fs::read(&circuit_path).unwrap(); + + let mut program: PreprocessedProgram = + serde_json::from_slice(&circuit_bytes).expect("could not deserialize program"); + + program.proving_key = vec![]; + program.verification_key = vec![]; + + write_to_file(&serde_json::to_vec(&program).unwrap(), &circuit_path); +} + +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(), + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct PreprocessedProgram { + pub backend: String, + pub abi: Abi, + + #[serde( + serialize_with = "serialize_circuit", + deserialize_with = "deserialize_circuit" + )] + pub bytecode: Circuit, + + pub proving_key: Vec, + pub verification_key: Vec, +} + +fn serialize_circuit(circuit: &Circuit, s: S) -> Result +where + S: Serializer, +{ + let cs: ConstraintSystem = + ConstraintSystem::try_from(circuit).expect("should have no malformed bb funcs"); + let circuit_bytes = cs.to_bytes(); + + let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); + encoder.write_all(&circuit_bytes).unwrap(); + let compressed_bytes = encoder.finish().unwrap(); + + let b64_string = base64::encode(compressed_bytes); + s.serialize_str(&b64_string) +} + +fn deserialize_circuit<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let circuit_bytes = Vec::::deserialize(deserializer)?; + let circuit = Circuit::read(&*circuit_bytes).unwrap(); + Ok(circuit) +} diff --git a/acir_tests/run_acir_tests.sh b/acir_tests/run_acir_tests.sh new file mode 100755 index 0000000000..5614100704 --- /dev/null +++ b/acir_tests/run_acir_tests.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# Env var overrides: +# BB: to specify a different binary to test with (e.g. bb.js or bb.js-dev). +# VERBOSE: to enable logging for each test. + +set -e + +BB=$PWD/${BB:-../cpp/build/bin/bb} +ATBBC=$PWD/acir-to-bberg-circuit/target/release/acir-to-bberg-circuit +CRS_PATH=~/.bb-crs + +# Pull down the test vectors from the noir repo, if we don't have the folder already. +if [ ! -d acir_tests ]; then + rm -rf noir + # TODO: Merge this branch to master! It contains all precompiled test vectors and flat witness data. + git clone -b mv/witness-for-bbjs --filter=blob:none --no-checkout https://github.com/noir-lang/noir.git + cd noir + git sparse-checkout init --cone + git sparse-checkout set crates/nargo_cli/tests/test_data + git checkout + cd .. + mv noir/crates/nargo_cli/tests/test_data acir_tests + rm -rf noir +fi + +# Get the tool to convert acir to bb constraint buf, if we don't have it already. +if [ ! -f $ATBBC ]; then + cd acir-to-bberg-circuit + cargo build --release + cd .. +fi + +cd acir_tests + +# Remove excluded and expected-to-fail tests. +rm -rf bit_shifts_runtime comptime_fail poseidonsponge_x5_254 sha2_blocks sha2_byte diamond_deps_0 range_fail + +function test() { + echo -n "Testing $1... " + cd $1 + if [ ! -f target/translated ]; then + $ATBBC + touch target/translated + fi + set +e + if [ -n "$VERBOSE" ]; then + $BB prove_and_verify -v -c $CRS_PATH + else + $BB prove_and_verify -c $CRS_PATH > /dev/null 2>&1 + fi + result=$? + set -e + cd .. + + if [ $result -eq 0 ]; then + echo -e "\033[32mPASSED\033[0m" + else + echo -e "\033[31mFAILED\033[0m" + fi +} + +if [ -n "$1" ]; then + test $1 +else + for DIR in $(find -maxdepth 1 -type d -not -path '.'); do + test $DIR + done +fi diff --git a/bootstrap_docker.sh b/bootstrap_docker.sh new file mode 100755 index 0000000000..737f9d0756 --- /dev/null +++ b/bootstrap_docker.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# This script builds the projects listed in build_mainifest.sh. + +set -e + +COMMIT_HASH=$(git rev-parse HEAD) +source ./build-system/scripts/setup_env $COMMIT_HASH '' mainframe_$USER $(git rev-parse --show-toplevel) +build_local \ No newline at end of file diff --git a/build_manifest.json b/build_manifest.json index 88a4af592d..12d4522e12 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -39,5 +39,10 @@ "buildDir": "ts", "rebuildPatterns": ["^ts/"], "dependencies": ["barretenberg-wasm-linux-clang"] + }, + "acir-tests": { + "buildDir": "acir_tests", + "rebuildPatterns": ["^acir_tests/"], + "dependencies": ["bb.js", "barretenberg-wasm-linux-clang-assert"] } } diff --git a/build_manifest.sh b/build_manifest.sh new file mode 100755 index 0000000000..5768303cf8 --- /dev/null +++ b/build_manifest.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Source this file to define the PROJECTS variable, needed by build_local, used by bootstrap_docker.sh. +# +# PROJECT elements have structure PROJECT_DIR_NAME:WORKING_DIR:DOCKERFILE:REPO. +# PROJECT_DIR_NAME: Should reflect the projects directory name. +# WORKING_DIR: Everything within this directory is copied into the docker context (excluding paths in .dockerignore). +# DOCKERFILE: Defaults to Dockerfile. However some projects have multiple build Dockerfiles located in subdirs. +# REPO: Defaults to . The docker repository name, used to name the resulting docker image. +# +# This file tells bootstrap_docker.sh which and in which order to build projects for locally testing the docker builds. +# To check *most* of the build works as expected, we can just do the minimum to produce the e2e tests, and run them +# locally to check they work. Other projects can be *temporarily* uncommented to test their Dockerfiles, but don't +# commit them, so that the most important build path remains fast and simple. + +PROJECTS=( + cpp:cpp:./dockerfiles/Dockerfile.wasm-linux-clang:barretenberg-wasm-linux-clang + cpp:cpp:./dockerfiles/Dockerfile.x86_64-linux-clang-assert:barretenberg-x86_64-linux-clang-assert + ts:ts:./Dockerfile:bb.js + acir_tests:acir_tests:./Dockerfile:acir_tests +) diff --git a/cpp/.gitignore b/cpp/.gitignore index c6a6fba41b..9a5226b72f 100644 --- a/cpp/.gitignore +++ b/cpp/.gitignore @@ -8,3 +8,4 @@ CMakeUserPresets.json .vscode/settings.json # to be unignored when we agree on clang-tidy rules .clangd +acir_tests \ No newline at end of file diff --git a/cpp/src/barretenberg/bb/main.cpp b/cpp/src/barretenberg/bb/main.cpp index bb7ae1e94b..fe155a9c78 100644 --- a/cpp/src/barretenberg/bb/main.cpp +++ b/cpp/src/barretenberg/bb/main.cpp @@ -12,7 +12,7 @@ using namespace barretenberg; uint32_t MAX_CIRCUIT_SIZE = 1 << 19; -auto CRS_PATH = "./crs"; +std::string CRS_PATH = "./crs"; bool verbose = false; void init() @@ -38,7 +38,7 @@ acir_format::acir_format get_contraint_system(std::string const& json_path) return from_buffer(bytecode.data()); } -void proveAndVerify(const std::string& jsonPath, const std::string& witnessPath, bool recursive) +bool proveAndVerify(const std::string& jsonPath, const std::string& witnessPath, bool recursive) { auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose); auto constraint_system = get_contraint_system(jsonPath); @@ -46,6 +46,7 @@ void proveAndVerify(const std::string& jsonPath, const std::string& witnessPath, auto proof = acir_composer->create_proof(srs::get_crs_factory(), constraint_system, witness, recursive); auto verified = acir_composer->verify_proof(proof, recursive); info("verified: ", verified); + return verified; } void prove(const std::string& jsonPath, const std::string& witnessPath, bool recursive, const std::string& outputPath) @@ -152,11 +153,12 @@ int main(int argc, char* argv[]) std::string witness_path = getOption(args, "-w", "./target/witness.tr"); std::string proof_path = getOption(args, "-p", "./proofs/proof"); std::string vk_path = getOption(args, "-k", "./target/vk"); + CRS_PATH = getOption(args, "-c", "./crs"); bool recursive = flagPresent(args, "-r") || flagPresent(args, "--recursive"); init(); if (command == "prove_and_verify") { - proveAndVerify(json_path, witness_path, recursive); + return proveAndVerify(json_path, witness_path, recursive) ? 0 : 1; } else if (command == "prove") { std::string output_path = getOption(args, "-o", "./proofs/proof"); prove(json_path, witness_path, recursive, output_path); diff --git a/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp index d95467e44a..e43906fc4f 100644 --- a/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp +++ b/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -62,6 +62,7 @@ std::vector AcirComposer::create_proof( vinfo("building circuit..."); create_circuit_with_witness(builder_, constraint_system, witness); + vinfo("gates: ", builder_.get_total_circuit_size()); composer_ = [&]() { if (proving_key_) { diff --git a/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp b/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp index 641cc3f4a1..5fd3e06da1 100644 --- a/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp @@ -32,6 +32,7 @@ template class UltraCircuitBuilder_ : public CircuitBuilderBase class UltraCircuitBuilder_ : public CircuitBuilderBasepublic_inputs.size(); - return std::max(minimum_circuit_size, num_filled_gates); + return std::max(minimum_circuit_size, num_filled_gates) + NUM_RESERVED_GATES; } /**x diff --git a/ts/Dockerfile b/ts/Dockerfile index c293870663..9a4877deea 100644 --- a/ts/Dockerfile +++ b/ts/Dockerfile @@ -1,5 +1,5 @@ #FROM aztecprotocol/barretenberg-wasm-linux-clang:latest -FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/barretenberg-wasm-linux-clang AS builder +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/barretenberg-wasm-linux-clang FROM node:18-alpine COPY --from=0 /usr/src/barretenberg /usr/src/barretenberg diff --git a/ts/src/crs/node/index.ts b/ts/src/crs/node/index.ts index 47cb65b197..afcbb37e8e 100644 --- a/ts/src/crs/node/index.ts +++ b/ts/src/crs/node/index.ts @@ -12,8 +12,8 @@ const debug = createDebug('bb.js:crs'); export class Crs { constructor(public readonly numPoints: number, public readonly path: string) {} - static async new(numPoints: number) { - const crs = new Crs(numPoints, './crs'); + static async new(numPoints: number, crsPath = './crs') { + const crs = new Crs(numPoints, crsPath); await crs.init(); return crs; } diff --git a/ts/src/examples/simple.test.ts b/ts/src/examples/simple.test.ts index 828b0cb4ea..a2ce26daf1 100644 --- a/ts/src/examples/simple.test.ts +++ b/ts/src/examples/simple.test.ts @@ -14,7 +14,7 @@ describe('simple', () => { const crs = await Crs.new(2 ** 19 + 1); await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); - }, 20000); + }, 30000); afterAll(async () => { await api.destroy(); diff --git a/ts/src/main.ts b/ts/src/main.ts index 4038f69a01..40f64a68dc 100755 --- a/ts/src/main.ts +++ b/ts/src/main.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env -S node --no-warnings +#!/usr/bin/env node import { Crs, BarretenbergApiAsync, newBarretenbergApiAsync, RawBuffer } from './index.js'; import createDebug from 'debug'; import { readFileSync, writeFileSync } from 'fs'; @@ -49,7 +49,7 @@ async function computeCircuitSize(jsonPath: string, api: BarretenbergApiAsync) { return { exact, total, subgroup }; } -async function init(jsonPath: string) { +async function init(jsonPath: string, crsPath: string) { const api = await newBarretenbergApiAsync(); const circuitSize = await getGates(jsonPath, api); @@ -62,7 +62,7 @@ async function init(jsonPath: string) { debug(`subgroup size: ${subgroupSize}`); debug('loading crs...'); // Plus 1 needed! (Move +1 into Crs?) - const crs = await Crs.new(subgroupSize + 1); + const crs = await Crs.new(subgroupSize + 1, crsPath); // Important to init slab allocator as first thing, to ensure maximum memory efficiency. await api.commonInitSlabAllocator(subgroupSize); @@ -88,8 +88,8 @@ async function initLite() { return { api, acirComposer }; } -export async function proveAndVerify(jsonPath: string, witnessPath: string, isRecursive: boolean) { - const { api, acirComposer } = await init(jsonPath); +export async function proveAndVerify(jsonPath: string, witnessPath: string, crsPath: string, isRecursive: boolean) { + const { api, acirComposer } = await init(jsonPath, crsPath); try { debug(`creating proof...`); const bytecode = getBytecode(jsonPath); @@ -105,8 +105,14 @@ export async function proveAndVerify(jsonPath: string, witnessPath: string, isRe } } -export async function prove(jsonPath: string, witnessPath: string, isRecursive: boolean, outputPath: string) { - const { api, acirComposer } = await init(jsonPath); +export async function prove( + jsonPath: string, + witnessPath: string, + crsPath: string, + isRecursive: boolean, + outputPath: string, +) { + const { api, acirComposer } = await init(jsonPath, crsPath); try { debug(`creating proof...`); const bytecode = getBytecode(jsonPath); @@ -158,8 +164,8 @@ export async function contract(outputPath: string, vkPath: string) { } } -export async function writeVk(jsonPath: string, outputPath: string) { - const { api, acirComposer } = await init(jsonPath); +export async function writeVk(jsonPath: string, crsPath: string, outputPath: string) { + const { api, acirComposer } = await init(jsonPath, crsPath); try { debug('initing proving key...'); const bytecode = getBytecode(jsonPath); @@ -214,6 +220,7 @@ export async function vkAsFields(vkPath: string, vkeyOutputPath: string) { const program = new Command(); program.option('-v, --verbose', 'enable verbose logging', false); +program.option('-c, --crs-path ', 'set crs path', './crs'); function handleGlobalOptions() { if (program.opts().verbose) { @@ -227,9 +234,9 @@ program .option('-j, --json-path ', 'Specify the JSON path', './target/main.json') .option('-w, --witness-path ', 'Specify the witness path', './target/witness.tr') .option('-r, --recursive', 'prove and verify using recursive prover and verifier', false) - .action(async ({ jsonPath, witnessPath, recursive }) => { + .action(async ({ jsonPath, witnessPath, recursive, crsPath }) => { handleGlobalOptions(); - const result = await proveAndVerify(jsonPath, witnessPath, recursive); + const result = await proveAndVerify(jsonPath, witnessPath, crsPath, recursive); process.exit(result ? 0 : 1); }); @@ -240,9 +247,9 @@ program .option('-w, --witness-path ', 'Specify the witness path', './target/witness.tr') .option('-r, --recursive', 'prove using recursive prover', false) .option('-o, --output-path ', 'Specify the proof output path', './proofs/proof') - .action(async ({ jsonPath, witnessPath, recursive, outputPath }) => { + .action(async ({ jsonPath, witnessPath, recursive, outputPath, crsPath }) => { handleGlobalOptions(); - await prove(jsonPath, witnessPath, recursive, outputPath); + await prove(jsonPath, witnessPath, crsPath, recursive, outputPath); }); program @@ -282,9 +289,9 @@ program .description('Output verification key.') .option('-j, --json-path ', 'Specify the JSON path', './target/main.json') .requiredOption('-o, --output-path ', 'Specify the path to write the key') - .action(async ({ jsonPath, outputPath }) => { + .action(async ({ jsonPath, outputPath, crsPath }) => { handleGlobalOptions(); - await writeVk(jsonPath, outputPath); + await writeVk(jsonPath, crsPath, outputPath); }); program