diff --git a/.gitignore b/.gitignore index 351f5e16a7f..a3d669b44e3 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ result *.pk *.vk **/Verifier.toml +**/target diff --git a/.vscode/settings.json b/.vscode/settings.json index 78bfd88c35e..61d9452c95c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,4 +13,12 @@ } } }, + "rust-analyzer.cargo.features": [ + "bb_js" + ], + "rust-analyzer.cargo.noDefaultFeatures": true, + "rust-analyzer.check.features": [ + "bb_js" + ], + "rust-analyzer.check.noDefaultFeatures": true, } diff --git a/Cargo.lock b/Cargo.lock index d0bc0e7c491..7fba19b65bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,8 +5,7 @@ version = 3 [[package]] name = "acir" version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e011212158b81a8bbe6c9f7f4713fbf8b9542076a49ba916769436833b5d738f" +source = "git+https://github.com/noir-lang/acvm.git?rev=71e50173957794e9f2547c12e217b913e648244b#71e50173957794e9f2547c12e217b913e648244b" dependencies = [ "acir_field", "brillig_vm", @@ -19,8 +18,7 @@ dependencies = [ [[package]] name = "acir_field" version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08e3bbb98412bdcb65b7b688269cbc04db0710e25f3c32e99cf3923026ea3941" +source = "git+https://github.com/noir-lang/acvm.git?rev=71e50173957794e9f2547c12e217b913e648244b#71e50173957794e9f2547c12e217b913e648244b" dependencies = [ "ark-bn254", "ark-ff", @@ -33,8 +31,7 @@ dependencies = [ [[package]] name = "acvm" version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b5a910c6dcbea83195107368805911a02b2ed3453a1516e15fa2bc89e4d1c2" +source = "git+https://github.com/noir-lang/acvm.git?rev=71e50173957794e9f2547c12e217b913e648244b#71e50173957794e9f2547c12e217b913e648244b" dependencies = [ "acir", "acvm_stdlib", @@ -52,8 +49,7 @@ dependencies = [ [[package]] name = "acvm-backend-barretenberg" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e792521ba83064509ce23763d11a9134773f90c325d7a418cb650b139f02afa6" +source = "git+https://github.com/noir-lang/acvm-backend-barretenberg.git?rev=8f56a684a5cad3d88371f91f8a8a01d1b7bf40a4#8f56a684a5cad3d88371f91f8a8a01d1b7bf40a4" dependencies = [ "acvm", "barretenberg-sys", @@ -72,8 +68,7 @@ dependencies = [ [[package]] name = "acvm_stdlib" version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe3837b19bcbf11cecd61083e088a49c2d7911abedd0585cc62bf77bb47a384" +source = "git+https://github.com/noir-lang/acvm.git?rev=71e50173957794e9f2547c12e217b913e648244b#71e50173957794e9f2547c12e217b913e648244b" dependencies = [ "acir", ] @@ -126,9 +121,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -379,7 +374,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide 0.6.2", - "object 0.30.3", + "object 0.30.4", "rustc-demangle", ] @@ -403,6 +398,12 @@ 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 = "base64" version = "0.21.2" @@ -485,8 +486,7 @@ dependencies = [ [[package]] name = "brillig_vm" version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b690fd9d34b8653edf286c03982433e80e6e3878a8fc6289b680997c3e80925b" +source = "git+https://github.com/noir-lang/acvm.git?rev=71e50173957794e9f2547c12e217b913e648244b#71e50173957794e9f2547c12e217b913e648244b" dependencies = [ "acir_field", "num-bigint", @@ -620,9 +620,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" +checksum = "401a4694d2bf92537b6867d94de48c4842089645fdcdf6c71865b175d836e9c2" dependencies = [ "clap_builder", "clap_derive", @@ -631,9 +631,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980" dependencies = [ "anstream", "anstyle", @@ -644,9 +644,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", "proc-macro2", @@ -1189,9 +1189,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1268,9 +1268,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -1534,9 +1534,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1683,9 +1683,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libloading" @@ -1833,10 +1833,14 @@ name = "nargo" version = "0.6.0" dependencies = [ "acvm", + "acvm-backend-barretenberg", + "base64 0.13.1", + "flate2", "noirc_abi", "noirc_driver", "rustc_version", "serde", + "serde-big-array", "thiserror", "toml", ] @@ -1870,7 +1874,10 @@ dependencies = [ "thiserror", "tokio", "toml", + "tracing", + "tracing-subscriber", "url", + "which", ] [[package]] @@ -1982,6 +1989,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -2036,18 +2053,24 @@ dependencies = [ [[package]] name = "object" -version = "0.30.3" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.2" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owo-colors" @@ -2069,9 +2092,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project-lite" @@ -2357,11 +2380,11 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ - "aho-corasick 1.0.1", + "aho-corasick 1.0.2", "memchr", "regex-syntax", ] @@ -2414,7 +2437,7 @@ version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64", + "base64 0.21.2", "bytes", "encoding_rs", "futures-core", @@ -2612,7 +2635,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.2", ] [[package]] @@ -2977,9 +3000,9 @@ dependencies = [ [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" @@ -3027,15 +3050,16 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -3232,15 +3256,29 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ + "nu-ansi-term", "sharded-slab", + "smallvec", "thread_local", "tracing-core", + "tracing-log", ] [[package]] @@ -3296,9 +3334,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -3794,7 +3832,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets", ] [[package]] @@ -3810,37 +3848,13 @@ dependencies = [ "windows_x86_64_msvc 0.33.0", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -3849,21 +3863,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_gnullvm", "windows_aarch64_msvc 0.48.0", "windows_i686_gnu 0.48.0", "windows_i686_msvc 0.48.0", "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_gnullvm", "windows_x86_64_msvc 0.48.0", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" @@ -3876,12 +3884,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.0" @@ -3894,12 +3896,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.0" @@ -3912,12 +3908,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.0" @@ -3930,24 +3920,12 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" @@ -3960,12 +3938,6 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index e188f19dd89..fcea2450301 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,9 @@ noirc_errors = { path = "crates/noirc_errors" } noirc_evaluator = { path = "crates/noirc_evaluator" } noirc_frontend = { path = "crates/noirc_frontend" } noir_wasm = { path = "crates/wasm" } +# `base64` and `flate2` are only needed by bb.js +base64 = "0.13" +flate2 = "1.0" cfg-if = "1.0.0" clap = { version = "4.1.4", features = ["derive"] } @@ -50,3 +53,7 @@ toml = "0.7.2" url = "2.2.0" wasm-bindgen = { version = "0.2.83", features = ["serde-serialize"] } wasm-bindgen-test = "0.3.33" + +[patch.crates-io] +acvm = { git = "https://github.com/noir-lang/acvm.git", rev = "71e50173957794e9f2547c12e217b913e648244b" } +acvm-backend-barretenberg = { git = "https://github.com/noir-lang/acvm-backend-barretenberg.git", rev = "8f56a684a5cad3d88371f91f8a8a01d1b7bf40a4" } diff --git a/crates/nargo/Cargo.toml b/crates/nargo/Cargo.toml index 77c881835dc..5436c6c229e 100644 --- a/crates/nargo/Cargo.toml +++ b/crates/nargo/Cargo.toml @@ -17,3 +17,18 @@ noirc_driver.workspace = true toml.workspace = true serde.workspace = true thiserror.workspace = true +# These three dependencies below are only needed to maintain the correct serialization for bb.js +base64 = { workspace = true, optional = true } +flate2 = { workspace = true, optional = true } +serde-big-array = { version = "0.5.1", optional = true } +# Backend only needed by bb.js +acvm-backend-barretenberg = { optional = true, version = "0.3.0", default-features = false } + +[features] +default = [] +bb_js = [ + "dep:base64", + "dep:flate2", + "dep:serde-big-array", + "acvm-backend-barretenberg/native" +] diff --git a/crates/nargo/src/artifacts/mod.rs b/crates/nargo/src/artifacts/mod.rs index 400254bfb0d..01fe2acb044 100644 --- a/crates/nargo/src/artifacts/mod.rs +++ b/crates/nargo/src/artifacts/mod.rs @@ -10,7 +10,14 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub mod contract; pub mod program; +#[cfg(feature = "bb_js")] +use { + acvm_backend_barretenberg::ConstraintSystem, base64, flate2::read::GzDecoder, + flate2::write::GzEncoder, flate2::Compression, std::io::prelude::*, +}; + // TODO: move these down into ACVM. +#[cfg(not(feature = "bb_js"))] fn serialize_circuit(circuit: &Circuit, s: S) -> Result where S: Serializer, @@ -21,6 +28,7 @@ where circuit_bytes.serialize(s) } +#[cfg(not(feature = "bb_js"))] fn deserialize_circuit<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -29,3 +37,31 @@ where let circuit = Circuit::read(&*circuit_bytes).unwrap(); Ok(circuit) } + +#[cfg(feature = "bb_js")] +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) +} + +#[cfg(feature = "bb_js")] +fn deserialize_circuit<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + // TODO(#1569): bb.js expects a serialized ConstraintSystem. For bb.js to fully interop with nargo, + // it will have to break out of the normal nargo deserialization process for a circuit. + // Handle this elsewhere when reading in a program for proving/verifying with bb.js + panic!("Not supported"); +} diff --git a/crates/nargo/src/ops/prove.rs b/crates/nargo/src/ops/prove.rs index e2c70739a35..16839a1b060 100644 --- a/crates/nargo/src/ops/prove.rs +++ b/crates/nargo/src/ops/prove.rs @@ -8,5 +8,6 @@ pub fn prove_execution( solved_witness: WitnessMap, proving_key: &[u8], ) -> Result, B::Error> { - backend.prove_with_pk(common_reference_string, circuit, solved_witness, proving_key) + // TODO(#1569): update from not just accepting `false` once we get nargo to interop with dynamic backend + backend.prove_with_pk(common_reference_string, circuit, solved_witness, proving_key, false) } diff --git a/crates/nargo/src/ops/verify.rs b/crates/nargo/src/ops/verify.rs index 1d2d3bbbd6f..4cc6c9ce34b 100644 --- a/crates/nargo/src/ops/verify.rs +++ b/crates/nargo/src/ops/verify.rs @@ -9,5 +9,13 @@ pub fn verify_proof( public_inputs: WitnessMap, verification_key: &[u8], ) -> Result { - backend.verify_with_vk(common_reference_string, proof, public_inputs, circuit, verification_key) + // TODO(#1569): update from not just accepting `false` once we get nargo to interop with dynamic backend + backend.verify_with_vk( + common_reference_string, + proof, + public_inputs, + circuit, + verification_key, + false, + ) } diff --git a/crates/nargo_cli/Cargo.toml b/crates/nargo_cli/Cargo.toml index 4d4cdc75159..b9af40a6d6c 100644 --- a/crates/nargo_cli/Cargo.toml +++ b/crates/nargo_cli/Cargo.toml @@ -19,7 +19,7 @@ toml.workspace = true [dependencies] cfg-if.workspace = true -clap.workspace = true +clap = { workspace = true, features = ["env"]} dirs.workspace = true url.workspace = true iter-extended.workspace = true @@ -36,10 +36,14 @@ hex = "0.4.2" serde_json = "1.0" termcolor = "1.1.2" color-eyre = "0.6.2" -tokio = "1.0" +tokio = { version = "1.0.0", features = ["rt"] } +tracing = "0.1" +tracing-subscriber = "0.3" # Backends -acvm-backend-barretenberg = { version = "0.3.0", default-features = false } +acvm-backend-barretenberg = { optional = true, version = "0.3.0", default-features = false } +which = "4.4.0" + [dev-dependencies] tempdir = "0.3.7" @@ -52,3 +56,5 @@ default = ["plonk_bn254"] # The plonk backend can only use bn254, so we do not specify the field plonk_bn254 = ["acvm-backend-barretenberg/native"] plonk_bn254_wasm = ["acvm-backend-barretenberg/wasm"] +bb_js = ["nargo/bb_js"] + diff --git a/crates/nargo_cli/src/backends.rs b/crates/nargo_cli/src/backends.rs index bbec5c99006..0c3f7ee57c7 100644 --- a/crates/nargo_cli/src/backends.rs +++ b/crates/nargo_cli/src/backends.rs @@ -1,9 +1,211 @@ +#[cfg(any(feature = "plonk_bn254", feature = "plonk_bn254_wasm"))] pub(crate) use acvm_backend_barretenberg::Barretenberg as ConcreteBackend; -#[cfg(not(any(feature = "plonk_bn254", feature = "plonk_bn254_wasm")))] +#[cfg(not(any(feature = "plonk_bn254", feature = "plonk_bn254_wasm", feature = "bb_js")))] compile_error!("please specify a backend to compile with"); #[cfg(all(feature = "plonk_bn254", feature = "plonk_bn254_wasm"))] compile_error!( "feature \"plonk_bn254\" and feature \"plonk_bn254_wasm\" cannot be enabled at the same time" ); + +// TODO(#1569): The bb.js impls in this file currently fulfill the interface to enable compiling nargo, but +// removing all `todo!()` statements inside this file requires full communication between nargo and bb.js +#[cfg(feature = "bb_js")] +use acvm::{ + acir::circuit::opcodes::BlackBoxFuncCall, Backend, CommonReferenceString, + PartialWitnessGenerator, ProofSystemCompiler, SmartContract, +}; + +#[cfg(feature = "bb_js")] +#[derive(Debug, Clone, Copy, Default)] +pub(crate) struct ConcreteBackend; + +#[cfg(feature = "bb_js")] +#[derive(Debug, Clone, Copy, Default)] +pub(crate) struct Errors; + +#[cfg(feature = "bb_js")] +impl std::fmt::Display for Errors { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!("Errors") + } +} + +#[cfg(feature = "bb_js")] +impl std::error::Error for Errors { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } + + fn description(&self) -> &str { + "description() is deprecated; use Display" + } + + fn cause(&self) -> Option<&dyn std::error::Error> { + self.source() + } +} + +#[cfg(feature = "bb_js")] +impl Backend for ConcreteBackend {} + +#[cfg(feature = "bb_js")] +impl CommonReferenceString for ConcreteBackend { + type Error = Errors; + + fn generate_common_reference_string<'life0, 'life1, 'async_trait>( + &'life0 self, + circuit: &'life1 acvm::acir::circuit::Circuit, + ) -> core::pin::Pin< + Box, Self::Error>> + 'async_trait>, + > + where + 'life0: 'async_trait, + 'life1: 'async_trait, + Self: 'async_trait, + { + todo!() + } + + fn update_common_reference_string<'life0, 'life1, 'async_trait>( + &'life0 self, + common_reference_string: Vec, + circuit: &'life1 acvm::acir::circuit::Circuit, + ) -> core::pin::Pin< + Box, Self::Error>> + 'async_trait>, + > + where + 'life0: 'async_trait, + 'life1: 'async_trait, + Self: 'async_trait, + { + todo!() + } +} + +#[cfg(feature = "bb_js")] +impl PartialWitnessGenerator for ConcreteBackend { + fn schnorr_verify( + &self, + initial_witness: &mut acvm::acir::native_types::WitnessMap, + public_key_x: &acvm::acir::circuit::opcodes::FunctionInput, + public_key_y: &acvm::acir::circuit::opcodes::FunctionInput, + signature: &[acvm::acir::circuit::opcodes::FunctionInput], + message: &[acvm::acir::circuit::opcodes::FunctionInput], + output: &acvm::acir::native_types::Witness, + ) -> Result { + todo!() + } + + fn pedersen( + &self, + initial_witness: &mut acvm::acir::native_types::WitnessMap, + inputs: &[acvm::acir::circuit::opcodes::FunctionInput], + domain_separator: u32, + outputs: &[acvm::acir::native_types::Witness], + ) -> Result { + todo!() + } + + fn fixed_base_scalar_mul( + &self, + initial_witness: &mut acvm::acir::native_types::WitnessMap, + input: &acvm::acir::circuit::opcodes::FunctionInput, + outputs: &[acvm::acir::native_types::Witness], + ) -> Result { + todo!() + } +} + +#[cfg(feature = "bb_js")] +impl ProofSystemCompiler for ConcreteBackend { + type Error = Errors; + + fn np_language(&self) -> acvm::Language { + acvm::Language::PLONKCSat { width: 3 } + } + + fn get_exact_circuit_size( + &self, + _circuit: &acvm::acir::circuit::Circuit, + ) -> Result { + todo!() + } + + fn supports_opcode(&self, opcode: &acvm::acir::circuit::Opcode) -> bool { + match opcode { + acvm::acir::circuit::Opcode::BlackBoxFuncCall(black_box_func_call) => { + // TODO(#1569): bb.js does not currently support ACVM simulation with a backend + // ACVM simulation with bb.js is necessary to support these opcodes + match black_box_func_call { + BlackBoxFuncCall::SchnorrVerify { .. } + | BlackBoxFuncCall::Pedersen { .. } + | BlackBoxFuncCall::FixedBaseScalarMul { .. } => false, + _ => true, + } + } + _ => true, + } + } + + fn proof_as_fields( + &self, + proof: &[u8], + public_inputs: acvm::acir::native_types::WitnessMap, + ) -> Result, Self::Error> { + todo!() + } + + fn vk_as_fields( + &self, + common_reference_string: &[u8], + verification_key: &[u8], + ) -> Result<(Vec, acvm::FieldElement), Self::Error> { + todo!() + } + + fn preprocess( + &self, + common_reference_string: &[u8], + circuit: &acvm::acir::circuit::Circuit, + ) -> Result<(Vec, Vec), Self::Error> { + todo!() + } + + fn prove_with_pk( + &self, + common_reference_string: &[u8], + circuit: &acvm::acir::circuit::Circuit, + witness_values: acvm::acir::native_types::WitnessMap, + proving_key: &[u8], + is_recursive: bool, + ) -> Result, Self::Error> { + todo!() + } + + fn verify_with_vk( + &self, + common_reference_string: &[u8], + proof: &[u8], + public_inputs: acvm::acir::native_types::WitnessMap, + circuit: &acvm::acir::circuit::Circuit, + verification_key: &[u8], + is_recursive: bool, + ) -> Result { + todo!() + } +} + +#[cfg(feature = "bb_js")] +impl SmartContract for ConcreteBackend { + type Error = Errors; + + fn eth_contract_from_vk( + &self, + common_reference_string: &[u8], + verification_key: &[u8], + ) -> Result { + todo!() + } +} diff --git a/crates/nargo_cli/src/cli/compile_cmd.rs b/crates/nargo_cli/src/cli/compile_cmd.rs index d2b5532cf24..13893b2ffdb 100644 --- a/crates/nargo_cli/src/cli/compile_cmd.rs +++ b/crates/nargo_cli/src/cli/compile_cmd.rs @@ -20,6 +20,9 @@ use super::fs::{ }; use super::NargoConfig; +#[cfg(feature = "bb_js")] +use nargo::artifacts::program::PreprocessedProgram; + // TODO(#1388): pull this from backend. const BACKEND_IDENTIFIER: &str = "acvm-backend-barretenberg"; @@ -37,6 +40,7 @@ pub(crate) struct CompileCommand { compile_options: CompileOptions, } +#[cfg(not(feature = "bb_js"))] pub(crate) fn run( backend: &B, args: CompileCommand, @@ -100,6 +104,26 @@ pub(crate) fn run( Ok(()) } +#[cfg(feature = "bb_js")] +pub(crate) fn run( + backend: &B, + args: CompileCommand, + config: NargoConfig, +) -> Result<(), CliError> { + let circuit_dir = config.program_dir.join(TARGET_DIR); + + let program = compile_circuit(backend, &config.program_dir, &args.compile_options)?; + let preprocessed_program = PreprocessedProgram { + backend: String::from("dummy-backend-bb.js"), + abi: program.abi, + bytecode: program.circuit, + proving_key: vec![], + verification_key: vec![], + }; + save_program_to_file(&preprocessed_program, &args.circuit_name, circuit_dir); + Ok(()) +} + pub(super) fn setup_driver( backend: &B, program_dir: &Path, diff --git a/crates/nargo_cli/src/cli/fs/witness.rs b/crates/nargo_cli/src/cli/fs/witness.rs index 3b2ca2aab9f..78a1e4649e2 100644 --- a/crates/nargo_cli/src/cli/fs/witness.rs +++ b/crates/nargo_cli/src/cli/fs/witness.rs @@ -6,14 +6,17 @@ use super::{create_named_dir, write_to_file}; use crate::{constants::WITNESS_EXT, errors::FilesystemError}; pub(crate) fn save_witness_to_dir>( - witness: WitnessMap, + witnesses: WitnessMap, witness_name: &str, witness_dir: P, ) -> Result { create_named_dir(witness_dir.as_ref(), "witness"); let witness_path = witness_dir.as_ref().join(witness_name).with_extension(WITNESS_EXT); - let buf: Vec = witness.try_into()?; + let mut buf = Vec::new(); + for (_, value) in witnesses { + buf.extend_from_slice(&value.to_be_bytes()); + } write_to_file(buf.as_slice(), &witness_path); diff --git a/crates/nargo_cli/src/cli/mod.rs b/crates/nargo_cli/src/cli/mod.rs index 9c1c7b7c2cc..cb470a8e441 100644 --- a/crates/nargo_cli/src/cli/mod.rs +++ b/crates/nargo_cli/src/cli/mod.rs @@ -27,7 +27,7 @@ static VERSION_STRING: &str = formatcp!("{} (git version hash: {}, is dirty: {})", CARGO_PKG_VERSION, GIT_HASH, IS_DIRTY); #[derive(Parser, Debug)] -#[command(name="nargo", author, version=VERSION_STRING, about, long_about = None)] +#[command(name="nargo", author, version=VERSION_STRING, about, long_about = None, trailing_var_arg = true, allow_hyphen_values = true)] struct NargoCli { #[command(subcommand)] command: NargoCommand, diff --git a/crates/nargo_cli/src/cli/prove_cmd.rs b/crates/nargo_cli/src/cli/prove_cmd.rs index 1238dbd9f8e..116affcd002 100644 --- a/crates/nargo_cli/src/cli/prove_cmd.rs +++ b/crates/nargo_cli/src/cli/prove_cmd.rs @@ -1,28 +1,9 @@ -use std::path::{Path, PathBuf}; - use acvm::Backend; use clap::Args; -use nargo::artifacts::program::PreprocessedProgram; -use nargo::ops::{preprocess_program, prove_execution, verify_proof}; -use noirc_abi::input_parser::Format; -use noirc_driver::CompileOptions; use super::NargoConfig; -use super::{ - compile_cmd::compile_circuit, - fs::{ - common_reference_string::{ - read_cached_common_reference_string, update_common_reference_string, - write_cached_common_reference_string, - }, - inputs::{read_inputs_from_file, write_inputs_to_file}, - program::read_program_from_file, - proof::save_proof_to_dir, - }, -}; use crate::{ - cli::execute_cmd::execute_program, - constants::{PROOFS_DIR, PROVER_INPUT_FILE, TARGET_DIR, VERIFIER_INPUT_FILE}, + // constants::{PROOFS_DIR, PROVER_INPUT_FILE, TARGET_DIR, VERIFIER_INPUT_FILE}, errors::CliError, }; @@ -39,8 +20,19 @@ pub(crate) struct ProveCommand { #[arg(short, long)] verify: bool, - #[clap(flatten)] - compile_options: CompileOptions, + // #[clap(flatten)] + // compile_options: CompileOptions, + + /// Argument or environment variable to specify path to backend executable, default `$USER/.nargo/bin/bb.js` + #[arg(long, env)] + backend_executable: Option, + + #[arg(long, env)] + recursive: Option, + + // Thise option should allow for -- --args to pass to backend + #[clap(last=true)] + raw_pass_through: Option>, } pub(crate) fn run( @@ -48,108 +40,46 @@ pub(crate) fn run( args: ProveCommand, config: NargoConfig, ) -> Result<(), CliError> { - let proof_dir = config.program_dir.join(PROOFS_DIR); - - let circuit_build_path = args - .circuit_name - .map(|circuit_name| config.program_dir.join(TARGET_DIR).join(circuit_name)); - - prove_with_path( - backend, - args.proof_name, - config.program_dir, - proof_dir, - circuit_build_path, - args.verify, - &args.compile_options, - )?; - - Ok(()) -} - -pub(crate) fn prove_with_path>( - backend: &B, - proof_name: Option, - program_dir: P, - proof_dir: P, - circuit_build_path: Option, - check_proof: bool, - compile_options: &CompileOptions, -) -> Result, CliError> { - let common_reference_string = read_cached_common_reference_string(); - - let (common_reference_string, preprocessed_program) = match circuit_build_path { - Some(circuit_build_path) => { - let program = read_program_from_file(circuit_build_path)?; - let common_reference_string = update_common_reference_string( - backend, - &common_reference_string, - &program.bytecode, - ) - .map_err(CliError::CommonReferenceStringError)?; - (common_reference_string, program) - } - None => { - let program = compile_circuit(backend, program_dir.as_ref(), compile_options)?; - let common_reference_string = - update_common_reference_string(backend, &common_reference_string, &program.circuit) - .map_err(CliError::CommonReferenceStringError)?; - let program = preprocess_program(backend, &common_reference_string, program) - .map_err(CliError::ProofSystemCompilerError)?; - (common_reference_string, program) + use tracing::{debug}; + use std::process::{Command, Stdio}; + use std::io::{BufRead, BufReader}; + use which::which; + + let backend_executable_path = if let Some(backend_executable) = args.backend_executable { + debug!("Backend path specified as argument or environment variable `{}`", backend_executable); + backend_executable + } else { + match which("bb.js") { + Ok(path) => path.to_string_lossy().to_string(), + Err(_) => { + let home_dir = dirs::home_dir().unwrap().join(".nargo").join("backends").join("bb.js"); + debug!("bb.js not found on path, choosing default `{}`", home_dir.to_string_lossy()); + home_dir.to_string_lossy().to_string() + }, } }; - write_cached_common_reference_string(&common_reference_string); - - let PreprocessedProgram { abi, bytecode, proving_key, verification_key, .. } = - preprocessed_program; - - // Parse the initial witness values from Prover.toml - let (inputs_map, _) = - read_inputs_from_file(&program_dir, PROVER_INPUT_FILE, Format::Toml, &abi)?; - - let solved_witness = execute_program(backend, bytecode.clone(), &abi, &inputs_map)?; - - // Write public inputs into Verifier.toml - let public_abi = abi.public_abi(); - let (public_inputs, return_value) = public_abi.decode(&solved_witness)?; - - write_inputs_to_file( - &public_inputs, - &return_value, - &program_dir, - VERIFIER_INPUT_FILE, - Format::Toml, - )?; - - let proof = - prove_execution(backend, &common_reference_string, &bytecode, solved_witness, &proving_key) - .map_err(CliError::ProofSystemCompilerError)?; - - if check_proof { - let public_inputs = public_abi.encode(&public_inputs, return_value)?; - let valid_proof = verify_proof( - backend, - &common_reference_string, - &bytecode, - &proof, - public_inputs, - &verification_key, - ) - .map_err(CliError::ProofSystemCompilerError)?; - - if !valid_proof { - return Err(CliError::InvalidProof("".into())); - } - } - - let proof_path = if let Some(proof_name) = proof_name { - Some(save_proof_to_dir(&proof, &proof_name, proof_dir)?) - } else { - println!("{}", hex::encode(&proof)); - None - }; - - Ok(proof_path) + let mut raw_pass_through= args.raw_pass_through.unwrap(); + let mut backend_args = vec!["prove".to_string()]; + backend_args.append(&mut raw_pass_through); + + debug!("About to spawn new command `{} {}`", backend_executable_path, backend_args.join(" ")); + let mut backend = Command::new(backend_executable_path.to_owned()) + .args(backend_args) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn().expect(format!("Failed to execute backend with `{}`, specify with `--backend-executable` argument", backend_executable_path).as_str()); + + let stderr = backend.stderr.take().expect("no stderr"); + BufReader::new(stderr) + .lines() + .for_each(|line| debug!("{}", line.unwrap_or_default().to_string())); + + let stdout = backend.stdout.take().expect("no stdout"); + BufReader::new(stdout) + .lines() + .for_each(|line| debug!("{}", line.unwrap_or_default().to_string())); + + Ok(()) } + diff --git a/crates/nargo_cli/src/main.rs b/crates/nargo_cli/src/main.rs index a73785c64c6..fdb779b1dd7 100644 --- a/crates/nargo_cli/src/main.rs +++ b/crates/nargo_cli/src/main.rs @@ -4,6 +4,8 @@ use color_eyre::{config::HookBuilder, eyre}; use nargo_cli::cli::start_cli; fn main() -> eyre::Result<()> { + tracing_subscriber::fmt::init(); + // Register a panic hook to display more readable panic messages to end-users let (panic_hook, _) = HookBuilder::default() .display_env_section(false) diff --git a/crates/nargo_cli/tests/codegen-verifier.rs b/crates/nargo_cli/tests/codegen-verifier.rs index 3e4dc1dc745..9414f3a270e 100644 --- a/crates/nargo_cli/tests/codegen-verifier.rs +++ b/crates/nargo_cli/tests/codegen-verifier.rs @@ -1,33 +1,37 @@ //! This integration test aims to check that the `nargo codegen-verifier` will successfully create a //! file containing a verifier for a simple program. -use assert_cmd::prelude::*; -use predicates::prelude::*; -use std::process::Command; - -use assert_fs::prelude::{PathAssert, PathChild}; - -#[test] -fn simple_verifier_codegen() { - let test_dir = assert_fs::TempDir::new().unwrap(); - std::env::set_current_dir(&test_dir).unwrap(); - - // Create trivial program - let project_name = "hello_world"; - let project_dir = test_dir.child(project_name); - - let mut cmd = Command::cargo_bin("nargo").unwrap(); - cmd.arg("new").arg(project_name); - cmd.assert().success(); - - std::env::set_current_dir(&project_dir).unwrap(); - - // Run `nargo codegen-verifier` - let mut cmd = Command::cargo_bin("nargo").unwrap(); - cmd.arg("codegen-verifier"); - cmd.assert() - .success() - .stdout(predicate::str::contains("Contract successfully created and located at")); - - project_dir.child("contract").child("plonk_vk.sol").assert(predicate::path::is_file()); +#[cfg(not(feature = "bb_js"))] +#[cfg(test)] +mod tests { + #[test] + fn simple_verifier_codegen() { + use assert_cmd::prelude::*; + use predicates::prelude::*; + use std::process::Command; + + use assert_fs::prelude::{PathAssert, PathChild}; + + let test_dir = assert_fs::TempDir::new().unwrap(); + std::env::set_current_dir(&test_dir).unwrap(); + + // Create trivial program + let project_name = "hello_world"; + let project_dir = test_dir.child(project_name); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("new").arg(project_name); + cmd.assert().success(); + + std::env::set_current_dir(&project_dir).unwrap(); + + // Run `nargo codegen-verifier` + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("codegen-verifier"); + cmd.assert() + .success() + .stdout(predicate::str::contains("Contract successfully created and located at")); + + project_dir.child("contract").child("plonk_vk.sol").assert(predicate::path::is_file()); + } } diff --git a/crates/nargo_cli/tests/hello_world.rs b/crates/nargo_cli/tests/hello_world.rs index 121f09f0ece..5ad5b7a6f72 100644 --- a/crates/nargo_cli/tests/hello_world.rs +++ b/crates/nargo_cli/tests/hello_world.rs @@ -2,55 +2,60 @@ //! It then follows the steps published at https://noir-lang.org/getting_started/hello_world.html //! Any modifications to the commands run here MUST be documented in the noir-lang book. -use assert_cmd::prelude::*; -use predicates::prelude::*; -use std::process::Command; - -use assert_fs::prelude::{FileWriteStr, PathAssert, PathChild}; - -#[test] -fn hello_world_example() { - let test_dir = assert_fs::TempDir::new().unwrap(); - std::env::set_current_dir(&test_dir).unwrap(); - - let project_name = "hello_world"; - let project_dir = test_dir.child(project_name); - - // `nargo new hello_world` - let mut cmd = Command::cargo_bin("nargo").unwrap(); - cmd.arg("new").arg(project_name); - cmd.assert().success().stdout(predicate::str::contains("Project successfully created!")); - - project_dir.child("src").assert(predicate::path::is_dir()); - project_dir.child("Nargo.toml").assert(predicate::path::is_file()); - - std::env::set_current_dir(&project_dir).unwrap(); - - // `nargo check` - let mut cmd = Command::cargo_bin("nargo").unwrap(); - cmd.arg("check"); - cmd.assert() - .success() - .stdout(predicate::str::contains("Constraint system successfully built!")); - - project_dir.child("Prover.toml").assert(predicate::path::is_file()); - project_dir.child("Verifier.toml").assert(predicate::path::is_file()); - - // `nargo prove p` - let proof_name = "p"; - project_dir.child("Prover.toml").write_str("x = 1\ny = 2").unwrap(); - - let mut cmd = Command::cargo_bin("nargo").unwrap(); - cmd.arg("prove").arg(proof_name); - cmd.assert().success(); - - project_dir - .child("proofs") - .child(format!("{proof_name}.proof")) - .assert(predicate::path::is_file()); - - // `nargo verify p` - let mut cmd = Command::cargo_bin("nargo").unwrap(); - cmd.arg("verify").arg(proof_name); - cmd.assert().success(); +#[cfg(not(feature = "bb_js"))] +#[cfg(test)] +mod tests { + use assert_cmd::prelude::*; + use predicates::prelude::*; + use std::process::Command; + + use assert_fs::prelude::{FileWriteStr, PathAssert, PathChild}; + + #[test] + + fn hello_world_example() { + let test_dir = assert_fs::TempDir::new().unwrap(); + std::env::set_current_dir(&test_dir).unwrap(); + + let project_name = "hello_world"; + let project_dir = test_dir.child(project_name); + + // `nargo new hello_world` + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("new").arg(project_name); + cmd.assert().success().stdout(predicate::str::contains("Project successfully created!")); + + project_dir.child("src").assert(predicate::path::is_dir()); + project_dir.child("Nargo.toml").assert(predicate::path::is_file()); + + std::env::set_current_dir(&project_dir).unwrap(); + + // `nargo check` + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("check"); + cmd.assert() + .success() + .stdout(predicate::str::contains("Constraint system successfully built!")); + + project_dir.child("Prover.toml").assert(predicate::path::is_file()); + project_dir.child("Verifier.toml").assert(predicate::path::is_file()); + + // `nargo prove p` + let proof_name = "p"; + project_dir.child("Prover.toml").write_str("x = 1\ny = 2").unwrap(); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("prove").arg(proof_name); + cmd.assert().success(); + + project_dir + .child("proofs") + .child(format!("{proof_name}.proof")) + .assert(predicate::path::is_file()); + + // `nargo verify p` + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("verify").arg(proof_name); + cmd.assert().success(); + } } diff --git a/crates/nargo_cli/tests/prove_and_verify.rs b/crates/nargo_cli/tests/prove_and_verify.rs index 0af60b2759b..d965c731d8f 100644 --- a/crates/nargo_cli/tests/prove_and_verify.rs +++ b/crates/nargo_cli/tests/prove_and_verify.rs @@ -1,4 +1,5 @@ #[allow(unused_imports)] +#[cfg(not(feature = "bb_js"))] #[cfg(test)] mod tests { // Some of these imports are consumed by the injected tests diff --git a/crates/nargo_cli/tests/test_data/pedersen_check/Prover.toml b/crates/nargo_cli/tests/test_data/pedersen_check/Prover.toml index 2fb3b1e1abf..c1884545c62 100644 --- a/crates/nargo_cli/tests/test_data/pedersen_check/Prover.toml +++ b/crates/nargo_cli/tests/test_data/pedersen_check/Prover.toml @@ -3,4 +3,4 @@ y = "1" salt = "42" out_x = "0x0c5e1ddecd49de44ed5e5798d3f6fb7c71fe3d37f5bee8664cf88a445b5ba0af" -out_y = "0x230294a041e26fe80b827c2ef5cb8784642bbaa83842da2714d62b1f3c4f9752" \ No newline at end of file +out_y = "0x230294a041e26fe80b827c2ef5cb8784642bbaa83842da2714d62b1f3c4f9752" diff --git a/crates/nargo_cli/tests/test_data/simple_shield/src/main.nr b/crates/nargo_cli/tests/test_data/simple_shield/src/main.nr index 18fccd862b5..409eed0694d 100644 --- a/crates/nargo_cli/tests/test_data/simple_shield/src/main.nr +++ b/crates/nargo_cli/tests/test_data/simple_shield/src/main.nr @@ -21,7 +21,7 @@ fn main( // Compute input note commitment let note_commitment = std::hash::pedersen([pubkey_x, pubkey_y]); - + // Compute input note nullifier let nullifier = std::hash::pedersen([note_commitment[0], index, priv_key]); diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs index 02179b17bca..ffa5878f2ad 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs @@ -95,6 +95,11 @@ pub(crate) fn evaluate( | BlackBoxFunc::HashToField128Security => { prepare_outputs(&mut acir_gen.memory, instruction_id, 1, ctx, evaluator) } + // There are some low level functions that have variable outputs and should not have a set output count + // in Noir + BlackBoxFunc::RecursiveAggregation => { + prepare_outputs_no_count(&mut acir_gen.memory, instruction_id, ctx, evaluator) + } _ => panic!("Unsupported low level function {:?}", op), }; let func_call = match op { @@ -151,6 +156,31 @@ pub(crate) fn evaluate( inputs: resolve_array(&args[0], acir_gen, ctx, evaluator), output: outputs[0], }, + BlackBoxFunc::RecursiveAggregation => { + let has_previous_aggregation = evaluator.opcodes.iter().any(|op| { + matches!( + op, + AcirOpcode::BlackBoxFuncCall( + BlackBoxFuncCall::RecursiveAggregation { .. } + ) + ) + }); + + let input_aggregation_object = if !has_previous_aggregation { + None + } else { + Some(resolve_array(&args[4], acir_gen, ctx, evaluator)) + }; + + BlackBoxFuncCall::RecursiveAggregation { + verification_key: resolve_array(&args[0], acir_gen, ctx, evaluator), + proof: resolve_array(&args[1], acir_gen, ctx, evaluator), + public_inputs: resolve_array(&args[2], acir_gen, ctx, evaluator), + key_hash: resolve_variable(&args[3], acir_gen, ctx, evaluator).unwrap(), + input_aggregation_object, + output_aggregation_object: outputs.to_vec(), + } + } _ => panic!("Unsupported low level function {:?}", op), }; evaluator.opcodes.push(AcirOpcode::BlackBoxFuncCall(func_call)); @@ -280,6 +310,25 @@ fn prepare_outputs( outputs } +fn prepare_outputs_no_count( + memory_map: &mut AcirMem, + pointer: NodeId, + ctx: &SsaContext, + evaluator: &mut Evaluator, +) -> Vec { + // Create fresh variables that will link to the output + let l_obj = ctx.try_get_node(pointer).unwrap(); + if let node::ObjectType::ArrayPointer(a) = l_obj.get_type() { + let mem_array = &ctx.mem[a]; + let output_nb = mem_array.len; + let outputs = vecmap(0..output_nb, |_| evaluator.add_witness_to_cs()); + memory_map.map_array(a, &outputs, ctx); + outputs + } else { + vec![evaluator.add_witness_to_cs()] + } +} + fn evaluate_println( var_cache: &mut InternalVarCache, memory_map: &mut AcirMem, diff --git a/crates/noirc_evaluator/src/ssa/builtin.rs b/crates/noirc_evaluator/src/ssa/builtin.rs index 6ef55f76b5f..7cda3ad7290 100644 --- a/crates/noirc_evaluator/src/ssa/builtin.rs +++ b/crates/noirc_evaluator/src/ssa/builtin.rs @@ -76,7 +76,8 @@ impl Opcode { | BlackBoxFunc::Keccak256 | BlackBoxFunc::Blake2s | BlackBoxFunc::Pedersen - | BlackBoxFunc::FixedBaseScalarMul => BigUint::zero(), + | BlackBoxFunc::FixedBaseScalarMul + | BlackBoxFunc::RecursiveAggregation => BigUint::zero(), // Verify returns zero or one BlackBoxFunc::SchnorrVerify | BlackBoxFunc::EcdsaSecp256k1 => BigUint::one(), BlackBoxFunc::HashToField128Security => ObjectType::native_field().max_size(), @@ -107,6 +108,10 @@ impl Opcode { } BlackBoxFunc::Pedersen => (2, ObjectType::native_field()), BlackBoxFunc::FixedBaseScalarMul => (2, ObjectType::native_field()), + BlackBoxFunc::RecursiveAggregation => { + let a = super::mem::Memory::deref(ctx, args[4]).unwrap(); + (ctx.mem[a].len, ctx.mem[a].element_type) + } BlackBoxFunc::RANGE | BlackBoxFunc::AND | BlackBoxFunc::XOR => { unreachable!("ICE: these opcodes do not have Noir builtin functions") } diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index 640fff829d1..5b7963b5f06 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -207,6 +207,10 @@ impl GeneratedAcir { let var_message_size = inputs.pop().expect("ICE: Missing message_size arg"); BlackBoxFuncCall::Keccak256VariableLength { inputs, var_message_size, outputs } } + // TODO(#1570): Generate ACIR for recursive aggregation + BlackBoxFunc::RecursiveAggregation => { + panic!("ICE: Cannot generate ACIR for recursive aggregation") + } }; self.opcodes.push(AcirOpcode::BlackBoxFuncCall(black_box_func_call)); @@ -635,6 +639,12 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // Inputs for fixed based scalar multiplication // is just a scalar BlackBoxFunc::FixedBaseScalarMul => Some(1), + // TODO(#1570): Generate ACIR for recursive aggregation + // RecursiveAggregation has variable inputs and we could return `None` here, + // but as it is not fully implemented we panic for now + BlackBoxFunc::RecursiveAggregation => { + panic!("ICE: Cannot generate ACIR for recursive aggregation") + } } } @@ -659,6 +669,10 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> u32 { // Output of fixed based scalar mul over the embedded curve // will be 2 field elements representing the point. BlackBoxFunc::FixedBaseScalarMul => 2, + // TODO(#1570): Generate ACIR for recursive aggregation + BlackBoxFunc::RecursiveAggregation => { + panic!("ICE: Cannot generate ACIR for recursive aggregation") + } } } diff --git a/flake.lock b/flake.lock index 6bfc9462b60..658be7fedca 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ ] }, "locked": { - "lastModified": 1685544246, - "narHash": "sha256-OECUSjN/pqJgS2TjOHwv02qH4NkHKk3BghD3XbEHUKw=", + "lastModified": 1685740878, + "narHash": "sha256-sJYVipq1EthnjSxVIZnZF15wy9LDMHNPfIJKRHyZrws=", "owner": "AztecProtocol", "repo": "barretenberg", - "rev": "aebfe95c547b0022a9baed3901e945bb386503be", + "rev": "8b8304cc7bfe132360d3b1d36d413bd4f13bc064", "type": "github" }, "original": { diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index f6a60a6dee7..b010eb31be3 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -15,3 +15,6 @@ mod compat; #[builtin(println)] fn println(_input : T) {} + +#[foreign(recursive_aggregation)] +fn verify_proof(_verification_key : [Field], _proof : [Field], _public_inputs : [Field], _key_hash : Field, _input_aggregation_object : [Field]) -> [Field] {}