From 8f9053b021949bce3c76312d6ae70b11548dc2ba Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 8 May 2024 11:13:11 +0000 Subject: [PATCH 1/4] feat(aztec-nr): add enqueue functions to AvmCallInterface (https://github.com/AztecProtocol/aztec-packages/pull/6264) --- .aztec-sync-commit | 2 +- .github/workflows/docs-pr.yml | 2 + .github/workflows/publish-nargo.yml | 2 +- .../workflows/test-rust-workspace-msrv.yml | 3 +- .github/workflows/test-rust-workspace.yml | 3 +- .release-please-manifest.json | 6 +- CHANGELOG.md | 116 +++ CONTRIBUTING.md | 2 +- Cargo.lock | 70 +- Cargo.toml | 32 +- acvm-repo/CHANGELOG.md | 240 ++++++ acvm-repo/acir/Cargo.toml | 2 +- acvm-repo/acir/README.md | 14 +- acvm-repo/acir/benches/serialization.rs | 1 + acvm-repo/acir/codegen/acir.cpp | 816 ++++++++++++------ .../acir/src/circuit/black_box_functions.rs | 12 +- acvm-repo/acir/src/circuit/brillig.rs | 10 - acvm-repo/acir/src/circuit/mod.rs | 83 +- acvm-repo/acir/src/circuit/opcodes.rs | 9 +- .../opcodes/black_box_function_call.rs | 33 +- acvm-repo/acir/src/lib.rs | 5 +- .../acir/tests/test_program_serialization.rs | 182 ++-- acvm-repo/acir_field/Cargo.toml | 2 +- acvm-repo/acvm/Cargo.toml | 2 +- acvm-repo/acvm/src/compiler/mod.rs | 6 +- acvm-repo/acvm/src/compiler/optimizers/mod.rs | 2 +- .../acvm/src/compiler/transformers/mod.rs | 14 - acvm-repo/acvm/src/pwg/arithmetic.rs | 4 + acvm-repo/acvm/src/pwg/blackbox/aes128.rs | 32 + ...se_scalar_mul.rs => embedded_curve_ops.rs} | 23 +- acvm-repo/acvm/src/pwg/blackbox/mod.rs | 16 +- acvm-repo/acvm/src/pwg/blackbox/range.rs | 1 + .../acvm/src/pwg/blackbox/signature/ecdsa.rs | 10 +- .../acvm/src/pwg/blackbox/signature/mod.rs | 34 - .../src/pwg/blackbox/signature/schnorr.rs | 6 +- acvm-repo/acvm/src/pwg/blackbox/utils.rs | 33 + acvm-repo/acvm/src/pwg/brillig.rs | 91 +- acvm-repo/acvm/src/pwg/directives/mod.rs | 1 + acvm-repo/acvm/src/pwg/mod.rs | 192 +++-- acvm-repo/acvm/tests/solver.rs | 336 ++++---- acvm-repo/acvm_js/Cargo.toml | 2 +- acvm-repo/acvm_js/build.sh | 2 +- acvm-repo/acvm_js/package.json | 2 +- acvm-repo/acvm_js/src/execute.rs | 68 +- acvm-repo/acvm_js/src/js_execution_error.rs | 20 +- .../test/browser/execute_circuit.test.ts | 4 +- .../acvm_js/test/node/execute_circuit.test.ts | 4 +- .../test/shared/complex_foreign_call.ts | 14 +- .../test/shared/fixed_base_scalar_mul.ts | 17 - acvm-repo/acvm_js/test/shared/foreign_call.ts | 8 +- acvm-repo/acvm_js/test/shared/memory_op.ts | 8 +- .../acvm_js/test/shared/multi_scalar_mul.ts | 21 + .../acvm_js/test/shared/nested_acir_call.ts | 14 +- acvm-repo/acvm_js/test/shared/pedersen.ts | 4 +- .../acvm_js/test/shared/schnorr_verify.ts | 4 +- acvm-repo/blackbox_solver/Cargo.toml | 3 +- acvm-repo/blackbox_solver/src/aes128.rs | 12 + .../src/curve_specific_solver.rs | 14 +- acvm-repo/blackbox_solver/src/lib.rs | 2 + acvm-repo/bn254_blackbox_solver/Cargo.toml | 2 +- .../src/embedded_curve_ops.rs | 241 ++++++ .../src/fixed_base_scalar_mul.rs | 165 ---- acvm-repo/bn254_blackbox_solver/src/lib.rs | 12 +- acvm-repo/brillig/Cargo.toml | 2 +- acvm-repo/brillig/src/black_box.rs | 17 +- acvm-repo/brillig/src/opcodes.rs | 9 +- acvm-repo/brillig_vm/Cargo.toml | 2 +- acvm-repo/brillig_vm/src/arithmetic.rs | 4 +- acvm-repo/brillig_vm/src/black_box.rs | 37 +- acvm-repo/brillig_vm/src/lib.rs | 10 +- .../src/transforms/contract_interface.rs | 1 + aztec_macros/src/transforms/functions.rs | 17 +- aztec_macros/src/utils/hir_utils.rs | 1 + .../{utils/arena => noirc_arena}/Cargo.toml | 2 +- .../{utils/arena => noirc_arena}/src/lib.rs | 8 + compiler/noirc_driver/src/abi_gen.rs | 12 +- compiler/noirc_driver/src/lib.rs | 4 +- compiler/noirc_errors/Cargo.toml | 2 +- .../brillig/brillig_gen/brillig_black_box.rs | 42 +- .../src/brillig/brillig_gen/brillig_block.rs | 75 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 10 +- .../src/brillig/brillig_ir/artifact.rs | 4 +- .../brillig_ir/codegen_control_flow.rs | 71 +- .../src/brillig/brillig_ir/debug_show.rs | 29 +- .../src/brillig/brillig_ir/entry_point.rs | 6 +- .../src/brillig/brillig_ir/instructions.rs | 14 +- compiler/noirc_evaluator/src/errors.rs | 20 +- compiler/noirc_evaluator/src/ssa.rs | 49 +- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 54 +- .../ssa/acir_gen/acir_ir/generated_acir.rs | 89 +- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 314 ++++--- .../src/ssa/function_builder/mod.rs | 26 +- compiler/noirc_evaluator/src/ssa/ir/dfg.rs | 23 +- .../noirc_evaluator/src/ssa/ir/function.rs | 34 +- .../noirc_evaluator/src/ssa/ir/instruction.rs | 208 +++-- .../src/ssa/ir/instruction/call.rs | 19 +- .../src/ssa/ir/instruction/constrain.rs | 2 +- .../noirc_evaluator/src/ssa/ir/post_order.rs | 2 +- .../noirc_evaluator/src/ssa/ir/printer.rs | 68 +- compiler/noirc_evaluator/src/ssa/ir/types.rs | 8 + .../src/ssa/opt/constant_folding.rs | 11 +- .../src/ssa/opt/defunctionalize.rs | 31 +- compiler/noirc_evaluator/src/ssa/opt/die.rs | 8 +- .../src/ssa/opt/flatten_cfg.rs | 95 +- .../ssa/opt/flatten_cfg/capacity_tracker.rs | 4 +- .../src/ssa/opt/flatten_cfg/value_merger.rs | 244 +++++- .../noirc_evaluator/src/ssa/opt/inlining.rs | 70 +- compiler/noirc_evaluator/src/ssa/opt/mod.rs | 1 + .../src/ssa/opt/remove_bit_shifts.rs | 4 +- .../src/ssa/opt/remove_enable_side_effects.rs | 1 + .../src/ssa/opt/remove_if_else.rs | 236 +++++ .../noirc_evaluator/src/ssa/opt/unrolling.rs | 13 +- .../src/ssa/ssa_gen/context.rs | 210 +---- .../noirc_evaluator/src/ssa/ssa_gen/mod.rs | 77 +- .../src/ssa/ssa_gen/program.rs | 9 +- compiler/noirc_frontend/Cargo.toml | 2 +- compiler/noirc_frontend/src/ast/expression.rs | 4 +- compiler/noirc_frontend/src/ast/function.rs | 1 + compiler/noirc_frontend/src/ast/statement.rs | 7 +- .../noirc_frontend/src/hir/comptime/errors.rs | 228 ++++- .../src/hir/comptime/hir_to_ast.rs | 2 +- .../src/hir/comptime/interpreter.rs | 47 +- .../noirc_frontend/src/hir/comptime/mod.rs | 2 + .../noirc_frontend/src/hir/comptime/scan.rs | 50 +- .../noirc_frontend/src/hir/comptime/tests.rs | 14 + .../noirc_frontend/src/hir/comptime/value.rs | 2 +- .../src/hir/def_collector/dc_crate.rs | 51 +- .../src/hir/def_collector/dc_mod.rs | 5 +- .../src/hir/def_collector/errors.rs | 38 +- .../noirc_frontend/src/hir/def_map/mod.rs | 2 +- .../src/hir/resolution/errors.rs | 122 ++- .../src/hir/resolution/import.rs | 4 +- .../src/hir/resolution/resolver.rs | 202 +++-- .../src/hir/resolution/traits.rs | 11 +- .../src/hir/type_check/errors.rs | 65 +- .../noirc_frontend/src/hir/type_check/expr.rs | 60 +- .../noirc_frontend/src/hir/type_check/mod.rs | 14 +- .../noirc_frontend/src/hir/type_check/stmt.rs | 4 +- .../noirc_frontend/src/hir_def/function.rs | 9 +- compiler/noirc_frontend/src/hir_def/stmt.rs | 1 + compiler/noirc_frontend/src/hir_def/types.rs | 35 +- compiler/noirc_frontend/src/lexer/errors.rs | 4 +- compiler/noirc_frontend/src/lexer/token.rs | 15 + compiler/noirc_frontend/src/lib.rs | 2 +- .../src/monomorphization/ast.rs | 69 +- .../src/monomorphization/mod.rs | 27 +- compiler/noirc_frontend/src/node_interner.rs | 19 +- compiler/noirc_frontend/src/parser/errors.rs | 10 +- compiler/noirc_frontend/src/parser/parser.rs | 70 +- .../src/parser/parser/function.rs | 51 +- .../src/parser/parser/test_helpers.rs | 8 +- .../src/parser/parser/traits.rs | 6 +- .../noirc_frontend/src/resolve_locations.rs | 2 +- compiler/noirc_frontend/src/tests.rs | 133 ++- compiler/noirc_printable_type/src/lib.rs | 19 +- compiler/wasm/package.json | 2 +- docs/docs/noir/concepts/ops.md | 4 +- .../noir/standard_library/black_box_fns.md | 3 +- .../standard_library/containers/boundedvec.md | 14 + .../cryptographic_primitives/ciphers.mdx | 28 + .../embedded_curve_ops.mdx | 77 ++ .../cryptographic_primitives/hashes.mdx | 5 +- docs/docs/noir/standard_library/traits.md | 9 + docs/docs/tutorials/noirjs_app.md | 2 +- docs/docusaurus.config.ts | 4 +- docs/package.json | 3 +- docs/src/components/Matomo/matomo.jsx | 133 +++ docs/src/css/custom.css | 28 + docs/src/pages/index.jsx | 3 +- docs/src/theme/Root.js | 22 + .../getting_started/01_tiny_noir_app.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../version-v0.22.0/tutorials/noirjs_app.md | 2 +- .../version-v0.23.0/tutorials/noirjs_app.md | 2 +- .../version-v0.24.0/tutorials/noirjs_app.md | 2 +- .../version-v0.25.0/tutorials/noirjs_app.md | 2 +- .../version-v0.26.0/tutorials/noirjs_app.md | 2 +- .../version-v0.27.0/tutorials/noirjs_app.md | 2 +- .../explainers/explainer-oracle.md | 57 ++ .../explainers/explainer-recursion.md | 176 ++++ .../getting_started/_category_.json | 5 + .../hello_noir/_category_.json | 5 + .../getting_started/hello_noir/index.md | 142 +++ .../hello_noir/project_breakdown.md | 199 +++++ .../installation/_category_.json | 6 + .../getting_started/installation/index.md | 48 ++ .../installation/other_install_methods.md | 102 +++ .../getting_started/tooling/noir_codegen.md | 113 +++ .../version-v0.28.0/how_to/_category_.json | 5 + .../how_to/debugger/_category_.json | 6 + .../debugger/debugging_with_the_repl.md | 164 ++++ .../how_to/debugger/debugging_with_vs_code.md | 68 ++ .../version-v0.28.0/how_to/how-to-oracles.md | 276 ++++++ .../how_to/how-to-recursion.md | 179 ++++ .../how_to/how-to-solidity-verifier.md | 231 +++++ .../version-v0.28.0/how_to/merkle-proof.mdx | 49 ++ .../how_to/using-devcontainers.mdx | 110 +++ docs/versioned_docs/version-v0.28.0/index.mdx | 67 ++ .../version-v0.28.0/migration_notes.md | 105 +++ .../noir/concepts/_category_.json | 6 + .../version-v0.28.0/noir/concepts/assert.md | 45 + .../version-v0.28.0/noir/concepts/comments.md | 33 + .../noir/concepts/control_flow.md | 77 ++ .../version-v0.28.0/noir/concepts/data_bus.md | 21 + .../noir/concepts/data_types/_category_.json | 5 + .../noir/concepts/data_types/arrays.md | 251 ++++++ .../noir/concepts/data_types/booleans.md | 31 + .../noir/concepts/data_types/fields.md | 192 +++++ .../concepts/data_types/function_types.md | 26 + .../noir/concepts/data_types/index.md | 110 +++ .../noir/concepts/data_types/integers.md | 155 ++++ .../noir/concepts/data_types/references.md | 23 + .../noir/concepts/data_types/slices.mdx | 195 +++++ .../noir/concepts/data_types/strings.md | 80 ++ .../noir/concepts/data_types/structs.md | 70 ++ .../noir/concepts/data_types/tuples.md | 48 ++ .../noir/concepts/distinct.md | 0 .../noir/concepts/functions.md | 226 +++++ .../version-v0.28.0/noir/concepts/generics.md | 106 +++ .../version-v0.28.0/noir/concepts/globals.md | 72 ++ .../version-v0.28.0/noir/concepts/lambdas.md | 81 ++ .../noir/concepts/mutability.md | 121 +++ .../version-v0.28.0/noir/concepts/ops.md | 98 +++ .../version-v0.28.0/noir/concepts/oracles.md | 31 + .../noir/concepts/shadowing.md | 44 + .../version-v0.28.0/noir/concepts/traits.md | 389 +++++++++ .../noir/concepts/unconstrained.md | 99 +++ .../modules_packages_crates/_category_.json | 6 + .../crates_and_packages.md | 43 + .../modules_packages_crates/dependencies.md | 124 +++ .../noir/modules_packages_crates/modules.md | 105 +++ .../modules_packages_crates/workspaces.md | 42 + .../noir/standard_library/_category_.json | 6 + .../noir/standard_library/bigint.md | 122 +++ .../noir/standard_library/black_box_fns.md | 31 + .../noir/standard_library/bn254.md | 46 + .../standard_library/containers/boundedvec.md | 326 +++++++ .../standard_library/containers/hashmap.md | 570 ++++++++++++ .../noir/standard_library/containers/index.md | 5 + .../noir/standard_library/containers/vec.mdx | 151 ++++ .../cryptographic_primitives/_category_.json | 5 + .../cryptographic_primitives/ec_primitives.md | 102 +++ .../ecdsa_sig_verification.mdx | 98 +++ .../cryptographic_primitives/eddsa.mdx | 37 + .../cryptographic_primitives/hashes.mdx | 250 ++++++ .../cryptographic_primitives/index.md | 14 + .../cryptographic_primitives/scalar.mdx | 9 +- .../cryptographic_primitives/schnorr.mdx | 64 ++ .../noir/standard_library/logging.md | 78 ++ .../noir/standard_library/merkle_trees.md | 58 ++ .../noir/standard_library/options.md | 101 +++ .../noir/standard_library/recursion.md | 88 ++ .../noir/standard_library/traits.md | 410 +++++++++ .../noir/standard_library/zeroed.md | 26 + .../NoirJS/backend_barretenberg/.nojekyll | 1 + .../classes/BarretenbergBackend.md | 160 ++++ .../classes/BarretenbergVerifier.md | 58 ++ .../NoirJS/backend_barretenberg/index.md | 59 ++ .../type-aliases/BackendOptions.md | 21 + .../backend_barretenberg/typedoc-sidebar.cjs | 4 + .../reference/NoirJS/noir_js/.nojekyll | 1 + .../reference/NoirJS/noir_js/classes/Noir.md | 132 +++ .../reference/NoirJS/noir_js/functions/and.md | 22 + .../NoirJS/noir_js/functions/blake2s256.md | 21 + .../functions/ecdsa_secp256k1_verify.md | 28 + .../functions/ecdsa_secp256r1_verify.md | 28 + .../NoirJS/noir_js/functions/keccak256.md | 21 + .../NoirJS/noir_js/functions/sha256.md | 21 + .../reference/NoirJS/noir_js/functions/xor.md | 22 + .../reference/NoirJS/noir_js/index.md | 54 ++ .../type-aliases/ForeignCallHandler.md | 24 + .../noir_js/type-aliases/ForeignCallInput.md | 9 + .../noir_js/type-aliases/ForeignCallOutput.md | 9 + .../NoirJS/noir_js/type-aliases/WitnessMap.md | 9 + .../NoirJS/noir_js/typedoc-sidebar.cjs | 4 + .../reference/NoirJS/noir_wasm/.nojekyll | 1 + .../NoirJS/noir_wasm/functions/compile.md | 51 ++ .../noir_wasm/functions/compile_contract.md | 51 ++ .../noir_wasm/functions/createFileManager.md | 21 + .../functions/inflateDebugSymbols.md | 21 + .../reference/NoirJS/noir_wasm/index.md | 49 ++ .../NoirJS/noir_wasm/typedoc-sidebar.cjs | 4 + .../version-v0.28.0/reference/_category_.json | 5 + .../reference/debugger/_category_.json | 6 + .../debugger/debugger_known_limitations.md | 59 ++ .../reference/debugger/debugger_repl.md | 360 ++++++++ .../reference/debugger/debugger_vscode.md | 82 ++ .../reference/nargo_commands.md | 381 ++++++++ .../version-v0.28.0/tooling/debugger.md | 27 + .../tooling/language_server.md | 43 + .../version-v0.28.0/tooling/testing.md | 62 ++ .../version-v0.28.0/tutorials/noirjs_app.md | 326 +++++++ .../explainers/explainer-oracle.md | 57 ++ .../explainers/explainer-recursion.md | 176 ++++ .../getting_started/_category_.json | 5 + .../hello_noir/_category_.json | 5 + .../getting_started/hello_noir/index.md | 142 +++ .../hello_noir/project_breakdown.md | 199 +++++ .../installation/_category_.json | 6 + .../getting_started/installation/index.md | 48 ++ .../installation/other_install_methods.md | 102 +++ .../getting_started/tooling/noir_codegen.md | 113 +++ .../version-v0.29.0/how_to/_category_.json | 5 + .../how_to/debugger/_category_.json | 6 + .../debugger/debugging_with_the_repl.md | 164 ++++ .../how_to/debugger/debugging_with_vs_code.md | 68 ++ .../version-v0.29.0/how_to/how-to-oracles.md | 276 ++++++ .../how_to/how-to-recursion.md | 179 ++++ .../how_to/how-to-solidity-verifier.md | 231 +++++ .../version-v0.29.0/how_to/merkle-proof.mdx | 49 ++ .../how_to/using-devcontainers.mdx | 110 +++ docs/versioned_docs/version-v0.29.0/index.mdx | 67 ++ .../version-v0.29.0/migration_notes.md | 105 +++ .../noir/concepts/_category_.json | 6 + .../version-v0.29.0/noir/concepts/assert.md | 45 + .../version-v0.29.0/noir/concepts/comments.md | 33 + .../noir/concepts/control_flow.md | 77 ++ .../version-v0.29.0/noir/concepts/data_bus.md | 21 + .../noir/concepts/data_types/_category_.json | 5 + .../noir/concepts/data_types/arrays.md | 251 ++++++ .../noir/concepts/data_types/booleans.md | 31 + .../noir/concepts/data_types/fields.md | 192 +++++ .../concepts/data_types/function_types.md | 26 + .../noir/concepts/data_types/index.md | 110 +++ .../noir/concepts/data_types/integers.md | 155 ++++ .../noir/concepts/data_types/references.md | 23 + .../noir/concepts/data_types/slices.mdx | 195 +++++ .../noir/concepts/data_types/strings.md | 80 ++ .../noir/concepts/data_types/structs.md | 70 ++ .../noir/concepts/data_types/tuples.md | 48 ++ .../noir/concepts/functions.md | 226 +++++ .../version-v0.29.0/noir/concepts/generics.md | 106 +++ .../version-v0.29.0/noir/concepts/globals.md | 72 ++ .../version-v0.29.0/noir/concepts/lambdas.md | 81 ++ .../noir/concepts/mutability.md | 121 +++ .../version-v0.29.0/noir/concepts/ops.md | 98 +++ .../version-v0.29.0/noir/concepts/oracles.md | 31 + .../noir/concepts/shadowing.md | 44 + .../version-v0.29.0/noir/concepts/traits.md | 389 +++++++++ .../noir/concepts/unconstrained.md | 99 +++ .../modules_packages_crates/_category_.json | 6 + .../crates_and_packages.md | 43 + .../modules_packages_crates/dependencies.md | 124 +++ .../noir/modules_packages_crates/modules.md | 105 +++ .../modules_packages_crates/workspaces.md | 42 + .../noir/standard_library/_category_.json | 6 + .../noir/standard_library/bigint.md | 122 +++ .../noir/standard_library/black_box_fns.md | 31 + .../noir/standard_library/bn254.md | 46 + .../standard_library/containers/boundedvec.md | 326 +++++++ .../standard_library/containers/hashmap.md | 570 ++++++++++++ .../noir/standard_library/containers/index.md | 5 + .../noir/standard_library/containers/vec.mdx | 151 ++++ .../cryptographic_primitives/_category_.json | 5 + .../cryptographic_primitives/ec_primitives.md | 102 +++ .../ecdsa_sig_verification.mdx | 98 +++ .../cryptographic_primitives/eddsa.mdx | 37 + .../cryptographic_primitives/hashes.mdx | 257 ++++++ .../cryptographic_primitives/index.md | 14 + .../cryptographic_primitives/scalar.mdx | 33 + .../cryptographic_primitives/schnorr.mdx | 64 ++ .../noir/standard_library/logging.md | 78 ++ .../noir/standard_library/merkle_trees.md | 58 ++ .../noir/standard_library/options.md | 101 +++ .../noir/standard_library/recursion.md | 88 ++ .../noir/standard_library/traits.md | 410 +++++++++ .../noir/standard_library/zeroed.md | 26 + .../NoirJS/backend_barretenberg/.nojekyll | 1 + .../classes/BarretenbergBackend.md | 160 ++++ .../classes/BarretenbergVerifier.md | 58 ++ .../NoirJS/backend_barretenberg/index.md | 59 ++ .../type-aliases/BackendOptions.md | 21 + .../backend_barretenberg/typedoc-sidebar.cjs | 4 + .../reference/NoirJS/noir_js/.nojekyll | 1 + .../reference/NoirJS/noir_js/classes/Noir.md | 132 +++ .../reference/NoirJS/noir_js/functions/and.md | 22 + .../NoirJS/noir_js/functions/blake2s256.md | 21 + .../functions/ecdsa_secp256k1_verify.md | 28 + .../functions/ecdsa_secp256r1_verify.md | 28 + .../NoirJS/noir_js/functions/keccak256.md | 21 + .../NoirJS/noir_js/functions/sha256.md | 21 + .../reference/NoirJS/noir_js/functions/xor.md | 22 + .../reference/NoirJS/noir_js/index.md | 54 ++ .../type-aliases/ForeignCallHandler.md | 24 + .../noir_js/type-aliases/ForeignCallInput.md | 9 + .../noir_js/type-aliases/ForeignCallOutput.md | 9 + .../NoirJS/noir_js/type-aliases/WitnessMap.md | 9 + .../NoirJS/noir_js/typedoc-sidebar.cjs | 4 + .../reference/NoirJS/noir_wasm/.nojekyll | 1 + .../NoirJS/noir_wasm/functions/compile.md | 51 ++ .../noir_wasm/functions/compile_contract.md | 51 ++ .../noir_wasm/functions/createFileManager.md | 21 + .../functions/inflateDebugSymbols.md | 21 + .../reference/NoirJS/noir_wasm/index.md | 49 ++ .../NoirJS/noir_wasm/typedoc-sidebar.cjs | 4 + .../version-v0.29.0/reference/_category_.json | 5 + .../reference/debugger/_category_.json | 6 + .../debugger/debugger_known_limitations.md | 59 ++ .../reference/debugger/debugger_repl.md | 360 ++++++++ .../reference/debugger/debugger_vscode.md | 82 ++ .../reference/nargo_commands.md | 381 ++++++++ .../version-v0.29.0/tooling/debugger.md | 27 + .../tooling/language_server.md | 43 + .../version-v0.29.0/tooling/testing.md | 62 ++ .../version-v0.29.0/tutorials/noirjs_app.md | 326 +++++++ .../version-v0.28.0-sidebars.json | 93 ++ .../version-v0.29.0-sidebars.json | 93 ++ flake.lock | 170 ---- noir_stdlib/src/aes128.nr | 5 + noir_stdlib/src/collections/bounded_vec.nr | 71 +- noir_stdlib/src/embedded_curve_ops.nr | 82 ++ noir_stdlib/src/grumpkin_scalar.nr | 21 - noir_stdlib/src/grumpkin_scalar_mul.nr | 7 - noir_stdlib/src/hash.nr | 1 + noir_stdlib/src/internal.nr | 12 - noir_stdlib/src/lib.nr | 6 +- noir_stdlib/src/ops.nr | 43 +- noir_stdlib/src/scalar_mul.nr | 45 - noir_stdlib/src/sha256.nr | 54 +- noir_stdlib/src/sha512.nr | 2 +- noir_stdlib/src/uint128.nr | 12 +- .../self_referential_struct/Nargo.toml | 7 + .../self_referential_struct/src/main.nr | 11 + .../src/main.nr | 8 +- .../comptime_mut_global/Nargo.toml | 7 + .../comptime_mut_global/src/main.nr | 30 + .../impl_from_where_impl/Nargo.toml | 7 + .../impl_from_where_impl/src/main.nr | 15 + .../intrinsic_die/src/main.nr | 4 +- .../aes128_encrypt/Nargo.toml | 7 + .../aes128_encrypt/Prover.toml | 4 + .../aes128_encrypt/src/main.nr | 44 + .../array_if_cond_simple/Nargo.toml | 7 + .../array_if_cond_simple/Prover.toml | 2 + .../array_if_cond_simple/src/main.nr | 8 + .../bit_shifts_comptime/src/main.nr | 2 +- .../bit_shifts_runtime/src/main.nr | 8 +- .../brillig_bit_shifts_runtime/src/main.nr | 12 +- .../Nargo.toml | 2 +- .../brillig_embedded_curve/Prover.toml | 3 + .../brillig_embedded_curve/src/main.nr | 28 + .../brillig_scalar_mul/Prover.toml | 7 - .../brillig_scalar_mul/src/main.nr | 32 - .../conditional_regression_547/Nargo.toml | 0 .../conditional_regression_547/Prover.toml | 0 .../conditional_regression_547/src/main.nr | 0 .../execution_success/debug_logs/src/main.nr | 13 + .../distinct_keyword/src/main.nr | 4 - .../Nargo.toml | 2 +- .../embedded_curve_ops/Prover.toml | 3 + .../embedded_curve_ops/src/main.nr | 24 + .../fold_complex_outputs/Nargo.toml | 7 + .../fold_complex_outputs/Prover.toml | 2 + .../fold_complex_outputs/src/main.nr | 72 ++ .../fold_distinct_return/Nargo.toml | 7 + .../fold_distinct_return/Prover.toml | 2 + .../fold_distinct_return/src/main.nr | 10 + .../fold_fibonacci/Nargo.toml | 7 + .../fold_fibonacci/Prover.toml | 1 + .../fold_fibonacci/src/main.nr | 12 + .../inline_never_basic/Nargo.toml | 7 + .../inline_never_basic/Prover.toml | 2 + .../inline_never_basic/src/main.nr | 8 + .../main_return/Nargo.toml | 0 .../main_return/Prover.toml | 0 .../main_return/src/main.nr | 0 .../nested_array_dynamic_simple/Nargo.toml | 7 + .../Prover.toml | 0 .../nested_array_dynamic_simple/src/main.nr | 9 + .../no_predicates_basic/Nargo.toml | 7 + .../no_predicates_basic/Prover.toml | 2 + .../no_predicates_basic/src/main.nr | 8 + .../Nargo.toml | 7 + .../Prover.toml | 2 + .../src/main.nr | 33 + .../operator_overloading/src/main.nr | 12 +- .../execution_success/regression/src/main.nr | 2 +- .../regression_3051/Nargo.toml | 7 + .../regression_3051/src/main.nr | 24 + .../regression_4383/Nargo.toml | 7 + .../regression_4383/src/main.nr | 3 + .../Nargo.toml | 2 +- .../regression_4709/Prover.toml | 2 + .../regression_4709/src/main.nr | 271 ++++++ .../Nargo.toml | 7 + .../Prover.toml | 18 + .../src/main.nr | 38 + .../execution_success/scalar_mul/Prover.toml | 7 - .../execution_success/scalar_mul/src/main.nr | 31 - .../execution_success/sha256/src/main.nr | 4 +- .../simple_array_param/Nargo.toml | 0 .../simple_array_param/Prover.toml | 0 .../simple_array_param/src/main.nr | 0 .../simple_shield/src/main.nr | 2 +- .../slice_coercion/src/main.nr | 8 + .../slice_init_with_complex_type/Nargo.toml | 7 + .../slice_init_with_complex_type}/Prover.toml | 0 .../slice_init_with_complex_type/src/main.nr | 17 + .../execution_success/u128/src/main.nr | 10 +- .../brillig_overflow_checks/Prover.toml | 0 .../comptime_globals/Nargo.toml | 7 + .../comptime_globals/src/main.nr | 21 + .../field_comparisons/Prover.toml | 0 .../ignored_oracle/Nargo.toml | 7 + .../ignored_oracle/src/main.nr | 23 + .../noir_test_success/mock_oracle/Prover.toml | 0 .../out_of_bounds_alignment/Prover.toml | 0 .../should_fail_with_matches/Prover.toml | 0 .../should_fail_with_matches/src/main.nr | 64 ++ test_programs/rebuild.sh | 13 +- .../mock_backend/src/info_cmd.rs | 2 +- tooling/debugger/ignored-tests.txt | 9 +- tooling/debugger/src/context.rs | 174 ++-- tooling/debugger/src/foreign_calls.rs | 16 +- tooling/debugger/src/repl.rs | 61 +- tooling/lsp/src/solver.rs | 8 +- tooling/nargo/src/artifacts/debug_vars.rs | 14 +- tooling/nargo/src/errors.rs | 57 +- tooling/nargo/src/ops/execute.rs | 65 +- tooling/nargo/src/ops/foreign_calls.rs | 144 +--- tooling/nargo/src/ops/mod.rs | 4 +- tooling/nargo/src/ops/test.rs | 21 +- tooling/nargo_cli/src/cli/execute_cmd.rs | 4 +- tooling/nargo_cli/src/cli/fmt_cmd.rs | 2 +- tooling/nargo_cli/src/cli/fs/inputs.rs | 1 + tooling/nargo_fmt/src/visitor/item.rs | 6 +- tooling/nargo_fmt/src/visitor/stmt.rs | 2 +- tooling/nargo_fmt/tests/expected/fn.nr | 2 +- .../tests/expected/impl_trait_fn_parameter.nr | 3 + tooling/nargo_fmt/tests/input/fn.nr | 2 +- .../tests/input/impl_trait_fn_parameter.nr | 3 + tooling/noir_codegen/package.json | 2 +- tooling/noir_js/package.json | 2 +- .../noir_js/scripts/compile_test_programs.sh | 2 + tooling/noir_js/src/index.ts | 1 + tooling/noir_js/src/program.ts | 9 +- tooling/noir_js/src/witness_generation.ts | 50 +- tooling/noir_js/test/node/e2e.test.ts | 23 + tooling/noir_js/test/node/execute.test.ts | 92 +- .../assert_msg_runtime/src/main.nr | 4 +- .../assert_raw_payload/Nargo.toml | 7 + .../assert_raw_payload/src/main.nr | 9 + .../fold_fibonacci/Nargo.toml | 7 + .../fold_fibonacci/src/main.nr | 12 + .../noir_js_backend_barretenberg/package.json | 4 +- .../test/public_input_deflattening.test.ts | 1 + tooling/noir_js_types/package.json | 2 +- tooling/noir_js_types/src/types.ts | 15 + tooling/noirc_abi/Cargo.toml | 1 + tooling/noirc_abi/src/input_parser/mod.rs | 1 + tooling/noirc_abi/src/lib.rs | 100 ++- tooling/noirc_abi_wasm/build.sh | 2 +- tooling/noirc_abi_wasm/package.json | 2 +- tooling/noirc_abi_wasm/src/lib.rs | 43 +- .../test/browser/decode_error.test.ts | 64 ++ .../test/node/decode_error.test.ts | 60 ++ .../noirc_abi_wasm/test/shared/abi_encode.ts | 1 + .../test/shared/array_as_field.ts | 1 + .../test/shared/decode_error.ts | 46 + .../test/shared/field_as_array.ts | 1 + tooling/noirc_abi_wasm/test/shared/structs.ts | 1 + .../test/shared/uint_overflow.ts | 1 + .../utils => utils}/iter-extended/Cargo.toml | 0 .../utils => utils}/iter-extended/src/lib.rs | 0 yarn.lock | 13 +- 569 files changed, 26953 insertions(+), 3125 deletions(-) create mode 100644 acvm-repo/acvm/src/pwg/blackbox/aes128.rs rename acvm-repo/acvm/src/pwg/blackbox/{fixed_base_scalar_mul.rs => embedded_curve_ops.rs} (60%) create mode 100644 acvm-repo/acvm/src/pwg/blackbox/utils.rs delete mode 100644 acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts create mode 100644 acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts create mode 100644 acvm-repo/blackbox_solver/src/aes128.rs create mode 100644 acvm-repo/bn254_blackbox_solver/src/embedded_curve_ops.rs delete mode 100644 acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs rename compiler/{utils/arena => noirc_arena}/Cargo.toml (86%) rename compiler/{utils/arena => noirc_arena}/src/lib.rs (94%) create mode 100644 compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs create mode 100644 docs/docs/noir/standard_library/cryptographic_primitives/ciphers.mdx create mode 100644 docs/docs/noir/standard_library/cryptographic_primitives/embedded_curve_ops.mdx create mode 100644 docs/src/components/Matomo/matomo.jsx create mode 100644 docs/src/theme/Root.js create mode 100644 docs/versioned_docs/version-v0.28.0/explainers/explainer-oracle.md create mode 100644 docs/versioned_docs/version-v0.28.0/explainers/explainer-recursion.md create mode 100644 docs/versioned_docs/version-v0.28.0/getting_started/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/index.md create mode 100644 docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/project_breakdown.md create mode 100644 docs/versioned_docs/version-v0.28.0/getting_started/installation/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/getting_started/installation/index.md create mode 100644 docs/versioned_docs/version-v0.28.0/getting_started/installation/other_install_methods.md create mode 100644 docs/versioned_docs/version-v0.28.0/getting_started/tooling/noir_codegen.md create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/debugger/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/debugger/debugging_with_the_repl.md create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/debugger/debugging_with_vs_code.md create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/how-to-oracles.md create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/how-to-recursion.md create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/how-to-solidity-verifier.md create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/merkle-proof.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/how_to/using-devcontainers.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/index.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/migration_notes.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/assert.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/comments.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/control_flow.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_bus.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/arrays.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/booleans.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/fields.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/function_types.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/index.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/integers.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/references.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/slices.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/strings.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/structs.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/tuples.md rename docs/{docs => versioned_docs/version-v0.28.0}/noir/concepts/distinct.md (100%) create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/functions.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/generics.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/globals.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/lambdas.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/mutability.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/ops.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/oracles.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/shadowing.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/traits.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/concepts/unconstrained.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/crates_and_packages.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/dependencies.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/modules.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/workspaces.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/bigint.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/black_box_fns.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/bn254.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/boundedvec.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/hashmap.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/index.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/vec.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/ec_primitives.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/eddsa.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/hashes.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/index.md rename docs/{docs => versioned_docs/version-v0.28.0}/noir/standard_library/cryptographic_primitives/scalar.mdx (64%) create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/schnorr.mdx create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/logging.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/merkle_trees.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/options.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/recursion.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/traits.md create mode 100644 docs/versioned_docs/version-v0.28.0/noir/standard_library/zeroed.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/.nojekyll create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/index.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/.nojekyll create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/classes/Noir.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/and.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/blake2s256.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/keccak256.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/sha256.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/xor.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/index.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/.nojekyll create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/compile.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/compile_contract.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/createFileManager.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/index.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs create mode 100644 docs/versioned_docs/version-v0.28.0/reference/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/reference/debugger/_category_.json create mode 100644 docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_known_limitations.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_repl.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_vscode.md create mode 100644 docs/versioned_docs/version-v0.28.0/reference/nargo_commands.md create mode 100644 docs/versioned_docs/version-v0.28.0/tooling/debugger.md create mode 100644 docs/versioned_docs/version-v0.28.0/tooling/language_server.md create mode 100644 docs/versioned_docs/version-v0.28.0/tooling/testing.md create mode 100644 docs/versioned_docs/version-v0.28.0/tutorials/noirjs_app.md create mode 100644 docs/versioned_docs/version-v0.29.0/explainers/explainer-oracle.md create mode 100644 docs/versioned_docs/version-v0.29.0/explainers/explainer-recursion.md create mode 100644 docs/versioned_docs/version-v0.29.0/getting_started/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/index.md create mode 100644 docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/project_breakdown.md create mode 100644 docs/versioned_docs/version-v0.29.0/getting_started/installation/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/getting_started/installation/index.md create mode 100644 docs/versioned_docs/version-v0.29.0/getting_started/installation/other_install_methods.md create mode 100644 docs/versioned_docs/version-v0.29.0/getting_started/tooling/noir_codegen.md create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/debugger/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/debugger/debugging_with_the_repl.md create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/debugger/debugging_with_vs_code.md create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/how-to-oracles.md create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/how-to-recursion.md create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/how-to-solidity-verifier.md create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/merkle-proof.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/how_to/using-devcontainers.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/index.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/migration_notes.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/assert.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/comments.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/control_flow.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_bus.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/arrays.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/booleans.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/fields.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/function_types.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/index.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/integers.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/references.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/slices.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/strings.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/structs.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/tuples.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/functions.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/generics.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/globals.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/lambdas.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/mutability.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/ops.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/oracles.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/shadowing.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/traits.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/concepts/unconstrained.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/crates_and_packages.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/dependencies.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/modules.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/workspaces.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/bigint.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/black_box_fns.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/bn254.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/boundedvec.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/hashmap.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/index.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/vec.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/ec_primitives.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/eddsa.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/hashes.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/index.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/scalar.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/schnorr.mdx create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/logging.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/merkle_trees.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/options.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/recursion.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/traits.md create mode 100644 docs/versioned_docs/version-v0.29.0/noir/standard_library/zeroed.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/.nojekyll create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/index.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/.nojekyll create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/classes/Noir.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/and.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/blake2s256.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/keccak256.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/sha256.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/xor.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/index.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/.nojekyll create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/compile.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/compile_contract.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/createFileManager.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/index.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs create mode 100644 docs/versioned_docs/version-v0.29.0/reference/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/reference/debugger/_category_.json create mode 100644 docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_known_limitations.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_repl.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_vscode.md create mode 100644 docs/versioned_docs/version-v0.29.0/reference/nargo_commands.md create mode 100644 docs/versioned_docs/version-v0.29.0/tooling/debugger.md create mode 100644 docs/versioned_docs/version-v0.29.0/tooling/language_server.md create mode 100644 docs/versioned_docs/version-v0.29.0/tooling/testing.md create mode 100644 docs/versioned_docs/version-v0.29.0/tutorials/noirjs_app.md create mode 100644 docs/versioned_sidebars/version-v0.28.0-sidebars.json create mode 100644 docs/versioned_sidebars/version-v0.29.0-sidebars.json delete mode 100644 flake.lock create mode 100644 noir_stdlib/src/aes128.nr create mode 100644 noir_stdlib/src/embedded_curve_ops.nr delete mode 100644 noir_stdlib/src/grumpkin_scalar.nr delete mode 100644 noir_stdlib/src/grumpkin_scalar_mul.nr delete mode 100644 noir_stdlib/src/internal.nr delete mode 100644 noir_stdlib/src/scalar_mul.nr create mode 100644 test_programs/compile_failure/self_referential_struct/Nargo.toml create mode 100644 test_programs/compile_failure/self_referential_struct/src/main.nr create mode 100644 test_programs/compile_success_empty/comptime_mut_global/Nargo.toml create mode 100644 test_programs/compile_success_empty/comptime_mut_global/src/main.nr create mode 100644 test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml create mode 100644 test_programs/compile_success_empty/impl_from_where_impl/src/main.nr create mode 100644 test_programs/execution_success/aes128_encrypt/Nargo.toml create mode 100644 test_programs/execution_success/aes128_encrypt/Prover.toml create mode 100644 test_programs/execution_success/aes128_encrypt/src/main.nr create mode 100644 test_programs/execution_success/array_if_cond_simple/Nargo.toml create mode 100644 test_programs/execution_success/array_if_cond_simple/Prover.toml create mode 100644 test_programs/execution_success/array_if_cond_simple/src/main.nr rename test_programs/execution_success/{distinct_keyword => brillig_embedded_curve}/Nargo.toml (62%) create mode 100644 test_programs/execution_success/brillig_embedded_curve/Prover.toml create mode 100644 test_programs/execution_success/brillig_embedded_curve/src/main.nr delete mode 100644 test_programs/execution_success/brillig_scalar_mul/Prover.toml delete mode 100644 test_programs/execution_success/brillig_scalar_mul/src/main.nr rename test_programs/{compile_success_empty => execution_success}/conditional_regression_547/Nargo.toml (100%) rename test_programs/{compile_success_empty => execution_success}/conditional_regression_547/Prover.toml (100%) rename test_programs/{compile_success_empty => execution_success}/conditional_regression_547/src/main.nr (100%) delete mode 100644 test_programs/execution_success/distinct_keyword/src/main.nr rename test_programs/execution_success/{brillig_scalar_mul => embedded_curve_ops}/Nargo.toml (65%) create mode 100644 test_programs/execution_success/embedded_curve_ops/Prover.toml create mode 100644 test_programs/execution_success/embedded_curve_ops/src/main.nr create mode 100644 test_programs/execution_success/fold_complex_outputs/Nargo.toml create mode 100644 test_programs/execution_success/fold_complex_outputs/Prover.toml create mode 100644 test_programs/execution_success/fold_complex_outputs/src/main.nr create mode 100644 test_programs/execution_success/fold_distinct_return/Nargo.toml create mode 100644 test_programs/execution_success/fold_distinct_return/Prover.toml create mode 100644 test_programs/execution_success/fold_distinct_return/src/main.nr create mode 100644 test_programs/execution_success/fold_fibonacci/Nargo.toml create mode 100644 test_programs/execution_success/fold_fibonacci/Prover.toml create mode 100644 test_programs/execution_success/fold_fibonacci/src/main.nr create mode 100644 test_programs/execution_success/inline_never_basic/Nargo.toml create mode 100644 test_programs/execution_success/inline_never_basic/Prover.toml create mode 100644 test_programs/execution_success/inline_never_basic/src/main.nr rename test_programs/{compile_success_empty => execution_success}/main_return/Nargo.toml (100%) rename test_programs/{compile_success_empty => execution_success}/main_return/Prover.toml (100%) rename test_programs/{compile_success_empty => execution_success}/main_return/src/main.nr (100%) create mode 100644 test_programs/execution_success/nested_array_dynamic_simple/Nargo.toml rename test_programs/execution_success/{distinct_keyword => nested_array_dynamic_simple}/Prover.toml (100%) create mode 100644 test_programs/execution_success/nested_array_dynamic_simple/src/main.nr create mode 100644 test_programs/execution_success/no_predicates_basic/Nargo.toml create mode 100644 test_programs/execution_success/no_predicates_basic/Prover.toml create mode 100644 test_programs/execution_success/no_predicates_basic/src/main.nr create mode 100644 test_programs/execution_success/no_predicates_numeric_generic_poseidon/Nargo.toml create mode 100644 test_programs/execution_success/no_predicates_numeric_generic_poseidon/Prover.toml create mode 100644 test_programs/execution_success/no_predicates_numeric_generic_poseidon/src/main.nr create mode 100644 test_programs/execution_success/regression_3051/Nargo.toml create mode 100644 test_programs/execution_success/regression_3051/src/main.nr create mode 100644 test_programs/execution_success/regression_4383/Nargo.toml create mode 100644 test_programs/execution_success/regression_4383/src/main.nr rename test_programs/execution_success/{scalar_mul => regression_4709}/Nargo.toml (68%) create mode 100644 test_programs/execution_success/regression_4709/Prover.toml create mode 100644 test_programs/execution_success/regression_4709/src/main.nr create mode 100644 test_programs/execution_success/regression_struct_array_conditional/Nargo.toml create mode 100644 test_programs/execution_success/regression_struct_array_conditional/Prover.toml create mode 100644 test_programs/execution_success/regression_struct_array_conditional/src/main.nr delete mode 100644 test_programs/execution_success/scalar_mul/Prover.toml delete mode 100644 test_programs/execution_success/scalar_mul/src/main.nr rename test_programs/{compile_success_empty => execution_success}/simple_array_param/Nargo.toml (100%) rename test_programs/{compile_success_empty => execution_success}/simple_array_param/Prover.toml (100%) rename test_programs/{compile_success_empty => execution_success}/simple_array_param/src/main.nr (100%) create mode 100644 test_programs/execution_success/slice_init_with_complex_type/Nargo.toml rename test_programs/{noir_test_success/bounded_vec => execution_success/slice_init_with_complex_type}/Prover.toml (100%) create mode 100644 test_programs/execution_success/slice_init_with_complex_type/src/main.nr delete mode 100644 test_programs/noir_test_success/brillig_overflow_checks/Prover.toml create mode 100644 test_programs/noir_test_success/comptime_globals/Nargo.toml create mode 100644 test_programs/noir_test_success/comptime_globals/src/main.nr delete mode 100644 test_programs/noir_test_success/field_comparisons/Prover.toml create mode 100644 test_programs/noir_test_success/ignored_oracle/Nargo.toml create mode 100644 test_programs/noir_test_success/ignored_oracle/src/main.nr delete mode 100644 test_programs/noir_test_success/mock_oracle/Prover.toml delete mode 100644 test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml delete mode 100644 test_programs/noir_test_success/should_fail_with_matches/Prover.toml create mode 100644 tooling/nargo_fmt/tests/expected/impl_trait_fn_parameter.nr create mode 100644 tooling/nargo_fmt/tests/input/impl_trait_fn_parameter.nr create mode 100644 tooling/noir_js/test/noir_compiled_examples/assert_raw_payload/Nargo.toml create mode 100644 tooling/noir_js/test/noir_compiled_examples/assert_raw_payload/src/main.nr create mode 100644 tooling/noir_js/test/noir_compiled_examples/fold_fibonacci/Nargo.toml create mode 100644 tooling/noir_js/test/noir_compiled_examples/fold_fibonacci/src/main.nr create mode 100644 tooling/noirc_abi_wasm/test/browser/decode_error.test.ts create mode 100644 tooling/noirc_abi_wasm/test/node/decode_error.test.ts create mode 100644 tooling/noirc_abi_wasm/test/shared/decode_error.ts rename {compiler/utils => utils}/iter-extended/Cargo.toml (100%) rename {compiler/utils => utils}/iter-extended/src/lib.rs (100%) diff --git a/.aztec-sync-commit b/.aztec-sync-commit index a159698f8a8..b9e87cffedc 100644 --- a/.aztec-sync-commit +++ b/.aztec-sync-commit @@ -1 +1 @@ -2e64428af9525bd8c390931061505f7b48d729a4 +1c74387e56b49102043fc6701735325a891e6c65 diff --git a/.github/workflows/docs-pr.yml b/.github/workflows/docs-pr.yml index 945ed555639..9cb6775bfb7 100644 --- a/.github/workflows/docs-pr.yml +++ b/.github/workflows/docs-pr.yml @@ -79,6 +79,8 @@ jobs: run: yarn workspace docs version::stables - name: Build docs + env: + MATOMO_ENV: staging # not really a secret, it will show in the footer anyway run: yarn workspaces foreach -Rpt --from docs run build - name: Upload artifact diff --git a/.github/workflows/publish-nargo.yml b/.github/workflows/publish-nargo.yml index 85010503b00..26a4c701c5b 100644 --- a/.github/workflows/publish-nargo.yml +++ b/.github/workflows/publish-nargo.yml @@ -23,7 +23,7 @@ permissions: jobs: build-apple-darwin: - runs-on: macos-latest + runs-on: macos-12 env: CROSS_CONFIG: ${{ github.workspace }}/.github/Cross.toml NIGHTLY_RELEASE: ${{ inputs.tag == '' }} diff --git a/.github/workflows/test-rust-workspace-msrv.yml b/.github/workflows/test-rust-workspace-msrv.yml index c13b0815d94..ccd431ea879 100644 --- a/.github/workflows/test-rust-workspace-msrv.yml +++ b/.github/workflows/test-rust-workspace-msrv.yml @@ -88,7 +88,8 @@ jobs: - name: Run tests run: | cargo nextest run --archive-file nextest-archive.tar.zst \ - --partition count:${{ matrix.partition }}/4 + --partition count:${{ matrix.partition }}/4 \ + --no-fail-fast # This is a job which depends on all test jobs and reports the overall status. # This allows us to add/remove test jobs without having to update the required workflows. diff --git a/.github/workflows/test-rust-workspace.yml b/.github/workflows/test-rust-workspace.yml index cf35950fa3e..1f3ee5e2268 100644 --- a/.github/workflows/test-rust-workspace.yml +++ b/.github/workflows/test-rust-workspace.yml @@ -75,7 +75,8 @@ jobs: - name: Run tests run: | cargo nextest run --archive-file nextest-archive.tar.zst \ - --partition count:${{ matrix.partition }}/4 + --partition count:${{ matrix.partition }}/4 \ + --no-fail-fast # This is a job which depends on all test jobs and reports the overall status. # This allows us to add/remove test jobs without having to update the required workflows. diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7579928c999..447e12155b8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,4 +1,4 @@ { - ".": "0.27.0", - "acvm-repo": "0.43.0" -} \ No newline at end of file + ".": "0.29.0", + "acvm-repo": "0.45.0" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index a084811fc21..7be8c387026 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,121 @@ # Changelog +## [0.29.0](https://github.com/noir-lang/noir/compare/v0.28.0...v0.29.0) (2024-05-03) + + +### ⚠ BREAKING CHANGES + +* use `distinct` return value witnesses by default ([#4951](https://github.com/noir-lang/noir/issues/4951)) +* Bit shift is restricted to u8 right operand ([#4907](https://github.com/noir-lang/noir/issues/4907)) + +### Features + +* Add `#[inline(tag)]` attribute and codegen ([#4913](https://github.com/noir-lang/noir/issues/4913)) ([1ec9cdc](https://github.com/noir-lang/noir/commit/1ec9cdc7013e867db3672d27e3a6104e4b7e7eef)) +* Add de-sugaring for `impl Trait` in function parameters ([#4919](https://github.com/noir-lang/noir/issues/4919)) ([8aad2e4](https://github.com/noir-lang/noir/commit/8aad2e45acbe08afc3902db95a83324f822c35eb)) +* Add variable size sha256 ([#4920](https://github.com/noir-lang/noir/issues/4920)) ([dbfca58](https://github.com/noir-lang/noir/commit/dbfca58a817ee1f1512e3e02138119f363c3d12b)) +* Bit shift is restricted to u8 right operand ([#4907](https://github.com/noir-lang/noir/issues/4907)) ([c4b0369](https://github.com/noir-lang/noir/commit/c4b03691feca17ef268acab523292f3051f672ea)) +* Complex outputs from acir call ([#4952](https://github.com/noir-lang/noir/issues/4952)) ([2e085b9](https://github.com/noir-lang/noir/commit/2e085b935b143c1305b70cd7ae86907b61a45fc0)) +* **experimental:** `comptime` globals ([#4918](https://github.com/noir-lang/noir/issues/4918)) ([8a3c7f1](https://github.com/noir-lang/noir/commit/8a3c7f1c11666ed5140a63a5aa296ef417c97bfa)) +* Handle `BrilligCall` opcodes in the debugger ([#4897](https://github.com/noir-lang/noir/issues/4897)) ([b380dc4](https://github.com/noir-lang/noir/commit/b380dc44de5c9f8de278ece3d531ebbc2c9238ba)) +* Handle `no_predicates` attribute ([#4942](https://github.com/noir-lang/noir/issues/4942)) ([0ce04d3](https://github.com/noir-lang/noir/commit/0ce04d3ea8734b76d96f5dd0fb2a6cdd4081969e)) +* Handle empty response foreign calls without an external resolver ([#4959](https://github.com/noir-lang/noir/issues/4959)) ([0154bde](https://github.com/noir-lang/noir/commit/0154bdef9f6dfe45497d77ecbf3904dcc138b8d7)) +* Optimize array sets in if conditions (alternate version) ([#4716](https://github.com/noir-lang/noir/issues/4716)) ([a87c655](https://github.com/noir-lang/noir/commit/a87c655c6c8c077c71e3372cc9181b7870348a3d)) +* Use `distinct` return value witnesses by default ([#4951](https://github.com/noir-lang/noir/issues/4951)) ([5f1b584](https://github.com/noir-lang/noir/commit/5f1b58470779e977293323d10ab9a8f0857ea29e)) + + +### Bug Fixes + +* Ban self-referential structs ([#4883](https://github.com/noir-lang/noir/issues/4883)) ([800f670](https://github.com/noir-lang/noir/commit/800f670b63a5a2ae08f09a86dae767089f7f67af)) +* Discard ref counts during unrolling ([#4923](https://github.com/noir-lang/noir/issues/4923)) ([91062db](https://github.com/noir-lang/noir/commit/91062db84a749bf191eae9ce487a2315cc74bfb2)) +* Ensure where clauses propagated to trait default definitions ([#4894](https://github.com/noir-lang/noir/issues/4894)) ([aaac0f6](https://github.com/noir-lang/noir/commit/aaac0f6bffbe11eb090145354f1b82919bb93cb7)) +* Move remove_if_else pass after second inlining ([#4976](https://github.com/noir-lang/noir/issues/4976)) ([96fb3e9](https://github.com/noir-lang/noir/commit/96fb3e94b3a2f7b586d17ea9445f44267f5d9c6d)) +* Nested array equality ([#4903](https://github.com/noir-lang/noir/issues/4903)) ([0cf2e2a](https://github.com/noir-lang/noir/commit/0cf2e2a1b8d247bed03ba5b7b1be5cd30f0d51b2)) +* Require for all foldable functions to use distinct return ([#4949](https://github.com/noir-lang/noir/issues/4949)) ([d4c6806](https://github.com/noir-lang/noir/commit/d4c68066ab35ce1c52510cf0c038fb627a0677c3)) +* Use annotated type when checking declaration ([#4966](https://github.com/noir-lang/noir/issues/4966)) ([f7fa696](https://github.com/noir-lang/noir/commit/f7fa69661006e1e10ddeecee1cdf8f024d6bc3e9)) + +## [0.28.0](https://github.com/noir-lang/noir/compare/v0.27.0...v0.28.0) (2024-04-24) + + +### ⚠ BREAKING CHANGES + +* Add `as_array` and remove `_slice` variants of hash functions ([#4675](https://github.com/noir-lang/noir/issues/4675)) +* reserve keyword `super` ([#4836](https://github.com/noir-lang/noir/issues/4836)) +* contract interfaces and better function calls (https://github.com/AztecProtocol/aztec-packages/pull/5687) +* change backend width to 4 (https://github.com/AztecProtocol/aztec-packages/pull/5374) +* Use fixed size arrays in black box functions where sizes are known (https://github.com/AztecProtocol/aztec-packages/pull/5620) +* trap with revert data (https://github.com/AztecProtocol/aztec-packages/pull/5732) +* **acir:** BrilligCall opcode (https://github.com/AztecProtocol/aztec-packages/pull/5709) +* remove fixed-length keccak256 (https://github.com/AztecProtocol/aztec-packages/pull/5617) +* storage_layout and `#[aztec(storage)]` (https://github.com/AztecProtocol/aztec-packages/pull/5387) +* **acir:** Add predicate to call opcode (https://github.com/AztecProtocol/aztec-packages/pull/5616) +* contract_abi-exports (https://github.com/AztecProtocol/aztec-packages/pull/5386) + +### Features + +* **acir_gen:** Brillig stdlib ([#4848](https://github.com/noir-lang/noir/issues/4848)) ([0c8175c](https://github.com/noir-lang/noir/commit/0c8175cb539efd9427c73ae5af0d48abe688ebab)) +* **acir:** Add predicate to call opcode (https://github.com/AztecProtocol/aztec-packages/pull/5616) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* **acir:** BrilligCall opcode (https://github.com/AztecProtocol/aztec-packages/pull/5709) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Add `min` and `max` functions to the stdlib ([#4839](https://github.com/noir-lang/noir/issues/4839)) ([6cfb328](https://github.com/noir-lang/noir/commit/6cfb328d0d162eaa20ad1a118d085e03a52d049d)) +* Add `NARGO_FOREIGN_CALL_TIMEOUT` environment variable ([#4780](https://github.com/noir-lang/noir/issues/4780)) ([791f1c8](https://github.com/noir-lang/noir/commit/791f1c8522d49972dad4eb940f9cad437e28b25b)) +* Add comptime Interpreter ([#4821](https://github.com/noir-lang/noir/issues/4821)) ([5992436](https://github.com/noir-lang/noir/commit/599243633281e6827f0f4f095fb12d313e0125fa)) +* Add return values to aztec fns (https://github.com/AztecProtocol/aztec-packages/pull/5389) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Allow numeric generics to non inlined ACIR functions ([#4834](https://github.com/noir-lang/noir/issues/4834)) ([9cc03a4](https://github.com/noir-lang/noir/commit/9cc03a4d6f714a1b2d31c6982eb8e791ba5c869c)) +* **avm:** Integrate AVM with initializers (https://github.com/AztecProtocol/aztec-packages/pull/5469) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Brillig heterogeneous memory cells (https://github.com/AztecProtocol/aztec-packages/pull/5608) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Brillig pointer codegen and execution (https://github.com/AztecProtocol/aztec-packages/pull/5737) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Change backend width to 4 (https://github.com/AztecProtocol/aztec-packages/pull/5374) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Contract interfaces and better function calls (https://github.com/AztecProtocol/aztec-packages/pull/5687) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Contract_abi-exports (https://github.com/AztecProtocol/aztec-packages/pull/5386) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* **experimental:** Add `comptime` keyword ([#4840](https://github.com/noir-lang/noir/issues/4840)) ([4dfd7f0](https://github.com/noir-lang/noir/commit/4dfd7f03bc1b9cf57f5829c435a560bed53b7f46)) +* Get last mock oracles params ([#4789](https://github.com/noir-lang/noir/issues/4789)) ([1d96937](https://github.com/noir-lang/noir/commit/1d96937a8e94a91c0c17c97102498d067fca76c3)) +* Impl of missing functionality in new key store (https://github.com/AztecProtocol/aztec-packages/pull/5750) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Implement `Eq` trait on `BoundedVec` ([#4830](https://github.com/noir-lang/noir/issues/4830)) ([6cefe16](https://github.com/noir-lang/noir/commit/6cefe16deb643951c0cc552d08e22272900ed456)) +* Lalrpop lexer prototype ([#4656](https://github.com/noir-lang/noir/issues/4656)) ([25ad018](https://github.com/noir-lang/noir/commit/25ad018a55b61dd861e899f050c48200f0a00430)) +* **nargo:** Handle call stacks for multiple Acir calls ([#4711](https://github.com/noir-lang/noir/issues/4711)) ([5b23171](https://github.com/noir-lang/noir/commit/5b231714740447d82cde7cdbe65d4a8b46a31df4)) +* Narrow ABI encoding errors down to target problem argument/field ([#4798](https://github.com/noir-lang/noir/issues/4798)) ([e412e6e](https://github.com/noir-lang/noir/commit/e412e6e30910472b9d5f9000370ce5138ad39ce7)) +* Proving the rollup circuits (https://github.com/AztecProtocol/aztec-packages/pull/5599) ([5b352d6](https://github.com/noir-lang/noir/commit/5b352d6266c40522f5626f79d2f36a409b482aaa)) +* Reserve keyword `super` ([#4836](https://github.com/noir-lang/noir/issues/4836)) ([d5028a6](https://github.com/noir-lang/noir/commit/d5028a613e5a65ad1286dd20ce0fb0313f19f6ee)) +* Restore hashing args via slice for performance (https://github.com/AztecProtocol/aztec-packages/pull/5539) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Simplify `BoundedVec::eq` ([#4838](https://github.com/noir-lang/noir/issues/4838)) ([3d33a33](https://github.com/noir-lang/noir/commit/3d33a33e74c3e7d0fc511059b07f0ef9ddd9b667)) +* **simulator:** Fetch return values at circuit execution (https://github.com/AztecProtocol/aztec-packages/pull/5642) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Split `backend_barretenburg` into prover and verifier classes ([#4769](https://github.com/noir-lang/noir/issues/4769)) ([ce1e662](https://github.com/noir-lang/noir/commit/ce1e6624ece3c91f06b0273af9ba88e703c1b589)) +* Storage_layout and `#[aztec(storage)]` (https://github.com/AztecProtocol/aztec-packages/pull/5387) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5572) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5619) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5697) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5725) ([5b352d6](https://github.com/noir-lang/noir/commit/5b352d6266c40522f5626f79d2f36a409b482aaa)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5794) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5814) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5935) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5955) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5999) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Trap with revert data (https://github.com/AztecProtocol/aztec-packages/pull/5732) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Unroll loops iteratively ([#4779](https://github.com/noir-lang/noir/issues/4779)) ([f831b0b](https://github.com/noir-lang/noir/commit/f831b0bdbf99cab1bcd24d494c4546a36309465e)) +* Use fixed size arrays in black box functions where sizes are known (https://github.com/AztecProtocol/aztec-packages/pull/5620) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Variable length returns (https://github.com/AztecProtocol/aztec-packages/pull/5633) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) + + +### Bug Fixes + +* ArrayGet and Set are not pure ([#4783](https://github.com/noir-lang/noir/issues/4783)) ([90ee479](https://github.com/noir-lang/noir/commit/90ee4792c8e7115e55a3b1dadd1e43066ad8ac66)) +* Avoid huge unrolling in hash_args (https://github.com/AztecProtocol/aztec-packages/pull/5703) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Catch panics from EC point creation (e.g. the point is at infinity) ([#4790](https://github.com/noir-lang/noir/issues/4790)) ([645dba1](https://github.com/noir-lang/noir/commit/645dba192f16ef34018828186ffb297422a8dc73)) +* Don't reuse brillig with slice arguments (https://github.com/AztecProtocol/aztec-packages/pull/5800) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* **experimental:** Skip over comptime functions in scan pass ([#4893](https://github.com/noir-lang/noir/issues/4893)) ([f267d42](https://github.com/noir-lang/noir/commit/f267d4205b46317eacb1c247c9dca0e7698d1259)) +* Fix curve parameters for bigints ([#4900](https://github.com/noir-lang/noir/issues/4900)) ([5985e42](https://github.com/noir-lang/noir/commit/5985e4285de9e29f7c986103a49fdaec59228887)) +* Fix panic when returning a zeroed unit value ([#4797](https://github.com/noir-lang/noir/issues/4797)) ([2ea9292](https://github.com/noir-lang/noir/commit/2ea92926956658ea99d8fb97734831eba00d3a4b)) +* Issue 4682 and add solver for unconstrained bigintegers ([#4729](https://github.com/noir-lang/noir/issues/4729)) ([e4d33c1](https://github.com/noir-lang/noir/commit/e4d33c126a2795d9aaa6048d4e91b64cb4bbe4f2)) +* Primary_message typo in errors.rs (https://github.com/AztecProtocol/aztec-packages/pull/5646) ([5b352d6](https://github.com/noir-lang/noir/commit/5b352d6266c40522f5626f79d2f36a409b482aaa)) +* Proper field inversion for bigints ([#4802](https://github.com/noir-lang/noir/issues/4802)) ([b46d0e3](https://github.com/noir-lang/noir/commit/b46d0e39f4252f8bbaa987f88d112e4c233b3d61)) +* Reset the noir-gates-diff report on master ([#4878](https://github.com/noir-lang/noir/issues/4878)) ([50bc325](https://github.com/noir-lang/noir/commit/50bc32587a837c930ed14175c98ace1530c54bef)) +* Update noir-gates-diff commit to use master reference report ([#4891](https://github.com/noir-lang/noir/issues/4891)) ([4a3ffb7](https://github.com/noir-lang/noir/commit/4a3ffb7b4c5cdd5fcadb19e7f251b1ee27b0c02b)) + + +### Miscellaneous Chores + +* Add `as_array` and remove `_slice` variants of hash functions ([#4675](https://github.com/noir-lang/noir/issues/4675)) ([8e39706](https://github.com/noir-lang/noir/commit/8e39706cbb51f27b42fbe851aaa6a67070d07c74)) +* Remove fixed-length keccak256 (https://github.com/AztecProtocol/aztec-packages/pull/5617) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) + ## [0.27.0](https://github.com/noir-lang/noir/compare/v0.26.0...v0.27.0) (2024-04-10) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d2553b003f8..c02d24e91b8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -196,7 +196,7 @@ yarn docusaurus docs:version This should create a new version by copying the docs folder and the sidebars.js file to the relevant folders, as well as adding this version to versions.json. -You can then open a Pull Request according to the the [PR section](#pull-requests) +You can then open a Pull Request according to the [PR section](#pull-requests) ## Changelog diff --git a/Cargo.lock b/Cargo.lock index 9c9e13b57c9..859579c077f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "acir" -version = "0.43.0" +version = "0.45.0" dependencies = [ "acir_field", "base64 0.21.2", @@ -26,7 +26,7 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.43.0" +version = "0.45.0" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -40,7 +40,7 @@ dependencies = [ [[package]] name = "acvm" -version = "0.43.0" +version = "0.45.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -56,13 +56,14 @@ dependencies = [ [[package]] name = "acvm_blackbox_solver" -version = "0.43.0" +version = "0.45.0" dependencies = [ "acir", "blake2", "blake3", "k256", "keccak", + "libaes", "num-bigint", "p256", "sha2", @@ -92,7 +93,7 @@ dependencies = [ [[package]] name = "acvm_js" -version = "0.43.0" +version = "0.45.0" dependencies = [ "acvm", "bn254_blackbox_solver", @@ -233,10 +234,6 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" -[[package]] -name = "arena" -version = "0.27.0" - [[package]] name = "ark-bls12-381" version = "0.4.0" @@ -445,7 +442,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "aztec_macros" -version = "0.27.0" +version = "0.29.0" dependencies = [ "convert_case 0.6.0", "iter-extended", @@ -456,7 +453,7 @@ dependencies = [ [[package]] name = "backend-interface" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "bb_abstraction_leaks", @@ -612,7 +609,7 @@ dependencies = [ [[package]] name = "bn254_blackbox_solver" -version = "0.43.0" +version = "0.45.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -634,7 +631,7 @@ dependencies = [ [[package]] name = "brillig" -version = "0.43.0" +version = "0.45.0" dependencies = [ "acir_field", "serde", @@ -642,7 +639,7 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.43.0" +version = "0.45.0" dependencies = [ "acir", "acvm_blackbox_solver", @@ -1766,7 +1763,7 @@ dependencies = [ [[package]] name = "fm" -version = "0.27.0" +version = "0.29.0" dependencies = [ "codespan-reporting", "iter-extended", @@ -2387,7 +2384,7 @@ dependencies = [ [[package]] name = "iter-extended" -version = "0.27.0" +version = "0.29.0" [[package]] name = "itertools" @@ -2620,6 +2617,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +[[package]] +name = "libaes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82903360c009b816f5ab72a9b68158c27c301ee2c3f20655b55c5e589e7d3bb7" + [[package]] name = "libc" version = "0.2.151" @@ -2812,7 +2815,7 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "nargo" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "codespan-reporting", @@ -2838,7 +2841,7 @@ dependencies = [ [[package]] name = "nargo_cli" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "assert_cmd", @@ -2892,7 +2895,7 @@ dependencies = [ [[package]] name = "nargo_fmt" -version = "0.27.0" +version = "0.29.0" dependencies = [ "bytecount", "noirc_frontend", @@ -2904,7 +2907,7 @@ dependencies = [ [[package]] name = "nargo_toml" -version = "0.27.0" +version = "0.29.0" dependencies = [ "dirs", "fm", @@ -2983,7 +2986,7 @@ dependencies = [ [[package]] name = "noir_debugger" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "assert_cmd", @@ -3018,7 +3021,7 @@ dependencies = [ [[package]] name = "noir_lsp" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "async-lsp", @@ -3044,7 +3047,7 @@ dependencies = [ [[package]] name = "noir_wasm" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "build-data", @@ -3067,11 +3070,12 @@ dependencies = [ [[package]] name = "noirc_abi" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "iter-extended", "noirc_frontend", + "noirc_printable_type", "num-bigint", "num-traits", "serde", @@ -3084,7 +3088,7 @@ dependencies = [ [[package]] name = "noirc_abi_wasm" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "build-data", @@ -3099,9 +3103,13 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "noirc_arena" +version = "0.29.0" + [[package]] name = "noirc_driver" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "aztec_macros", @@ -3122,7 +3130,7 @@ dependencies = [ [[package]] name = "noirc_errors" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "base64 0.21.2", @@ -3140,7 +3148,7 @@ dependencies = [ [[package]] name = "noirc_evaluator" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "chrono", @@ -3157,10 +3165,9 @@ dependencies = [ [[package]] name = "noirc_frontend" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", - "arena", "base64 0.21.2", "chumsky", "fm", @@ -3168,6 +3175,7 @@ dependencies = [ "iter-extended", "lalrpop", "lalrpop-util", + "noirc_arena", "noirc_errors", "noirc_printable_type", "petgraph", @@ -3186,7 +3194,7 @@ dependencies = [ [[package]] name = "noirc_printable_type" -version = "0.27.0" +version = "0.29.0" dependencies = [ "acvm", "iter-extended", diff --git a/Cargo.toml b/Cargo.toml index 132ff181e44..f744d6d0cf5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ # Aztec Macro crate for metaprogramming "aztec_macros", # Compiler crates + "compiler/noirc_arena", "compiler/noirc_evaluator", "compiler/noirc_frontend", "compiler/noirc_errors", @@ -11,10 +12,7 @@ members = [ "compiler/noirc_printable_type", "compiler/fm", "compiler/wasm", - # Utility crates used by the Noir compiler - "compiler/utils/arena", - "compiler/utils/iter-extended", - # Crates related to tooling built ontop of the Noir compiler + # Crates related to tooling built on top of the Noir compiler "tooling/backend_interface", "tooling/bb_abstraction_leaks", "tooling/lsp", @@ -35,13 +33,15 @@ members = [ "acvm-repo/brillig_vm", "acvm-repo/blackbox_solver", "acvm-repo/bn254_blackbox_solver", + # Utility crates + "utils/iter-extended", ] default-members = ["tooling/nargo_cli", "tooling/acvm_cli"] resolver = "2" [workspace.package] # x-release-please-start-version -version = "0.27.0" +version = "0.29.0" # x-release-please-end authors = ["The Noir Team "] edition = "2021" @@ -52,18 +52,17 @@ repository = "https://github.com/noir-lang/noir/" [workspace.dependencies] # ACVM workspace dependencies -acir_field = { version = "0.43.0", path = "acvm-repo/acir_field", default-features = false } -acir = { version = "0.43.0", path = "acvm-repo/acir", default-features = false } -acvm = { version = "0.43.0", path = "acvm-repo/acvm" } -brillig = { version = "0.43.0", path = "acvm-repo/brillig", default-features = false } -brillig_vm = { version = "0.43.0", path = "acvm-repo/brillig_vm", default-features = false } -acvm_blackbox_solver = { version = "0.43.0", path = "acvm-repo/blackbox_solver", default-features = false } -bn254_blackbox_solver = { version = "0.43.0", path = "acvm-repo/bn254_blackbox_solver", default-features = false } +acir_field = { version = "0.45.0", path = "acvm-repo/acir_field", default-features = false } +acir = { version = "0.45.0", path = "acvm-repo/acir", default-features = false } +acvm = { version = "0.45.0", path = "acvm-repo/acvm" } +brillig = { version = "0.45.0", path = "acvm-repo/brillig", default-features = false } +brillig_vm = { version = "0.45.0", path = "acvm-repo/brillig_vm", default-features = false } +acvm_blackbox_solver = { version = "0.45.0", path = "acvm-repo/blackbox_solver", default-features = false } +bn254_blackbox_solver = { version = "0.45.0", path = "acvm-repo/bn254_blackbox_solver", default-features = false } # Noir compiler workspace dependencies -arena = { path = "compiler/utils/arena" } fm = { path = "compiler/fm" } -iter-extended = { path = "compiler/utils/iter-extended" } +noirc_arena = { path = "compiler/noirc_arena" } noirc_driver = { path = "compiler/noirc_driver" } noirc_errors = { path = "compiler/noirc_errors" } noirc_evaluator = { path = "compiler/noirc_evaluator" } @@ -80,6 +79,9 @@ noirc_abi = { path = "tooling/noirc_abi" } bb_abstraction_leaks = { path = "tooling/bb_abstraction_leaks" } acvm_cli = { path = "tooling/acvm_cli" } +# Misc utils crates +iter-extended = { path = "utils/iter-extended" } + # LSP async-lsp = { version = "0.1.0", default-features = false } lsp-types = "0.94.1" @@ -109,7 +111,7 @@ chumsky = { git = "https://github.com/jfecher/chumsky", rev = "ad9d312", default criterion = "0.5.0" # Note that using the "frame-pointer" feature breaks framegraphs on linux # https://github.com/tikv/pprof-rs/pull/172 -pprof = { version = "0.13", features = ["flamegraph","criterion"] } +pprof = { version = "0.13", features = ["flamegraph", "criterion"] } dirs = "4" diff --git a/acvm-repo/CHANGELOG.md b/acvm-repo/CHANGELOG.md index 9d9ff539559..6ac04f6f83f 100644 --- a/acvm-repo/CHANGELOG.md +++ b/acvm-repo/CHANGELOG.md @@ -5,6 +5,246 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.45.0](https://github.com/noir-lang/noir/compare/v0.44.0...v0.45.0) (2024-05-03) + + +### ⚠ BREAKING CHANGES + +* Bit shift is restricted to u8 right operand ([#4907](https://github.com/noir-lang/noir/issues/4907)) +* contract interfaces and better function calls (https://github.com/AztecProtocol/aztec-packages/pull/5687) +* change backend width to 4 (https://github.com/AztecProtocol/aztec-packages/pull/5374) +* Use fixed size arrays in black box functions where sizes are known (https://github.com/AztecProtocol/aztec-packages/pull/5620) +* trap with revert data (https://github.com/AztecProtocol/aztec-packages/pull/5732) +* **acir:** BrilligCall opcode (https://github.com/AztecProtocol/aztec-packages/pull/5709) +* remove fixed-length keccak256 (https://github.com/AztecProtocol/aztec-packages/pull/5617) +* storage_layout and `#[aztec(storage)]` (https://github.com/AztecProtocol/aztec-packages/pull/5387) +* **acir:** Add predicate to call opcode (https://github.com/AztecProtocol/aztec-packages/pull/5616) +* contract_abi-exports (https://github.com/AztecProtocol/aztec-packages/pull/5386) +* Brillig typed memory (https://github.com/AztecProtocol/aztec-packages/pull/5395) +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) +* automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) +* Internal as a macro (https://github.com/AztecProtocol/aztec-packages/pull/4898) +* move noir out of yarn-project (https://github.com/AztecProtocol/aztec-packages/pull/4479) +* note type ids (https://github.com/AztecProtocol/aztec-packages/pull/4500) +* rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) +* init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) +* Sync commits from `aztec-packages` ([#4144](https://github.com/noir-lang/noir/issues/4144)) +* Breaking changes from aztec-packages ([#3955](https://github.com/noir-lang/noir/issues/3955)) + +### Features + +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **acir_gen:** Brillig stdlib ([#4848](https://github.com/noir-lang/noir/issues/4848)) ([0c8175c](https://github.com/noir-lang/noir/commit/0c8175cb539efd9427c73ae5af0d48abe688ebab)) +* **acir_gen:** Fold attribute at compile-time and initial non inlined ACIR (https://github.com/AztecProtocol/aztec-packages/pull/5341) ([a0f7474](https://github.com/noir-lang/noir/commit/a0f7474ae6bd74132efdb945d2eb2383f3913cce)) +* **acir:** Add predicate to call opcode (https://github.com/AztecProtocol/aztec-packages/pull/5616) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* **acir:** BrilligCall opcode (https://github.com/AztecProtocol/aztec-packages/pull/5709) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* **acvm_js:** Execute program ([#4694](https://github.com/noir-lang/noir/issues/4694)) ([386f6d0](https://github.com/noir-lang/noir/commit/386f6d0a5822912db878285cb001032a7c0ff622)) +* **acvm:** Execute multiple circuits (https://github.com/AztecProtocol/aztec-packages/pull/5380) ([a0f7474](https://github.com/noir-lang/noir/commit/a0f7474ae6bd74132efdb945d2eb2383f3913cce)) +* Add bit size to const opcode (https://github.com/AztecProtocol/aztec-packages/pull/4385) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Add CMOV instruction to brillig and brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5308) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Add instrumentation for tracking variables in debugging ([#4122](https://github.com/noir-lang/noir/issues/4122)) ([c58d691](https://github.com/noir-lang/noir/commit/c58d69141b54a918cd1675400c00bfd48720f896)) +* Add poseidon2 opcode implementation for acvm/brillig, and Noir ([#4398](https://github.com/noir-lang/noir/issues/4398)) ([10e8292](https://github.com/noir-lang/noir/commit/10e82920798380f50046e52db4a20ca205191ab7)) +* Add return values to aztec fns (https://github.com/AztecProtocol/aztec-packages/pull/5389) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Add support for overriding expression width ([#4117](https://github.com/noir-lang/noir/issues/4117)) ([c8026d5](https://github.com/noir-lang/noir/commit/c8026d557d535b10fe455165d6445076df7a03de)) +* Added cast opcode and cast calldata (https://github.com/AztecProtocol/aztec-packages/pull/4423) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Allow brillig to read arrays directly from memory (https://github.com/AztecProtocol/aztec-packages/pull/4460) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Allow nested arrays and vectors in Brillig foreign calls (https://github.com/AztecProtocol/aztec-packages/pull/4478) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Allow variables and stack trace inspection in the debugger ([#4184](https://github.com/noir-lang/noir/issues/4184)) ([bf263fc](https://github.com/noir-lang/noir/commit/bf263fc8d843940f328a90f6366edd2671fb2682)) +* Automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* **avm:** Back in avm context with macro - refactor context (https://github.com/AztecProtocol/aztec-packages/pull/4438) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* **avm:** Brillig CONST of size > u128 (https://github.com/AztecProtocol/aztec-packages/pull/5217) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **avm:** Integrate AVM with initializers (https://github.com/AztecProtocol/aztec-packages/pull/5469) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* **aztec-nr:** Initial work for aztec public vm macro (https://github.com/AztecProtocol/aztec-packages/pull/4400) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Backpropagate constants in ACIR during optimization ([#3926](https://github.com/noir-lang/noir/issues/3926)) ([aad0da0](https://github.com/noir-lang/noir/commit/aad0da024c69663f42e6913e674682d5864b26ae)) +* Bit shift is restricted to u8 right operand ([#4907](https://github.com/noir-lang/noir/issues/4907)) ([c4b0369](https://github.com/noir-lang/noir/commit/c4b03691feca17ef268acab523292f3051f672ea)) +* Breaking changes from aztec-packages ([#3955](https://github.com/noir-lang/noir/issues/3955)) ([5be049e](https://github.com/noir-lang/noir/commit/5be049eee6c342649462282ee04f6411e6ea392c)) +* Brillig heterogeneous memory cells (https://github.com/AztecProtocol/aztec-packages/pull/5608) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Brillig IR refactor (https://github.com/AztecProtocol/aztec-packages/pull/5233) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Brillig pointer codegen and execution (https://github.com/AztecProtocol/aztec-packages/pull/5737) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Brillig typed memory (https://github.com/AztecProtocol/aztec-packages/pull/5395) ([0bc18c4](https://github.com/noir-lang/noir/commit/0bc18c4f78171590dd58bded959f68f53a44cc8c)) +* Change backend width to 4 (https://github.com/AztecProtocol/aztec-packages/pull/5374) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Check initializer msg.sender matches deployer from address preimage (https://github.com/AztecProtocol/aztec-packages/pull/5222) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Contract interfaces and better function calls (https://github.com/AztecProtocol/aztec-packages/pull/5687) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Contract_abi-exports (https://github.com/AztecProtocol/aztec-packages/pull/5386) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Evaluation of dynamic assert messages ([#4101](https://github.com/noir-lang/noir/issues/4101)) ([c284e01](https://github.com/noir-lang/noir/commit/c284e01bfe20ceae4414dc123624b5cbb8b66d09)) +* Handle `BrilligCall` opcodes in the debugger ([#4897](https://github.com/noir-lang/noir/issues/4897)) ([b380dc4](https://github.com/noir-lang/noir/commit/b380dc44de5c9f8de278ece3d531ebbc2c9238ba)) +* Impl of missing functionality in new key store (https://github.com/AztecProtocol/aztec-packages/pull/5750) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Initial Earthly CI (https://github.com/AztecProtocol/aztec-packages/pull/5069) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Internal as a macro (https://github.com/AztecProtocol/aztec-packages/pull/4898) ([5f57ebb](https://github.com/noir-lang/noir/commit/5f57ebb7ff4b810802f90699a10f4325ef904f2e)) +* **nargo:** Handle call stacks for multiple Acir calls ([#4711](https://github.com/noir-lang/noir/issues/4711)) ([5b23171](https://github.com/noir-lang/noir/commit/5b231714740447d82cde7cdbe65d4a8b46a31df4)) +* New brillig field operations and refactor of binary operations (https://github.com/AztecProtocol/aztec-packages/pull/5208) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Note type ids (https://github.com/AztecProtocol/aztec-packages/pull/4500) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Remove replacement of boolean range opcodes with `AssertZero` opcodes ([#4107](https://github.com/noir-lang/noir/issues/4107)) ([dac0e87](https://github.com/noir-lang/noir/commit/dac0e87ee3be3446b92bbb12ef4832fd493fcee3)) +* Restore hashing args via slice for performance (https://github.com/AztecProtocol/aztec-packages/pull/5539) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Signed integer division and modulus in brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5279) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **simulator:** Fetch return values at circuit execution (https://github.com/AztecProtocol/aztec-packages/pull/5642) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Storage_layout and `#[aztec(storage)]` (https://github.com/AztecProtocol/aztec-packages/pull/5387) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync `aztec-packages` ([#4011](https://github.com/noir-lang/noir/issues/4011)) ([fee2452](https://github.com/noir-lang/noir/commit/fee24523c427c27f0bdaf98ea09a852a2da3e94c)) +* Sync commits from `aztec-packages` ([#4068](https://github.com/noir-lang/noir/issues/4068)) ([7a8f3a3](https://github.com/noir-lang/noir/commit/7a8f3a33b57875e681e3d81e667e3570a1cdbdcc)) +* Sync commits from `aztec-packages` ([#4144](https://github.com/noir-lang/noir/issues/4144)) ([0205d3b](https://github.com/noir-lang/noir/commit/0205d3b4ad0cf5ffd775a43eb5af273a772cf138)) +* Sync from aztec-packages ([#4483](https://github.com/noir-lang/noir/issues/4483)) ([fe8f277](https://github.com/noir-lang/noir/commit/fe8f2776ccfde29209a2c3fc162311c99e4f59be)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5234) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5286) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5572) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5619) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5697) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5794) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5814) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5935) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5955) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5999) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Trap with revert data (https://github.com/AztecProtocol/aztec-packages/pull/5732) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Use fixed size arrays in black box functions where sizes are known (https://github.com/AztecProtocol/aztec-packages/pull/5620) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Variable length returns (https://github.com/AztecProtocol/aztec-packages/pull/5633) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) + + +### Bug Fixes + +* **acvm:** Mark outputs of Opcode::Call solvable ([#4708](https://github.com/noir-lang/noir/issues/4708)) ([8fea405](https://github.com/noir-lang/noir/commit/8fea40576f262bd5bb588923c0660d8967404e56)) +* Avoid huge unrolling in hash_args (https://github.com/AztecProtocol/aztec-packages/pull/5703) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Catch panics from EC point creation (e.g. the point is at infinity) ([#4790](https://github.com/noir-lang/noir/issues/4790)) ([645dba1](https://github.com/noir-lang/noir/commit/645dba192f16ef34018828186ffb297422a8dc73)) +* Don't reuse brillig with slice arguments (https://github.com/AztecProtocol/aztec-packages/pull/5800) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Issue 4682 and add solver for unconstrained bigintegers ([#4729](https://github.com/noir-lang/noir/issues/4729)) ([e4d33c1](https://github.com/noir-lang/noir/commit/e4d33c126a2795d9aaa6048d4e91b64cb4bbe4f2)) +* Noir test incorrect reporting (https://github.com/AztecProtocol/aztec-packages/pull/4925) ([5f57ebb](https://github.com/noir-lang/noir/commit/5f57ebb7ff4b810802f90699a10f4325ef904f2e)) +* Proper field inversion for bigints ([#4802](https://github.com/noir-lang/noir/issues/4802)) ([b46d0e3](https://github.com/noir-lang/noir/commit/b46d0e39f4252f8bbaa987f88d112e4c233b3d61)) +* Remove panic from `init_log_level` in `acvm_js` ([#4195](https://github.com/noir-lang/noir/issues/4195)) ([2e26530](https://github.com/noir-lang/noir/commit/2e26530bf53006c1ed4fee310bcaa905c95dd95b)) +* Return error rather instead of panicking on invalid circuit ([#3976](https://github.com/noir-lang/noir/issues/3976)) ([67201bf](https://github.com/noir-lang/noir/commit/67201bfc21a9c8858aa86be9cd47d463fb78d925)) + + +### Miscellaneous Chores + +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Move noir out of yarn-project (https://github.com/AztecProtocol/aztec-packages/pull/4479) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Remove fixed-length keccak256 (https://github.com/AztecProtocol/aztec-packages/pull/5617) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) + +## [0.44.0](https://github.com/noir-lang/noir/compare/v0.43.0...v0.44.0) (2024-04-24) + + +### ⚠ BREAKING CHANGES + +* contract interfaces and better function calls (https://github.com/AztecProtocol/aztec-packages/pull/5687) +* change backend width to 4 (https://github.com/AztecProtocol/aztec-packages/pull/5374) +* Use fixed size arrays in black box functions where sizes are known (https://github.com/AztecProtocol/aztec-packages/pull/5620) +* trap with revert data (https://github.com/AztecProtocol/aztec-packages/pull/5732) +* **acir:** BrilligCall opcode (https://github.com/AztecProtocol/aztec-packages/pull/5709) +* remove fixed-length keccak256 (https://github.com/AztecProtocol/aztec-packages/pull/5617) +* storage_layout and `#[aztec(storage)]` (https://github.com/AztecProtocol/aztec-packages/pull/5387) +* **acir:** Add predicate to call opcode (https://github.com/AztecProtocol/aztec-packages/pull/5616) +* contract_abi-exports (https://github.com/AztecProtocol/aztec-packages/pull/5386) +* Brillig typed memory (https://github.com/AztecProtocol/aztec-packages/pull/5395) +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) +* automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) +* Internal as a macro (https://github.com/AztecProtocol/aztec-packages/pull/4898) +* move noir out of yarn-project (https://github.com/AztecProtocol/aztec-packages/pull/4479) +* note type ids (https://github.com/AztecProtocol/aztec-packages/pull/4500) +* rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) +* init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) +* Sync commits from `aztec-packages` ([#4144](https://github.com/noir-lang/noir/issues/4144)) +* Breaking changes from aztec-packages ([#3955](https://github.com/noir-lang/noir/issues/3955)) + +### Features + +* Acir call opcode (https://github.com/AztecProtocol/aztec-packages/pull/4773) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **acir_gen:** Brillig stdlib ([#4848](https://github.com/noir-lang/noir/issues/4848)) ([0c8175c](https://github.com/noir-lang/noir/commit/0c8175cb539efd9427c73ae5af0d48abe688ebab)) +* **acir_gen:** Fold attribute at compile-time and initial non inlined ACIR (https://github.com/AztecProtocol/aztec-packages/pull/5341) ([a0f7474](https://github.com/noir-lang/noir/commit/a0f7474ae6bd74132efdb945d2eb2383f3913cce)) +* **acir:** Add predicate to call opcode (https://github.com/AztecProtocol/aztec-packages/pull/5616) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* **acir:** BrilligCall opcode (https://github.com/AztecProtocol/aztec-packages/pull/5709) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* **acir:** Program and witness stack structure (https://github.com/AztecProtocol/aztec-packages/pull/5149) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* **acvm_js:** Execute program ([#4694](https://github.com/noir-lang/noir/issues/4694)) ([386f6d0](https://github.com/noir-lang/noir/commit/386f6d0a5822912db878285cb001032a7c0ff622)) +* **acvm:** Execute multiple circuits (https://github.com/AztecProtocol/aztec-packages/pull/5380) ([a0f7474](https://github.com/noir-lang/noir/commit/a0f7474ae6bd74132efdb945d2eb2383f3913cce)) +* Add bit size to const opcode (https://github.com/AztecProtocol/aztec-packages/pull/4385) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Add CMOV instruction to brillig and brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5308) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Add instrumentation for tracking variables in debugging ([#4122](https://github.com/noir-lang/noir/issues/4122)) ([c58d691](https://github.com/noir-lang/noir/commit/c58d69141b54a918cd1675400c00bfd48720f896)) +* Add poseidon2 opcode implementation for acvm/brillig, and Noir ([#4398](https://github.com/noir-lang/noir/issues/4398)) ([10e8292](https://github.com/noir-lang/noir/commit/10e82920798380f50046e52db4a20ca205191ab7)) +* Add return values to aztec fns (https://github.com/AztecProtocol/aztec-packages/pull/5389) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Add support for overriding expression width ([#4117](https://github.com/noir-lang/noir/issues/4117)) ([c8026d5](https://github.com/noir-lang/noir/commit/c8026d557d535b10fe455165d6445076df7a03de)) +* Added cast opcode and cast calldata (https://github.com/AztecProtocol/aztec-packages/pull/4423) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Allow brillig to read arrays directly from memory (https://github.com/AztecProtocol/aztec-packages/pull/4460) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Allow nested arrays and vectors in Brillig foreign calls (https://github.com/AztecProtocol/aztec-packages/pull/4478) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Allow variables and stack trace inspection in the debugger ([#4184](https://github.com/noir-lang/noir/issues/4184)) ([bf263fc](https://github.com/noir-lang/noir/commit/bf263fc8d843940f328a90f6366edd2671fb2682)) +* Automatic NoteInterface and NoteGetterOptions auto select (https://github.com/AztecProtocol/aztec-packages/pull/4508) ([13eb71b](https://github.com/noir-lang/noir/commit/13eb71b8de44eb6aad9c37943ad06fc73db589f5)) +* **avm:** Back in avm context with macro - refactor context (https://github.com/AztecProtocol/aztec-packages/pull/4438) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* **avm:** Brillig CONST of size > u128 (https://github.com/AztecProtocol/aztec-packages/pull/5217) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **avm:** Integrate AVM with initializers (https://github.com/AztecProtocol/aztec-packages/pull/5469) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* **aztec-nr:** Initial work for aztec public vm macro (https://github.com/AztecProtocol/aztec-packages/pull/4400) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Backpropagate constants in ACIR during optimization ([#3926](https://github.com/noir-lang/noir/issues/3926)) ([aad0da0](https://github.com/noir-lang/noir/commit/aad0da024c69663f42e6913e674682d5864b26ae)) +* Breaking changes from aztec-packages ([#3955](https://github.com/noir-lang/noir/issues/3955)) ([5be049e](https://github.com/noir-lang/noir/commit/5be049eee6c342649462282ee04f6411e6ea392c)) +* Brillig heterogeneous memory cells (https://github.com/AztecProtocol/aztec-packages/pull/5608) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Brillig IR refactor (https://github.com/AztecProtocol/aztec-packages/pull/5233) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Brillig pointer codegen and execution (https://github.com/AztecProtocol/aztec-packages/pull/5737) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Brillig typed memory (https://github.com/AztecProtocol/aztec-packages/pull/5395) ([0bc18c4](https://github.com/noir-lang/noir/commit/0bc18c4f78171590dd58bded959f68f53a44cc8c)) +* Change backend width to 4 (https://github.com/AztecProtocol/aztec-packages/pull/5374) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Check initializer msg.sender matches deployer from address preimage (https://github.com/AztecProtocol/aztec-packages/pull/5222) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Contract interfaces and better function calls (https://github.com/AztecProtocol/aztec-packages/pull/5687) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Contract_abi-exports (https://github.com/AztecProtocol/aztec-packages/pull/5386) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Evaluation of dynamic assert messages ([#4101](https://github.com/noir-lang/noir/issues/4101)) ([c284e01](https://github.com/noir-lang/noir/commit/c284e01bfe20ceae4414dc123624b5cbb8b66d09)) +* Impl of missing functionality in new key store (https://github.com/AztecProtocol/aztec-packages/pull/5750) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Initial Earthly CI (https://github.com/AztecProtocol/aztec-packages/pull/5069) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Internal as a macro (https://github.com/AztecProtocol/aztec-packages/pull/4898) ([5f57ebb](https://github.com/noir-lang/noir/commit/5f57ebb7ff4b810802f90699a10f4325ef904f2e)) +* **nargo:** Handle call stacks for multiple Acir calls ([#4711](https://github.com/noir-lang/noir/issues/4711)) ([5b23171](https://github.com/noir-lang/noir/commit/5b231714740447d82cde7cdbe65d4a8b46a31df4)) +* New brillig field operations and refactor of binary operations (https://github.com/AztecProtocol/aztec-packages/pull/5208) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Note type ids (https://github.com/AztecProtocol/aztec-packages/pull/4500) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Remove range constraints from witnesses which are constrained to be constants ([#3928](https://github.com/noir-lang/noir/issues/3928)) ([afe9c7a](https://github.com/noir-lang/noir/commit/afe9c7a38bb9d4245205d3aa46d4ce23d70a5671)) +* Remove replacement of boolean range opcodes with `AssertZero` opcodes ([#4107](https://github.com/noir-lang/noir/issues/4107)) ([dac0e87](https://github.com/noir-lang/noir/commit/dac0e87ee3be3446b92bbb12ef4832fd493fcee3)) +* Restore hashing args via slice for performance (https://github.com/AztecProtocol/aztec-packages/pull/5539) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Signed integer division and modulus in brillig gen (https://github.com/AztecProtocol/aztec-packages/pull/5279) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* **simulator:** Fetch return values at circuit execution (https://github.com/AztecProtocol/aztec-packages/pull/5642) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Storage_layout and `#[aztec(storage)]` (https://github.com/AztecProtocol/aztec-packages/pull/5387) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Support contracts with no constructor (https://github.com/AztecProtocol/aztec-packages/pull/5175) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync `aztec-packages` ([#4011](https://github.com/noir-lang/noir/issues/4011)) ([fee2452](https://github.com/noir-lang/noir/commit/fee24523c427c27f0bdaf98ea09a852a2da3e94c)) +* Sync commits from `aztec-packages` ([#4068](https://github.com/noir-lang/noir/issues/4068)) ([7a8f3a3](https://github.com/noir-lang/noir/commit/7a8f3a33b57875e681e3d81e667e3570a1cdbdcc)) +* Sync commits from `aztec-packages` ([#4144](https://github.com/noir-lang/noir/issues/4144)) ([0205d3b](https://github.com/noir-lang/noir/commit/0205d3b4ad0cf5ffd775a43eb5af273a772cf138)) +* Sync from aztec-packages ([#4483](https://github.com/noir-lang/noir/issues/4483)) ([fe8f277](https://github.com/noir-lang/noir/commit/fe8f2776ccfde29209a2c3fc162311c99e4f59be)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5234) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5286) ([c3c9e19](https://github.com/noir-lang/noir/commit/c3c9e19a20d61272a04b95fd6c7d34cc4cb96e45)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5572) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5619) ([2bd006a](https://github.com/noir-lang/noir/commit/2bd006ae07499e8702b0fa9565855f0a5ef1a589)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5697) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5794) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5814) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5935) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5955) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/5999) ([1b867b1](https://github.com/noir-lang/noir/commit/1b867b121fba5db3087ca845b4934e6732b23fd1)) +* Trap with revert data (https://github.com/AztecProtocol/aztec-packages/pull/5732) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Use fixed size arrays in black box functions where sizes are known (https://github.com/AztecProtocol/aztec-packages/pull/5620) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Variable length returns (https://github.com/AztecProtocol/aztec-packages/pull/5633) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) + + +### Bug Fixes + +* **acvm:** Mark outputs of Opcode::Call solvable ([#4708](https://github.com/noir-lang/noir/issues/4708)) ([8fea405](https://github.com/noir-lang/noir/commit/8fea40576f262bd5bb588923c0660d8967404e56)) +* Avoid huge unrolling in hash_args (https://github.com/AztecProtocol/aztec-packages/pull/5703) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Catch panics from EC point creation (e.g. the point is at infinity) ([#4790](https://github.com/noir-lang/noir/issues/4790)) ([645dba1](https://github.com/noir-lang/noir/commit/645dba192f16ef34018828186ffb297422a8dc73)) +* Don't reuse brillig with slice arguments (https://github.com/AztecProtocol/aztec-packages/pull/5800) ([0f9ae0a](https://github.com/noir-lang/noir/commit/0f9ae0ac1d68714b56ba4524aedcc67212494f1b)) +* Issue 4682 and add solver for unconstrained bigintegers ([#4729](https://github.com/noir-lang/noir/issues/4729)) ([e4d33c1](https://github.com/noir-lang/noir/commit/e4d33c126a2795d9aaa6048d4e91b64cb4bbe4f2)) +* Noir test incorrect reporting (https://github.com/AztecProtocol/aztec-packages/pull/4925) ([5f57ebb](https://github.com/noir-lang/noir/commit/5f57ebb7ff4b810802f90699a10f4325ef904f2e)) +* Proper field inversion for bigints ([#4802](https://github.com/noir-lang/noir/issues/4802)) ([b46d0e3](https://github.com/noir-lang/noir/commit/b46d0e39f4252f8bbaa987f88d112e4c233b3d61)) +* Remove panic from `init_log_level` in `acvm_js` ([#4195](https://github.com/noir-lang/noir/issues/4195)) ([2e26530](https://github.com/noir-lang/noir/commit/2e26530bf53006c1ed4fee310bcaa905c95dd95b)) +* Return error rather instead of panicking on invalid circuit ([#3976](https://github.com/noir-lang/noir/issues/3976)) ([67201bf](https://github.com/noir-lang/noir/commit/67201bfc21a9c8858aa86be9cd47d463fb78d925)) + + +### Miscellaneous Chores + +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) +* Move noir out of yarn-project (https://github.com/AztecProtocol/aztec-packages/pull/4479) ([78ef013](https://github.com/noir-lang/noir/commit/78ef0134b82e76a73dadb6c7975def22290e3a1a)) +* Remove fixed-length keccak256 (https://github.com/AztecProtocol/aztec-packages/pull/5617) ([305bcdc](https://github.com/noir-lang/noir/commit/305bcdcbd01cb84dbaac900f14cb6cf867f83bda)) +* Rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) ([158c8ce](https://github.com/noir-lang/noir/commit/158c8cec7f0dc698042e9512001dd2c9d6b40bcc)) + ## [0.43.0](https://github.com/noir-lang/noir/compare/v0.42.0...v0.43.0) (2024-04-10) diff --git a/acvm-repo/acir/Cargo.toml b/acvm-repo/acir/Cargo.toml index d6990f83281..9e1a2f940c4 100644 --- a/acvm-repo/acir/Cargo.toml +++ b/acvm-repo/acir/Cargo.toml @@ -2,7 +2,7 @@ name = "acir" description = "ACIR is the IR that the VM processes, it is analogous to LLVM IR" # x-release-please-start-version -version = "0.43.0" +version = "0.45.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acir/README.md b/acvm-repo/acir/README.md index 801aeac1140..f7fccad0799 100644 --- a/acvm-repo/acir/README.md +++ b/acvm-repo/acir/README.md @@ -76,6 +76,12 @@ Some more advanced computations assume that the proving system has an 'embedded The black box functions supported by ACIR are: +**AES128Encrypt**: ciphers the provided plaintext using AES128 in CBC mode, padding the input using PKCS#7. +- inputs: byte array [u8; N] +- iv: initialization vector [u8; 16] +- key: user key [u8; 16] +- outputs: byte vector [u8] of length `input.len() + (16 - input.len() % 16)`` + **AND**: performs the bitwise AND of lhs and rhs. bit_size must be the same for both inputs. - lhs: (witness, bit_size) - rhs: (witness, bit_size) @@ -139,9 +145,11 @@ Inputs and outputs are similar to SchnorrVerify, except that because we use a di **EcdsaSecp256r1**: Same as EcdsaSecp256k1, but done over another curve. -**FixedBaseScalarMul**: scalar multiplication with a fixed generator of the embedded curve -- input: low, high are 2 (field , 254), representing the low and high part of the input. For Barretenberg, they must both be less than 128 bits. -- output: x and y coordinates of $low*G+high*2^{128}*G$, where G is a fixed generator +**MultiScalarMul**: scalar multiplication with a variable base/input point (P) of the embedded curve +- input: + points (FieldElement, N) a vector of x and y coordinates of input points [x1, y1, x2, y2,...]. + scalars (FieldElement, N) a vector of low and high limbs of input scalars [s1_low, s1_high, s2_low, s2_high, ...]. (FieldElement, N) For Barretenberg, they must both be less than 128 bits. +- output: (FieldElement, N) a vector of x and y coordinates of output points [op1_x, op1_y, op2_x, op2_y, ...]. Points computed as $s_low*P+s_high*2^{128}*P$ Because the Grumpkin scalar field is bigger than the ACIR field, we provide 2 ACIR fields representing the low and high parts of the Grumpkin scalar $a$: $a=low+high*2^{128},$ with $low, high < 2^{128}$ diff --git a/acvm-repo/acir/benches/serialization.rs b/acvm-repo/acir/benches/serialization.rs index 73e3916a73b..e51726e3901 100644 --- a/acvm-repo/acir/benches/serialization.rs +++ b/acvm-repo/acir/benches/serialization.rs @@ -40,6 +40,7 @@ fn sample_program(num_opcodes: usize) -> Program { assert_messages: Vec::new(), recursive: false, }], + unconstrained_functions: Vec::new(), } } diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index 6c7bd347e5d..b7e75c4320d 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -24,6 +24,17 @@ namespace Program { struct BlackBoxFuncCall { + struct AES128Encrypt { + std::vector inputs; + std::array iv; + std::array key; + std::vector outputs; + + friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); + std::vector bincodeSerialize() const; + static AES128Encrypt bincodeDeserialize(std::vector); + }; + struct AND { Program::FunctionInput lhs; Program::FunctionInput rhs; @@ -135,14 +146,14 @@ namespace Program { static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Program::FunctionInput low; - Program::FunctionInput high; + struct MultiScalarMul { + std::vector points; + std::vector scalars; std::array outputs; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const MultiScalarMul&, const MultiScalarMul&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static MultiScalarMul bincodeDeserialize(std::vector); }; struct EmbeddedCurveAdd { @@ -266,7 +277,7 @@ namespace Program { static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; @@ -324,6 +335,134 @@ namespace Program { static BrilligInputs bincodeDeserialize(std::vector); }; + struct BrilligOutputs { + + struct Simple { + Program::Witness value; + + friend bool operator==(const Simple&, const Simple&); + std::vector bincodeSerialize() const; + static Simple bincodeDeserialize(std::vector); + }; + + struct Array { + std::vector value; + + friend bool operator==(const Array&, const Array&); + std::vector bincodeSerialize() const; + static Array bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BrilligOutputs&, const BrilligOutputs&); + std::vector bincodeSerialize() const; + static BrilligOutputs bincodeDeserialize(std::vector); + }; + + struct Directive { + + struct ToLeRadix { + Program::Expression a; + std::vector b; + uint32_t radix; + + friend bool operator==(const ToLeRadix&, const ToLeRadix&); + std::vector bincodeSerialize() const; + static ToLeRadix bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const Directive&, const Directive&); + std::vector bincodeSerialize() const; + static Directive bincodeDeserialize(std::vector); + }; + + struct MemOp { + Program::Expression operation; + Program::Expression index; + Program::Expression value; + + friend bool operator==(const MemOp&, const MemOp&); + std::vector bincodeSerialize() const; + static MemOp bincodeDeserialize(std::vector); + }; + + struct Opcode { + + struct AssertZero { + Program::Expression value; + + friend bool operator==(const AssertZero&, const AssertZero&); + std::vector bincodeSerialize() const; + static AssertZero bincodeDeserialize(std::vector); + }; + + struct BlackBoxFuncCall { + Program::BlackBoxFuncCall value; + + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); + std::vector bincodeSerialize() const; + static BlackBoxFuncCall bincodeDeserialize(std::vector); + }; + + struct Directive { + Program::Directive value; + + friend bool operator==(const Directive&, const Directive&); + std::vector bincodeSerialize() const; + static Directive bincodeDeserialize(std::vector); + }; + + struct MemoryOp { + Program::BlockId block_id; + Program::MemOp op; + std::optional predicate; + + friend bool operator==(const MemoryOp&, const MemoryOp&); + std::vector bincodeSerialize() const; + static MemoryOp bincodeDeserialize(std::vector); + }; + + struct MemoryInit { + Program::BlockId block_id; + std::vector init; + + friend bool operator==(const MemoryInit&, const MemoryInit&); + std::vector bincodeSerialize() const; + static MemoryInit bincodeDeserialize(std::vector); + }; + + struct BrilligCall { + uint32_t id; + std::vector inputs; + std::vector outputs; + std::optional predicate; + + friend bool operator==(const BrilligCall&, const BrilligCall&); + std::vector bincodeSerialize() const; + static BrilligCall bincodeDeserialize(std::vector); + }; + + struct Call { + uint32_t id; + std::vector inputs; + std::vector outputs; + std::optional predicate; + + friend bool operator==(const Call&, const Call&); + std::vector bincodeSerialize() const; + static Call bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const Opcode&, const Opcode&); + std::vector bincodeSerialize() const; + static Opcode bincodeDeserialize(std::vector); + }; + struct BinaryFieldOp { struct Add { @@ -490,6 +629,17 @@ namespace Program { struct BlackBoxOp { + struct AES128Encrypt { + Program::HeapVector inputs; + Program::HeapArray iv; + Program::HeapArray key; + Program::HeapVector outputs; + + friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); + std::vector bincodeSerialize() const; + static AES128Encrypt bincodeDeserialize(std::vector); + }; + struct Sha256 { Program::HeapVector message; Program::HeapArray output; @@ -591,14 +741,14 @@ namespace Program { static PedersenHash bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Program::MemoryAddress low; - Program::MemoryAddress high; - Program::HeapArray result; + struct MultiScalarMul { + Program::HeapVector points; + Program::HeapVector scalars; + Program::HeapArray outputs; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const MultiScalarMul&, const MultiScalarMul&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static MultiScalarMul bincodeDeserialize(std::vector); }; struct EmbeddedCurveAdd { @@ -692,7 +842,7 @@ namespace Program { static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; @@ -922,8 +1072,7 @@ namespace Program { }; struct Trap { - uint64_t revert_data_offset; - uint64_t revert_data_size; + Program::HeapArray revert_data; friend bool operator==(const Trap&, const Trap&); std::vector bincodeSerialize() const; @@ -946,151 +1095,54 @@ namespace Program { static BrilligOpcode bincodeDeserialize(std::vector); }; - struct BrilligOutputs { - - struct Simple { - Program::Witness value; + struct ExpressionOrMemory { - friend bool operator==(const Simple&, const Simple&); - std::vector bincodeSerialize() const; - static Simple bincodeDeserialize(std::vector); - }; - - struct Array { - std::vector value; + struct Expression { + Program::Expression value; - friend bool operator==(const Array&, const Array&); + friend bool operator==(const Expression&, const Expression&); std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); + static Expression bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BrilligOutputs&, const BrilligOutputs&); - std::vector bincodeSerialize() const; - static BrilligOutputs bincodeDeserialize(std::vector); - }; - - struct Brillig { - std::vector inputs; - std::vector outputs; - std::vector bytecode; - std::optional predicate; - - friend bool operator==(const Brillig&, const Brillig&); - std::vector bincodeSerialize() const; - static Brillig bincodeDeserialize(std::vector); - }; - - struct Directive { - - struct ToLeRadix { - Program::Expression a; - std::vector b; - uint32_t radix; + struct Memory { + Program::BlockId value; - friend bool operator==(const ToLeRadix&, const ToLeRadix&); + friend bool operator==(const Memory&, const Memory&); std::vector bincodeSerialize() const; - static ToLeRadix bincodeDeserialize(std::vector); + static Memory bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const Directive&, const Directive&); + friend bool operator==(const ExpressionOrMemory&, const ExpressionOrMemory&); std::vector bincodeSerialize() const; - static Directive bincodeDeserialize(std::vector); - }; - - struct MemOp { - Program::Expression operation; - Program::Expression index; - Program::Expression value; - - friend bool operator==(const MemOp&, const MemOp&); - std::vector bincodeSerialize() const; - static MemOp bincodeDeserialize(std::vector); + static ExpressionOrMemory bincodeDeserialize(std::vector); }; - struct Opcode { - - struct AssertZero { - Program::Expression value; + struct AssertionPayload { - friend bool operator==(const AssertZero&, const AssertZero&); - std::vector bincodeSerialize() const; - static AssertZero bincodeDeserialize(std::vector); - }; - - struct BlackBoxFuncCall { - Program::BlackBoxFuncCall value; - - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; - - struct Directive { - Program::Directive value; - - friend bool operator==(const Directive&, const Directive&); - std::vector bincodeSerialize() const; - static Directive bincodeDeserialize(std::vector); - }; - - struct Brillig { - Program::Brillig value; - - friend bool operator==(const Brillig&, const Brillig&); - std::vector bincodeSerialize() const; - static Brillig bincodeDeserialize(std::vector); - }; - - struct MemoryOp { - Program::BlockId block_id; - Program::MemOp op; - std::optional predicate; - - friend bool operator==(const MemoryOp&, const MemoryOp&); - std::vector bincodeSerialize() const; - static MemoryOp bincodeDeserialize(std::vector); - }; - - struct MemoryInit { - Program::BlockId block_id; - std::vector init; - - friend bool operator==(const MemoryInit&, const MemoryInit&); - std::vector bincodeSerialize() const; - static MemoryInit bincodeDeserialize(std::vector); - }; - - struct BrilligCall { - uint32_t id; - std::vector inputs; - std::vector outputs; - std::optional predicate; + struct StaticString { + std::string value; - friend bool operator==(const BrilligCall&, const BrilligCall&); + friend bool operator==(const StaticString&, const StaticString&); std::vector bincodeSerialize() const; - static BrilligCall bincodeDeserialize(std::vector); + static StaticString bincodeDeserialize(std::vector); }; - struct Call { - uint32_t id; - std::vector inputs; - std::vector outputs; - std::optional predicate; + struct Dynamic { + std::tuple> value; - friend bool operator==(const Call&, const Call&); + friend bool operator==(const Dynamic&, const Dynamic&); std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); + static Dynamic bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const Opcode&, const Opcode&); + friend bool operator==(const AssertionPayload&, const AssertionPayload&); std::vector bincodeSerialize() const; - static Opcode bincodeDeserialize(std::vector); + static AssertionPayload bincodeDeserialize(std::vector); }; struct ExpressionWidth { @@ -1157,7 +1209,7 @@ namespace Program { std::vector private_parameters; Program::PublicInputs public_parameters; Program::PublicInputs return_values; - std::vector> assert_messages; + std::vector> assert_messages; bool recursive; friend bool operator==(const Circuit&, const Circuit&); @@ -1185,6 +1237,124 @@ namespace Program { } // end of namespace Program +namespace Program { + + inline bool operator==(const AssertionPayload &lhs, const AssertionPayload &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector AssertionPayload::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline AssertionPayload AssertionPayload::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::AssertionPayload &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Program::AssertionPayload serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Program::AssertionPayload obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Program { + + inline bool operator==(const AssertionPayload::StaticString &lhs, const AssertionPayload::StaticString &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector AssertionPayload::StaticString::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline AssertionPayload::StaticString AssertionPayload::StaticString::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::AssertionPayload::StaticString &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::AssertionPayload::StaticString serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::AssertionPayload::StaticString obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + + inline bool operator==(const AssertionPayload::Dynamic &lhs, const AssertionPayload::Dynamic &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector AssertionPayload::Dynamic::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline AssertionPayload::Dynamic AssertionPayload::Dynamic::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::AssertionPayload::Dynamic &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::AssertionPayload::Dynamic serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::AssertionPayload::Dynamic obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const BinaryFieldOp &lhs, const BinaryFieldOp &rhs) { @@ -2011,6 +2181,53 @@ Program::BlackBoxFuncCall serde::Deserializable::dese return obj; } +namespace Program { + + inline bool operator==(const BlackBoxFuncCall::AES128Encrypt &lhs, const BlackBoxFuncCall::AES128Encrypt &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.iv == rhs.iv)) { return false; } + if (!(lhs.key == rhs.key)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } + return true; + } + + inline std::vector BlackBoxFuncCall::AES128Encrypt::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxFuncCall::AES128Encrypt BlackBoxFuncCall::AES128Encrypt::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::AES128Encrypt &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.iv, serializer); + serde::Serializable::serialize(obj.key, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Program::BlackBoxFuncCall::AES128Encrypt serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::AES128Encrypt obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.iv = serde::Deserializable::deserialize(deserializer); + obj.key = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const BlackBoxFuncCall::AND &lhs, const BlackBoxFuncCall::AND &rhs) { @@ -2500,22 +2717,22 @@ Program::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable BlackBoxFuncCall::FixedBaseScalarMul::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::MultiScalarMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::FixedBaseScalarMul BlackBoxFuncCall::FixedBaseScalarMul::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::MultiScalarMul BlackBoxFuncCall::MultiScalarMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2526,18 +2743,18 @@ namespace Program { template <> template -void serde::Serializable::serialize(const Program::BlackBoxFuncCall::FixedBaseScalarMul &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.low, serializer); - serde::Serializable::serialize(obj.high, serializer); +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::MultiScalarMul &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.points, serializer); + serde::Serializable::serialize(obj.scalars, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Program::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BlackBoxFuncCall::FixedBaseScalarMul obj; - obj.low = serde::Deserializable::deserialize(deserializer); - obj.high = serde::Deserializable::deserialize(deserializer); +Program::BlackBoxFuncCall::MultiScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::MultiScalarMul obj; + obj.points = serde::Deserializable::deserialize(deserializer); + obj.scalars = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } @@ -3115,6 +3332,53 @@ Program::BlackBoxOp serde::Deserializable::deserialize(Dese return obj; } +namespace Program { + + inline bool operator==(const BlackBoxOp::AES128Encrypt &lhs, const BlackBoxOp::AES128Encrypt &rhs) { + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.iv == rhs.iv)) { return false; } + if (!(lhs.key == rhs.key)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } + return true; + } + + inline std::vector BlackBoxOp::AES128Encrypt::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxOp::AES128Encrypt BlackBoxOp::AES128Encrypt::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BlackBoxOp::AES128Encrypt &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.iv, serializer); + serde::Serializable::serialize(obj.key, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Program::BlackBoxOp::AES128Encrypt serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::AES128Encrypt obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.iv = serde::Deserializable::deserialize(deserializer); + obj.key = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const BlackBoxOp::Sha256 &lhs, const BlackBoxOp::Sha256 &rhs) { @@ -3560,22 +3824,22 @@ Program::BlackBoxOp::PedersenHash serde::Deserializable BlackBoxOp::FixedBaseScalarMul::bincodeSerialize() const { + inline std::vector BlackBoxOp::MultiScalarMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::FixedBaseScalarMul BlackBoxOp::FixedBaseScalarMul::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::MultiScalarMul BlackBoxOp::MultiScalarMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3586,19 +3850,19 @@ namespace Program { template <> template -void serde::Serializable::serialize(const Program::BlackBoxOp::FixedBaseScalarMul &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.low, serializer); - serde::Serializable::serialize(obj.high, serializer); - serde::Serializable::serialize(obj.result, serializer); +void serde::Serializable::serialize(const Program::BlackBoxOp::MultiScalarMul &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.points, serializer); + serde::Serializable::serialize(obj.scalars, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Program::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BlackBoxOp::FixedBaseScalarMul obj; - obj.low = serde::Deserializable::deserialize(deserializer); - obj.high = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); +Program::BlackBoxOp::MultiScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::MultiScalarMul obj; + obj.points = serde::Deserializable::deserialize(deserializer); + obj.scalars = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4043,57 +4307,6 @@ Program::BlockId serde::Deserializable::deserialize(Deserializ return obj; } -namespace Program { - - inline bool operator==(const Brillig &lhs, const Brillig &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { return false; } - if (!(lhs.bytecode == rhs.bytecode)) { return false; } - if (!(lhs.predicate == rhs.predicate)) { return false; } - return true; - } - - inline std::vector Brillig::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline Brillig Brillig::bincodeDeserialize(std::vector input) { - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw serde::deserialization_error("Some input bytes were not read"); - } - return value; - } - -} // end of namespace Program - -template <> -template -void serde::Serializable::serialize(const Program::Brillig &obj, Serializer &serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.outputs, serializer); - serde::Serializable::serialize(obj.bytecode, serializer); - serde::Serializable::serialize(obj.predicate, serializer); - serializer.decrease_container_depth(); -} - -template <> -template -Program::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { - deserializer.increase_container_depth(); - Program::Brillig obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); - obj.bytecode = serde::Deserializable::deserialize(deserializer); - obj.predicate = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); - return obj; -} - namespace Program { inline bool operator==(const BrilligBytecode &lhs, const BrilligBytecode &rhs) { @@ -5017,8 +5230,7 @@ Program::BrilligOpcode::BlackBox serde::Deserializable template void serde::Serializable::serialize(const Program::BrilligOpcode::Trap &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.revert_data_offset, serializer); - serde::Serializable::serialize(obj.revert_data_size, serializer); + serde::Serializable::serialize(obj.revert_data, serializer); } template <> template Program::BrilligOpcode::Trap serde::Deserializable::deserialize(Deserializer &deserializer) { Program::BrilligOpcode::Trap obj; - obj.revert_data_offset = serde::Deserializable::deserialize(deserializer); - obj.revert_data_size = serde::Deserializable::deserialize(deserializer); + obj.revert_data = serde::Deserializable::deserialize(deserializer); return obj; } @@ -5411,6 +5621,124 @@ Program::Expression serde::Deserializable::deserialize(Dese return obj; } +namespace Program { + + inline bool operator==(const ExpressionOrMemory &lhs, const ExpressionOrMemory &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector ExpressionOrMemory::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionOrMemory ExpressionOrMemory::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::ExpressionOrMemory &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Program::ExpressionOrMemory serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Program::ExpressionOrMemory obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Program { + + inline bool operator==(const ExpressionOrMemory::Expression &lhs, const ExpressionOrMemory::Expression &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector ExpressionOrMemory::Expression::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionOrMemory::Expression ExpressionOrMemory::Expression::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::ExpressionOrMemory::Expression &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::ExpressionOrMemory::Expression serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::ExpressionOrMemory::Expression obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + + inline bool operator==(const ExpressionOrMemory::Memory &lhs, const ExpressionOrMemory::Memory &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector ExpressionOrMemory::Memory::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionOrMemory::Memory ExpressionOrMemory::Memory::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::ExpressionOrMemory::Memory &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::ExpressionOrMemory::Memory serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::ExpressionOrMemory::Memory obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const ExpressionWidth &lhs, const ExpressionWidth &rhs) { @@ -6066,44 +6394,6 @@ Program::Opcode::Directive serde::Deserializable::de return obj; } -namespace Program { - - inline bool operator==(const Opcode::Brillig &lhs, const Opcode::Brillig &rhs) { - if (!(lhs.value == rhs.value)) { return false; } - return true; - } - - inline std::vector Opcode::Brillig::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline Opcode::Brillig Opcode::Brillig::bincodeDeserialize(std::vector input) { - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw serde::deserialization_error("Some input bytes were not read"); - } - return value; - } - -} // end of namespace Program - -template <> -template -void serde::Serializable::serialize(const Program::Opcode::Brillig &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.value, serializer); -} - -template <> -template -Program::Opcode::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::Opcode::Brillig obj; - obj.value = serde::Deserializable::deserialize(deserializer); - return obj; -} - namespace Program { inline bool operator==(const Opcode::MemoryOp &lhs, const Opcode::MemoryOp &rhs) { diff --git a/acvm-repo/acir/src/circuit/black_box_functions.rs b/acvm-repo/acir/src/circuit/black_box_functions.rs index 0a7ee244a5e..33c14436c85 100644 --- a/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -9,6 +9,8 @@ use strum_macros::EnumIter; #[derive(Clone, Debug, Hash, Copy, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(test, derive(EnumIter))] pub enum BlackBoxFunc { + /// Encrypts the input using AES128. + AES128Encrypt, /// Bitwise AND. AND, /// Bitwise XOR. @@ -36,8 +38,8 @@ pub enum BlackBoxFunc { EcdsaSecp256k1, /// Verifies a ECDSA signature over the secp256r1 curve. EcdsaSecp256r1, - /// Performs scalar multiplication over the embedded curve on which [`FieldElement`][acir_field::FieldElement] is defined. - FixedBaseScalarMul, + /// Performs multi scalar multiplication over the embedded curve. + MultiScalarMul, /// Calculates the Keccak256 hash of the inputs. Keccak256, /// Keccak Permutation function of 1600 width @@ -74,6 +76,7 @@ impl std::fmt::Display for BlackBoxFunc { impl BlackBoxFunc { pub fn name(&self) -> &'static str { match self { + BlackBoxFunc::AES128Encrypt => "aes128_encrypt", BlackBoxFunc::SHA256 => "sha256", BlackBoxFunc::SchnorrVerify => "schnorr_verify", BlackBoxFunc::Blake2s => "blake2s", @@ -81,7 +84,7 @@ impl BlackBoxFunc { BlackBoxFunc::PedersenCommitment => "pedersen_commitment", BlackBoxFunc::PedersenHash => "pedersen_hash", BlackBoxFunc::EcdsaSecp256k1 => "ecdsa_secp256k1", - BlackBoxFunc::FixedBaseScalarMul => "fixed_base_scalar_mul", + BlackBoxFunc::MultiScalarMul => "multi_scalar_mul", BlackBoxFunc::EmbeddedCurveAdd => "embedded_curve_add", BlackBoxFunc::AND => "and", BlackBoxFunc::XOR => "xor", @@ -103,6 +106,7 @@ impl BlackBoxFunc { pub fn lookup(op_name: &str) -> Option { match op_name { + "aes128_encrypt" => Some(BlackBoxFunc::AES128Encrypt), "sha256" => Some(BlackBoxFunc::SHA256), "schnorr_verify" => Some(BlackBoxFunc::SchnorrVerify), "blake2s" => Some(BlackBoxFunc::Blake2s), @@ -111,7 +115,7 @@ impl BlackBoxFunc { "pedersen_hash" => Some(BlackBoxFunc::PedersenHash), "ecdsa_secp256k1" => Some(BlackBoxFunc::EcdsaSecp256k1), "ecdsa_secp256r1" => Some(BlackBoxFunc::EcdsaSecp256r1), - "fixed_base_scalar_mul" => Some(BlackBoxFunc::FixedBaseScalarMul), + "multi_scalar_mul" => Some(BlackBoxFunc::MultiScalarMul), "embedded_curve_add" => Some(BlackBoxFunc::EmbeddedCurveAdd), "and" => Some(BlackBoxFunc::AND), "xor" => Some(BlackBoxFunc::XOR), diff --git a/acvm-repo/acir/src/circuit/brillig.rs b/acvm-repo/acir/src/circuit/brillig.rs index 7f87aabf9d5..ecf6f7a9761 100644 --- a/acvm-repo/acir/src/circuit/brillig.rs +++ b/acvm-repo/acir/src/circuit/brillig.rs @@ -20,16 +20,6 @@ pub enum BrilligOutputs { Array(Vec), } -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] -pub struct Brillig { - pub inputs: Vec, - pub outputs: Vec, - /// The Brillig VM bytecode to be executed by this ACIR opcode. - pub bytecode: Vec, - /// Predicate of the Brillig execution - indicates if it should be skipped - pub predicate: Option, -} - /// This is purely a wrapper struct around a list of Brillig opcode's which represents /// a full Brillig function to be executed by the Brillig VM. /// This is stored separately on a program and accessed through a [BrilligPointer]. diff --git a/acvm-repo/acir/src/circuit/mod.rs b/acvm-repo/acir/src/circuit/mod.rs index d655d136bc8..6a26a45d88b 100644 --- a/acvm-repo/acir/src/circuit/mod.rs +++ b/acvm-repo/acir/src/circuit/mod.rs @@ -3,7 +3,8 @@ pub mod brillig; pub mod directives; pub mod opcodes; -use crate::native_types::Witness; +use crate::native_types::{Expression, Witness}; +use acir_field::FieldElement; pub use opcodes::Opcode; use thiserror::Error; @@ -15,7 +16,7 @@ use serde::{de::Error as DeserializationError, Deserialize, Deserializer, Serial use std::collections::BTreeSet; -use self::brillig::BrilligBytecode; +use self::{brillig::BrilligBytecode, opcodes::BlockId}; /// Specifies the maximum width of the expressions which will be constrained. /// @@ -59,18 +60,14 @@ pub struct Circuit { pub public_parameters: PublicInputs, /// The set of public inputs calculated within the circuit. pub return_values: PublicInputs, - /// Maps opcode locations to failed assertion messages. - /// These messages are embedded in the circuit to provide useful feedback to users + /// Maps opcode locations to failed assertion payloads. + /// The data in the payload is embedded in the circuit to provide useful feedback to users /// when a constraint in the circuit is not satisfied. /// // Note: This should be a BTreeMap, but serde-reflect is creating invalid // c++ code at the moment when it is, due to OpcodeLocation needing a comparison // implementation which is never generated. - // - // TODO: These are only used for constraints that are explicitly created during code generation (such as index out of bounds on slices) - // TODO: We should move towards having all the checks being evaluated in the same manner - // TODO: as runtime assert messages specified by the user. This will also be a breaking change as the `Circuit` structure will change. - pub assert_messages: Vec<(OpcodeLocation, String)>, + pub assert_messages: Vec<(OpcodeLocation, AssertionPayload)>, /// States whether the backend should use a SNARK recursion friendly prover. /// If implemented by a backend, this means that proofs generated with this circuit @@ -78,15 +75,67 @@ pub struct Circuit { pub recursive: bool, } -impl Circuit { - /// Returns the assert message associated with the provided [`OpcodeLocation`]. - /// Returns `None` if no such assert message exists. - pub fn get_assert_message(&self, opcode_location: OpcodeLocation) -> Option<&str> { - self.assert_messages - .iter() - .find(|(loc, _)| *loc == opcode_location) - .map(|(_, message)| message.as_str()) +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ExpressionOrMemory { + Expression(Expression), + Memory(BlockId), +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum AssertionPayload { + StaticString(String), + Dynamic(/* error_selector */ u64, Vec), +} + +#[derive(Debug, Copy, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)] +pub struct ErrorSelector(u64); + +impl ErrorSelector { + pub fn new(integer: u64) -> Self { + ErrorSelector(integer) } + + pub fn as_u64(&self) -> u64 { + self.0 + } +} + +impl Serialize for ErrorSelector { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.to_string().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for ErrorSelector { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s: String = Deserialize::deserialize(deserializer)?; + let as_u64 = s.parse().map_err(serde::de::Error::custom)?; + Ok(ErrorSelector(as_u64)) + } +} + +/// This selector indicates that the payload is a string. +/// This is used to parse any error with a string payload directly, +/// to avoid users having to parse the error externally to the ACVM. +/// Only non-string errors need to be parsed externally to the ACVM using the circuit ABI. +pub const STRING_ERROR_SELECTOR: ErrorSelector = ErrorSelector(0); + +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub struct RawAssertionPayload { + pub selector: ErrorSelector, + pub data: Vec, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ResolvedAssertionPayload { + String(String), + Raw(RawAssertionPayload), } #[derive(Debug, Copy, Clone)] diff --git a/acvm-repo/acir/src/circuit/opcodes.rs b/acvm-repo/acir/src/circuit/opcodes.rs index b0b8e286e0c..7db317c41ab 100644 --- a/acvm-repo/acir/src/circuit/opcodes.rs +++ b/acvm-repo/acir/src/circuit/opcodes.rs @@ -1,5 +1,5 @@ use super::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, + brillig::{BrilligInputs, BrilligOutputs}, directives::Directive, }; use crate::native_types::{Expression, Witness}; @@ -20,7 +20,6 @@ pub enum Opcode { /// Often used for exposing more efficient implementations of SNARK-unfriendly computations. BlackBoxFuncCall(BlackBoxFuncCall), Directive(Directive), - Brillig(Brillig), /// Atomic operation on a block of memory MemoryOp { block_id: BlockId, @@ -88,12 +87,6 @@ impl std::fmt::Display for Opcode { b.last().unwrap().witness_index(), ) } - Opcode::Brillig(brillig) => { - write!(f, "BRILLIG: ")?; - writeln!(f, "inputs: {:?}", brillig.inputs)?; - writeln!(f, "outputs: {:?}", brillig.outputs)?; - writeln!(f, "{:?}", brillig.bytecode) - } Opcode::MemoryOp { block_id, op, predicate } => { write!(f, "MEM ")?; if let Some(pred) = predicate { diff --git a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index 405cd0cef00..115a33c1c9d 100644 --- a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -12,6 +12,12 @@ pub struct FunctionInput { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum BlackBoxFuncCall { + AES128Encrypt { + inputs: Vec, + iv: Box<[FunctionInput; 16]>, + key: Box<[FunctionInput; 16]>, + outputs: Vec, + }, AND { lhs: FunctionInput, rhs: FunctionInput, @@ -80,9 +86,9 @@ pub enum BlackBoxFuncCall { hashed_message: Box<[FunctionInput; 32]>, output: Witness, }, - FixedBaseScalarMul { - low: FunctionInput, - high: FunctionInput, + MultiScalarMul { + points: Vec, + scalars: Vec, outputs: (Witness, Witness), }, EmbeddedCurveAdd { @@ -177,6 +183,7 @@ pub enum BlackBoxFuncCall { impl BlackBoxFuncCall { pub fn get_black_box_func(&self) -> BlackBoxFunc { match self { + BlackBoxFuncCall::AES128Encrypt { .. } => BlackBoxFunc::AES128Encrypt, BlackBoxFuncCall::AND { .. } => BlackBoxFunc::AND, BlackBoxFuncCall::XOR { .. } => BlackBoxFunc::XOR, BlackBoxFuncCall::RANGE { .. } => BlackBoxFunc::RANGE, @@ -188,7 +195,7 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::PedersenHash { .. } => BlackBoxFunc::PedersenHash, BlackBoxFuncCall::EcdsaSecp256k1 { .. } => BlackBoxFunc::EcdsaSecp256k1, BlackBoxFuncCall::EcdsaSecp256r1 { .. } => BlackBoxFunc::EcdsaSecp256r1, - BlackBoxFuncCall::FixedBaseScalarMul { .. } => BlackBoxFunc::FixedBaseScalarMul, + BlackBoxFuncCall::MultiScalarMul { .. } => BlackBoxFunc::MultiScalarMul, BlackBoxFuncCall::EmbeddedCurveAdd { .. } => BlackBoxFunc::EmbeddedCurveAdd, BlackBoxFuncCall::Keccak256 { .. } => BlackBoxFunc::Keccak256, BlackBoxFuncCall::Keccakf1600 { .. } => BlackBoxFunc::Keccakf1600, @@ -210,7 +217,8 @@ impl BlackBoxFuncCall { pub fn get_inputs_vec(&self) -> Vec { match self { - BlackBoxFuncCall::SHA256 { inputs, .. } + BlackBoxFuncCall::AES128Encrypt { inputs, .. } + | BlackBoxFuncCall::SHA256 { inputs, .. } | BlackBoxFuncCall::Blake2s { inputs, .. } | BlackBoxFuncCall::Blake3 { inputs, .. } | BlackBoxFuncCall::PedersenCommitment { inputs, .. } @@ -231,7 +239,12 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::BigIntMul { .. } | BlackBoxFuncCall::BigIntDiv { .. } | BlackBoxFuncCall::BigIntToLeBytes { .. } => Vec::new(), - BlackBoxFuncCall::FixedBaseScalarMul { low, high, .. } => vec![*low, *high], + BlackBoxFuncCall::MultiScalarMul { points, scalars, .. } => { + let mut inputs: Vec = Vec::with_capacity(points.len() * 2); + inputs.extend(points.iter().copied()); + inputs.extend(scalars.iter().copied()); + inputs + } BlackBoxFuncCall::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, .. } => vec![*input1_x, *input1_y, *input2_x, *input2_y], @@ -243,7 +256,8 @@ impl BlackBoxFuncCall { message, .. } => { - let mut inputs = Vec::with_capacity(2 + signature.len() + message.len()); + let mut inputs: Vec = + Vec::with_capacity(2 + signature.len() + message.len()); inputs.push(*public_key_x); inputs.push(*public_key_y); inputs.extend(signature.iter().copied()); @@ -320,7 +334,8 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::Sha256Compression { outputs, .. } => outputs.to_vec(), - BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } => outputs.to_vec(), + BlackBoxFuncCall::AES128Encrypt { outputs, .. } + | BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } => outputs.to_vec(), BlackBoxFuncCall::AND { output, .. } | BlackBoxFuncCall::XOR { output, .. } @@ -328,7 +343,7 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::EcdsaSecp256k1 { output, .. } | BlackBoxFuncCall::PedersenHash { output, .. } | BlackBoxFuncCall::EcdsaSecp256r1 { output, .. } => vec![*output], - BlackBoxFuncCall::FixedBaseScalarMul { outputs, .. } + BlackBoxFuncCall::MultiScalarMul { outputs, .. } | BlackBoxFuncCall::PedersenCommitment { outputs, .. } | BlackBoxFuncCall::EmbeddedCurveAdd { outputs, .. } => vec![outputs.0, outputs.1], BlackBoxFuncCall::RANGE { .. } diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs index d14159f34a1..24f27aae06f 100644 --- a/acvm-repo/acir/src/lib.rs +++ b/acvm-repo/acir/src/lib.rs @@ -42,7 +42,8 @@ mod reflection { brillig::{BrilligInputs, BrilligOutputs}, directives::Directive, opcodes::BlackBoxFuncCall, - Circuit, ExpressionWidth, Opcode, OpcodeLocation, Program, + AssertionPayload, Circuit, ExpressionOrMemory, ExpressionWidth, Opcode, OpcodeLocation, + Program, }, native_types::{Witness, WitnessMap, WitnessStack}, }; @@ -74,6 +75,8 @@ mod reflection { tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); let registry = tracer.registry().unwrap(); diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index fb924a7437d..d9327f784e6 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -13,7 +13,7 @@ use std::collections::BTreeSet; use acir::{ circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, + brillig::{BrilligBytecode, BrilligInputs, BrilligOutputs}, opcodes::{BlackBoxFuncCall, BlockId, FunctionInput, MemOp}, Circuit, Opcode, Program, PublicInputs, }, @@ -58,18 +58,24 @@ fn addition_circuit() { } #[test] -fn fixed_base_scalar_mul_circuit() { - let fixed_base_scalar_mul = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::FixedBaseScalarMul { - low: FunctionInput { witness: Witness(1), num_bits: 128 }, - high: FunctionInput { witness: Witness(2), num_bits: 128 }, - outputs: (Witness(3), Witness(4)), +fn multi_scalar_mul_circuit() { + let multi_scalar_mul = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::MultiScalarMul { + points: vec![ + FunctionInput { witness: Witness(1), num_bits: 128 }, + FunctionInput { witness: Witness(2), num_bits: 128 }, + ], + scalars: vec![ + FunctionInput { witness: Witness(3), num_bits: 128 }, + FunctionInput { witness: Witness(4), num_bits: 128 }, + ], + outputs: (Witness(5), Witness(6)), }); let circuit = Circuit { - current_witness_index: 5, - opcodes: vec![fixed_base_scalar_mul], - private_parameters: BTreeSet::from([Witness(1), Witness(2)]), - return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(3), Witness(4)])), + current_witness_index: 7, + opcodes: vec![multi_scalar_mul], + private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3), Witness(4)]), + return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(5), Witness(6)])), ..Circuit::default() }; let program = Program { functions: vec![circuit], unconstrained_functions: vec![] }; @@ -77,9 +83,10 @@ fn fixed_base_scalar_mul_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 138, 81, 10, 0, 48, 8, 66, 87, 219, 190, 118, 233, - 29, 61, 35, 3, 19, 228, 137, 60, 91, 149, 139, 26, 119, 242, 145, 31, 117, 114, 163, 135, - 142, 139, 219, 91, 127, 117, 71, 2, 117, 84, 50, 98, 113, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 76, 65, 14, 0, 32, 8, 82, 179, 186, 244, 104, 159, + 30, 45, 218, 136, 141, 33, 40, 186, 93, 76, 208, 57, 31, 93, 96, 136, 47, 250, 146, 188, + 209, 39, 181, 131, 131, 187, 148, 110, 240, 246, 101, 38, 63, 180, 243, 97, 3, 125, 173, + 118, 131, 153, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -105,11 +112,10 @@ fn pedersen_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 9, 10, 0, 0, 4, 115, 149, 255, 127, 88, 8, 133, - 213, 218, 137, 80, 144, 32, 182, 79, 213, 151, 173, 61, 5, 121, 245, 91, 103, 255, 191, 3, - 7, 16, 26, 112, 158, 113, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 73, 10, 0, 0, 4, 180, 29, 252, 255, 193, 66, 40, + 76, 77, 179, 34, 20, 36, 136, 237, 83, 245, 101, 107, 79, 65, 94, 253, 214, 217, 255, 239, + 192, 1, 43, 124, 181, 238, 113, 0, 0, 0, ]; - assert_eq!(bytes, expected_serialization) } @@ -152,7 +158,7 @@ fn schnorr_verify_circuit() { let expected_serialization: Vec = vec![ 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 210, 85, 78, 67, 81, 24, 133, 209, 226, 238, 238, 238, 238, 238, 165, 148, 82, 102, 193, 252, 135, 64, 232, 78, 87, 147, 114, 147, 147, 5, - 47, 132, 252, 251, 107, 41, 212, 191, 159, 218, 107, 241, 115, 236, 228, 111, 237, 181, + 47, 132, 252, 251, 107, 41, 212, 191, 159, 218, 107, 241, 115, 236, 226, 111, 237, 181, 178, 173, 246, 186, 107, 175, 157, 29, 236, 100, 23, 27, 175, 135, 189, 236, 99, 63, 7, 56, 200, 33, 14, 115, 132, 163, 28, 227, 56, 39, 56, 201, 41, 78, 115, 134, 179, 156, 227, 60, 23, 184, 200, 37, 46, 115, 133, 171, 92, 227, 58, 55, 184, 201, 45, 110, 115, 135, 187, @@ -164,8 +170,8 @@ fn schnorr_verify_circuit() { 180, 144, 14, 210, 64, 246, 95, 46, 212, 119, 207, 230, 217, 59, 91, 103, 231, 108, 156, 125, 183, 237, 186, 107, 207, 125, 59, 30, 218, 239, 216, 110, 167, 246, 58, 183, 211, 165, 125, 174, 237, 114, 107, 143, 123, 59, 60, 186, 255, 179, 187, 191, 186, 115, 209, 125, 75, - 238, 90, 118, 207, 138, 59, 54, 110, 214, 184, 91, 161, 233, 158, 255, 190, 63, 165, 188, - 93, 151, 233, 3, 0, 0, + 238, 90, 118, 207, 138, 59, 54, 110, 214, 184, 91, 161, 233, 158, 255, 190, 63, 71, 59, 68, + 130, 233, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -176,14 +182,7 @@ fn simple_brillig_foreign_call() { let w_input = Witness(1); let w_inverted = Witness(2); - let brillig_data = Brillig { - inputs: vec![ - BrilligInputs::Single(w_input.into()), // Input Register 0, - ], - // This tells the BrilligSolver which witnesses its output values correspond to - outputs: vec![ - BrilligOutputs::Simple(w_inverted), // Output Register 1 - ], + let brillig_bytecode = BrilligBytecode { bytecode: vec![ brillig::Opcode::CalldataCopy { destination_address: MemoryAddress(0), @@ -199,27 +198,38 @@ fn simple_brillig_foreign_call() { }, brillig::Opcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], - predicate: None, }; - let opcodes = vec![Opcode::Brillig(brillig_data)]; + let opcodes = vec![Opcode::BrilligCall { + id: 0, + inputs: vec![ + BrilligInputs::Single(w_input.into()), // Input Register 0, + ], + // This tells the BrilligSolver which witnesses its output values correspond to + outputs: vec![ + BrilligOutputs::Simple(w_inverted), // Output Register 1 + ], + predicate: None, + }]; + let circuit = Circuit { current_witness_index: 8, opcodes, private_parameters: BTreeSet::from([Witness(1), Witness(2)]), ..Circuit::default() }; - let program = Program { functions: vec![circuit], unconstrained_functions: vec![] }; + let program = + Program { functions: vec![circuit], unconstrained_functions: vec![brillig_bytecode] }; let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 61, 10, 192, 32, 12, 133, 19, 11, 165, 116, - 235, 77, 236, 13, 122, 153, 14, 93, 58, 136, 120, 124, 241, 47, 129, 12, 42, 130, 126, 16, - 18, 146, 16, 222, 11, 66, 225, 136, 129, 84, 111, 162, 150, 112, 239, 161, 172, 231, 184, - 113, 221, 45, 45, 245, 42, 242, 144, 216, 43, 250, 153, 83, 204, 191, 223, 189, 198, 246, - 92, 39, 60, 244, 63, 195, 59, 87, 99, 150, 165, 113, 83, 193, 0, 1, 19, 247, 29, 5, 160, 1, - 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 193, 10, 192, 32, 8, 134, 117, 99, 99, 236, + 182, 55, 105, 111, 176, 151, 217, 161, 75, 135, 136, 30, 63, 42, 82, 144, 8, 47, 245, 65, + 252, 230, 47, 162, 34, 52, 174, 242, 144, 226, 131, 148, 255, 18, 206, 125, 164, 102, 142, + 23, 215, 245, 50, 114, 222, 173, 15, 80, 38, 65, 217, 108, 39, 61, 7, 30, 115, 11, 223, + 186, 248, 251, 160, 221, 170, 146, 64, 191, 39, 215, 60, 3, 47, 3, 99, 171, 188, 84, 164, + 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -239,27 +249,7 @@ fn complex_brillig_foreign_call() { let a_plus_b_plus_c = Witness(7); let a_plus_b_plus_c_times_2 = Witness(8); - let brillig_data = Brillig { - inputs: vec![ - // Input 0,1,2 - BrilligInputs::Array(vec![ - Expression::from(a), - Expression::from(b), - Expression::from(c), - ]), - // Input 3 - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(fe_1, a), (fe_1, b), (fe_1, c)], - q_c: fe_0, - }), - ], - // This tells the BrilligSolver which witnesses its output values correspond to - outputs: vec![ - BrilligOutputs::Array(vec![a_times_2, b_times_3, c_times_4]), // Output 0,1,2 - BrilligOutputs::Simple(a_plus_b_plus_c), // Output 3 - BrilligOutputs::Simple(a_plus_b_plus_c_times_2), // Output 4 - ], + let brillig_bytecode = BrilligBytecode { bytecode: vec![ brillig::Opcode::CalldataCopy { destination_address: MemoryAddress(32), @@ -300,30 +290,54 @@ fn complex_brillig_foreign_call() { }, brillig::Opcode::Stop { return_data_offset: 32, return_data_size: 5 }, ], - predicate: None, }; - let opcodes = vec![Opcode::Brillig(brillig_data)]; + let opcodes = vec![Opcode::BrilligCall { + id: 0, + inputs: vec![ + // Input 0,1,2 + BrilligInputs::Array(vec![ + Expression::from(a), + Expression::from(b), + Expression::from(c), + ]), + // Input 3 + BrilligInputs::Single(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, a), (fe_1, b), (fe_1, c)], + q_c: fe_0, + }), + ], + // This tells the BrilligSolver which witnesses its output values correspond to + outputs: vec![ + BrilligOutputs::Array(vec![a_times_2, b_times_3, c_times_4]), // Output 0,1,2 + BrilligOutputs::Simple(a_plus_b_plus_c), // Output 3 + BrilligOutputs::Simple(a_plus_b_plus_c_times_2), // Output 4 + ], + predicate: None, + }]; + let circuit = Circuit { current_witness_index: 8, opcodes, private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3)]), ..Circuit::default() }; - let program = Program { functions: vec![circuit], unconstrained_functions: vec![] }; + let program = + Program { functions: vec![circuit], unconstrained_functions: vec![brillig_bytecode] }; let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 77, 218, 209, 145, 217, - 205, 13, 6, 198, 3, 84, 79, 224, 93, 196, 157, 162, 75, 79, 47, 22, 124, 197, 16, 186, 17, - 43, 104, 32, 36, 109, 126, 143, 36, 45, 211, 70, 133, 103, 134, 110, 61, 27, 232, 140, 179, - 164, 224, 215, 64, 186, 115, 84, 113, 186, 92, 238, 42, 140, 230, 1, 24, 237, 5, 24, 195, - 62, 220, 116, 222, 41, 231, 146, 180, 127, 54, 242, 126, 94, 158, 51, 207, 57, 206, 111, - 200, 2, 247, 4, 219, 79, 245, 157, 132, 31, 137, 89, 52, 73, 176, 214, 46, 167, 125, 23, - 89, 213, 254, 8, 156, 237, 56, 76, 125, 55, 91, 229, 170, 161, 254, 133, 94, 42, 59, 171, - 184, 69, 197, 46, 66, 202, 47, 40, 86, 39, 220, 155, 3, 185, 191, 180, 183, 55, 163, 72, - 98, 70, 66, 221, 251, 40, 173, 255, 35, 68, 62, 61, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 131, 64, 12, 77, 102, 90, 43, 221, 245, + 6, 133, 246, 0, 211, 158, 192, 187, 136, 59, 69, 151, 158, 94, 116, 48, 131, 241, 233, 70, + 28, 65, 3, 195, 155, 79, 62, 47, 9, 25, 166, 81, 210, 97, 177, 236, 239, 130, 70, 208, 223, + 91, 154, 75, 208, 205, 4, 221, 62, 249, 113, 60, 95, 238, 40, 142, 230, 2, 28, 237, 1, 28, + 73, 245, 255, 132, 253, 142, 217, 151, 168, 245, 179, 43, 243, 115, 163, 113, 190, 18, 57, + 63, 4, 83, 44, 180, 55, 50, 180, 28, 188, 153, 224, 196, 122, 175, 111, 112, 68, 24, 65, + 50, 204, 162, 100, 249, 119, 137, 226, 193, 16, 251, 169, 50, 204, 235, 170, 41, 139, 214, + 130, 42, 82, 253, 168, 253, 23, 222, 25, 236, 58, 176, 237, 20, 234, 207, 107, 45, 78, 184, + 55, 27, 124, 191, 104, 42, 111, 40, 121, 15, 94, 163, 77, 128, 65, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -357,11 +371,11 @@ fn memory_op_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 81, 57, 14, 0, 32, 8, 147, 195, 255, 224, 15, 252, - 255, 171, 212, 200, 208, 129, 77, 24, 108, 66, 90, 150, 166, 20, 106, 23, 125, 143, 128, - 62, 96, 103, 114, 173, 45, 198, 116, 182, 55, 140, 106, 95, 74, 246, 149, 60, 47, 171, 46, - 215, 126, 43, 87, 179, 111, 23, 8, 202, 176, 99, 248, 240, 9, 11, 137, 33, 212, 110, 35, 3, - 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 82, 65, 10, 0, 32, 8, 203, 180, 255, 216, 15, 250, + 255, 171, 10, 154, 16, 210, 45, 61, 52, 144, 13, 132, 49, 135, 84, 54, 218, 26, 134, 22, + 112, 5, 19, 180, 237, 61, 6, 88, 223, 208, 179, 125, 41, 216, 151, 227, 188, 52, 187, 92, + 253, 173, 92, 137, 190, 157, 143, 160, 254, 155, 45, 188, 148, 11, 38, 213, 237, 188, 16, + 35, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -460,15 +474,15 @@ fn nested_acir_call_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 205, 146, 65, 10, 3, 33, 12, 69, 163, 46, 230, 58, 137, - 209, 49, 238, 122, 149, 74, 157, 251, 31, 161, 83, 154, 161, 86, 132, 89, 212, 194, 124, - 248, 24, 36, 132, 228, 241, 29, 188, 229, 212, 47, 45, 187, 205, 110, 11, 31, 25, 53, 28, - 255, 103, 77, 14, 58, 29, 141, 55, 125, 241, 55, 145, 109, 102, 49, 174, 33, 212, 228, 43, - 49, 221, 209, 231, 34, 17, 67, 44, 171, 144, 80, 148, 248, 240, 194, 92, 37, 72, 202, 37, - 39, 204, 20, 184, 210, 22, 51, 111, 58, 204, 205, 219, 11, 161, 129, 208, 214, 6, 6, 114, - 29, 193, 127, 193, 130, 137, 176, 236, 188, 189, 252, 162, 183, 218, 230, 238, 97, 138, - 250, 152, 245, 245, 87, 220, 12, 140, 113, 95, 153, 170, 129, 185, 17, 60, 3, 54, 212, 19, - 104, 145, 195, 151, 14, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 205, 146, 97, 10, 195, 32, 12, 133, 163, 66, 207, 147, + 24, 173, 241, 223, 174, 50, 153, 189, 255, 17, 214, 177, 148, 57, 17, 250, 99, 14, 250, + 224, 97, 144, 16, 146, 143, 231, 224, 45, 167, 126, 105, 217, 109, 118, 91, 248, 200, 168, + 225, 248, 63, 107, 114, 208, 233, 104, 188, 233, 139, 191, 137, 108, 51, 139, 113, 13, 161, + 38, 95, 137, 233, 142, 62, 23, 137, 24, 98, 89, 133, 132, 162, 196, 135, 23, 230, 42, 65, + 82, 46, 57, 97, 166, 192, 149, 182, 152, 121, 211, 97, 110, 222, 94, 8, 13, 132, 182, 54, + 48, 144, 235, 8, 254, 11, 22, 76, 132, 101, 231, 237, 229, 23, 189, 213, 54, 119, 15, 83, + 212, 199, 172, 175, 191, 226, 102, 96, 140, 251, 202, 84, 13, 204, 141, 224, 25, 176, 161, + 158, 53, 121, 144, 73, 14, 4, 0, 0, ]; assert_eq!(bytes, expected_serialization); } diff --git a/acvm-repo/acir_field/Cargo.toml b/acvm-repo/acir_field/Cargo.toml index 7a260ea1fa2..89ee161206e 100644 --- a/acvm-repo/acir_field/Cargo.toml +++ b/acvm-repo/acir_field/Cargo.toml @@ -2,7 +2,7 @@ name = "acir_field" description = "The field implementation being used by ACIR." # x-release-please-start-version -version = "0.43.0" +version = "0.45.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml index e6554d3f773..1b671d49366 100644 --- a/acvm-repo/acvm/Cargo.toml +++ b/acvm-repo/acvm/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm" description = "The virtual machine that processes ACIR given a backend/proof system." # x-release-please-start-version -version = "0.43.0" +version = "0.45.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm/src/compiler/mod.rs b/acvm-repo/acvm/src/compiler/mod.rs index 6543c70958b..436db648ea8 100644 --- a/acvm-repo/acvm/src/compiler/mod.rs +++ b/acvm-repo/acvm/src/compiler/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use acir::circuit::{Circuit, ExpressionWidth, OpcodeLocation}; +use acir::circuit::{AssertionPayload, Circuit, ExpressionWidth, OpcodeLocation}; // The various passes that we can use over ACIR mod optimizers; @@ -54,9 +54,9 @@ impl AcirTransformationMap { } fn transform_assert_messages( - assert_messages: Vec<(OpcodeLocation, String)>, + assert_messages: Vec<(OpcodeLocation, AssertionPayload)>, map: &AcirTransformationMap, -) -> Vec<(OpcodeLocation, String)> { +) -> Vec<(OpcodeLocation, AssertionPayload)> { assert_messages .into_iter() .flat_map(|(location, message)| { diff --git a/acvm-repo/acvm/src/compiler/optimizers/mod.rs b/acvm-repo/acvm/src/compiler/optimizers/mod.rs index 04d3f99a408..dfe348d4ff5 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/mod.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/mod.rs @@ -32,7 +32,7 @@ pub(super) fn optimize_internal(acir: Circuit) -> (Circuit, Vec) { // by applying the modifications done to the circuit opcodes and also to the opcode_positions (delete and insert) let acir_opcode_positions = (0..acir.opcodes.len()).collect(); - if acir.opcodes.len() == 1 && matches!(acir.opcodes[0], Opcode::Brillig(_)) { + if acir.opcodes.len() == 1 && matches!(acir.opcodes[0], Opcode::BrilligCall { .. }) { info!("Program is fully unconstrained, skipping optimization pass"); return (acir, acir_opcode_positions); } diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs index d13fac1672a..0099519e4b6 100644 --- a/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -128,20 +128,6 @@ pub(super) fn transform_internal( new_acir_opcode_positions.push(acir_opcode_positions[index]); transformed_opcodes.push(opcode); } - Opcode::Brillig(ref brillig) => { - for output in &brillig.outputs { - match output { - BrilligOutputs::Simple(w) => transformer.mark_solvable(*w), - BrilligOutputs::Array(v) => { - for witness in v { - transformer.mark_solvable(*witness); - } - } - } - } - new_acir_opcode_positions.push(acir_opcode_positions[index]); - transformed_opcodes.push(opcode); - } Opcode::BrilligCall { ref outputs, .. } => { for output in outputs { match output { diff --git a/acvm-repo/acvm/src/pwg/arithmetic.rs b/acvm-repo/acvm/src/pwg/arithmetic.rs index dc9e13d44b6..b971e4a0efb 100644 --- a/acvm-repo/acvm/src/pwg/arithmetic.rs +++ b/acvm-repo/acvm/src/pwg/arithmetic.rs @@ -53,6 +53,7 @@ impl ExpressionSolver { if !total_sum.is_zero() { Err(OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Unresolved, + payload: None, }) } else { Ok(()) @@ -81,6 +82,7 @@ impl ExpressionSolver { if !total_sum.is_zero() { Err(OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Unresolved, + payload: None, }) } else { Ok(()) @@ -96,6 +98,7 @@ impl ExpressionSolver { if !(a + b + opcode.q_c).is_zero() { Err(OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Unresolved, + payload: None, }) } else { Ok(()) @@ -113,6 +116,7 @@ impl ExpressionSolver { if !total_sum.is_zero() { Err(OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Unresolved, + payload: None, }) } else { Ok(()) diff --git a/acvm-repo/acvm/src/pwg/blackbox/aes128.rs b/acvm-repo/acvm/src/pwg/blackbox/aes128.rs new file mode 100644 index 00000000000..c02c59a174f --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/aes128.rs @@ -0,0 +1,32 @@ +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + FieldElement, +}; +use acvm_blackbox_solver::aes128_encrypt; + +use crate::{pwg::insert_value, OpcodeResolutionError}; + +use super::utils::{to_u8_array, to_u8_vec}; + +pub(super) fn solve_aes128_encryption_opcode( + initial_witness: &mut WitnessMap, + inputs: &[FunctionInput], + iv: &[FunctionInput; 16], + key: &[FunctionInput; 16], + outputs: &[Witness], +) -> Result<(), OpcodeResolutionError> { + let scalars = to_u8_vec(initial_witness, inputs)?; + + let iv = to_u8_array(initial_witness, iv)?; + let key = to_u8_array(initial_witness, key)?; + + let ciphertext = aes128_encrypt(&scalars, iv, key)?; + + // Write witness assignments + for (output_witness, value) in outputs.iter().zip(ciphertext.into_iter()) { + insert_value(output_witness, FieldElement::from(value as u128), initial_witness)?; + } + + Ok(()) +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs b/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs similarity index 60% rename from acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs rename to acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs index c5bfd1d5646..ee35385fa81 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs @@ -6,20 +6,27 @@ use acvm_blackbox_solver::BlackBoxFunctionSolver; use crate::pwg::{insert_value, witness_to_value, OpcodeResolutionError}; -pub(super) fn fixed_base_scalar_mul( +pub(super) fn multi_scalar_mul( backend: &impl BlackBoxFunctionSolver, initial_witness: &mut WitnessMap, - low: FunctionInput, - high: FunctionInput, + points: &[FunctionInput], + scalars: &[FunctionInput], outputs: (Witness, Witness), ) -> Result<(), OpcodeResolutionError> { - let low = witness_to_value(initial_witness, low.witness)?; - let high = witness_to_value(initial_witness, high.witness)?; + let points: Result, _> = + points.iter().map(|input| witness_to_value(initial_witness, input.witness)).collect(); + let points: Vec<_> = points?.into_iter().cloned().collect(); - let (pub_x, pub_y) = backend.fixed_base_scalar_mul(low, high)?; + let scalars: Result, _> = + scalars.iter().map(|input| witness_to_value(initial_witness, input.witness)).collect(); + let scalars: Vec<_> = scalars?.into_iter().cloned().collect(); - insert_value(&outputs.0, pub_x, initial_witness)?; - insert_value(&outputs.1, pub_y, initial_witness)?; + // Call the backend's multi-scalar multiplication function + let (res_x, res_y) = backend.multi_scalar_mul(&points, &scalars)?; + + // Insert the resulting point into the witness map + insert_value(&outputs.0, res_x, initial_witness)?; + insert_value(&outputs.1, res_y, initial_witness)?; Ok(()) } diff --git a/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 2753c7baaaa..a74f44b79dc 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -6,21 +6,24 @@ use acir::{ use acvm_blackbox_solver::{blake2s, blake3, keccak256, keccakf1600, sha256}; use self::{ - bigint::AcvmBigIntSolver, hash::solve_poseidon2_permutation_opcode, pedersen::pedersen_hash, + aes128::solve_aes128_encryption_opcode, bigint::AcvmBigIntSolver, + hash::solve_poseidon2_permutation_opcode, pedersen::pedersen_hash, }; use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; use crate::{pwg::witness_to_value, BlackBoxFunctionSolver}; +mod aes128; pub(crate) mod bigint; -mod fixed_base_scalar_mul; +mod embedded_curve_ops; mod hash; mod logic; mod pedersen; mod range; mod signature; +pub(crate) mod utils; -use fixed_base_scalar_mul::{embedded_curve_add, fixed_base_scalar_mul}; +use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul}; // Hash functions should eventually be exposed for external consumers. use hash::{solve_generic_256_hash_opcode, solve_sha_256_permutation_opcode}; use logic::{and, xor}; @@ -68,6 +71,9 @@ pub(crate) fn solve( } match bb_func { + BlackBoxFuncCall::AES128Encrypt { inputs, iv, key, outputs } => { + solve_aes128_encryption_opcode(initial_witness, inputs, iv, key, outputs) + } BlackBoxFuncCall::AND { lhs, rhs, output } => and(initial_witness, lhs, rhs, output), BlackBoxFuncCall::XOR { lhs, rhs, output } => xor(initial_witness, lhs, rhs, output), BlackBoxFuncCall::RANGE { input } => solve_range_opcode(initial_witness, input), @@ -155,8 +161,8 @@ pub(crate) fn solve( message.as_ref(), *output, ), - BlackBoxFuncCall::FixedBaseScalarMul { low, high, outputs } => { - fixed_base_scalar_mul(backend, initial_witness, *low, *high, *outputs) + BlackBoxFuncCall::MultiScalarMul { points, scalars, outputs } => { + multi_scalar_mul(backend, initial_witness, points, scalars, *outputs) } BlackBoxFuncCall::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, outputs } => { embedded_curve_add( diff --git a/acvm-repo/acvm/src/pwg/blackbox/range.rs b/acvm-repo/acvm/src/pwg/blackbox/range.rs index 2afe820b636..aac50b32fc8 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/range.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/range.rs @@ -12,6 +12,7 @@ pub(crate) fn solve_range_opcode( if w_value.num_bits() > input.num_bits { return Err(OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Unresolved, + payload: None, }); } Ok(()) diff --git a/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs b/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs index b113c801251..ce2e57e0bd7 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs @@ -5,9 +5,13 @@ use acir::{ }; use acvm_blackbox_solver::{ecdsa_secp256k1_verify, ecdsa_secp256r1_verify}; -use crate::{pwg::insert_value, OpcodeResolutionError}; - -use super::{to_u8_array, to_u8_vec}; +use crate::{ + pwg::{ + blackbox::utils::{to_u8_array, to_u8_vec}, + insert_value, + }, + OpcodeResolutionError, +}; pub(crate) fn secp256k1_prehashed( initial_witness: &mut WitnessMap, diff --git a/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs index bd223ecd0c9..0cfb96740b8 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs @@ -1,36 +1,2 @@ -use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap}; - -use crate::pwg::{witness_to_value, OpcodeResolutionError}; - -fn to_u8_array( - initial_witness: &WitnessMap, - inputs: &[FunctionInput; N], -) -> Result<[u8; N], OpcodeResolutionError> { - let mut result = [0; N]; - for (it, input) in result.iter_mut().zip(inputs) { - let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); - let byte = witness_value_bytes - .last() - .expect("Field element must be represented by non-zero amount of bytes"); - *it = *byte; - } - Ok(result) -} - -fn to_u8_vec( - initial_witness: &WitnessMap, - inputs: &[FunctionInput], -) -> Result, OpcodeResolutionError> { - let mut result = Vec::with_capacity(inputs.len()); - for input in inputs { - let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); - let byte = witness_value_bytes - .last() - .expect("Field element must be represented by non-zero amount of bytes"); - result.push(*byte); - } - Ok(result) -} - pub(super) mod ecdsa; pub(super) mod schnorr; diff --git a/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs b/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs index 3d0216fa217..7b085d9ff47 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs @@ -1,6 +1,8 @@ -use super::{to_u8_array, to_u8_vec}; use crate::{ - pwg::{insert_value, witness_to_value, OpcodeResolutionError}, + pwg::{ + blackbox::utils::{to_u8_array, to_u8_vec}, + insert_value, witness_to_value, OpcodeResolutionError, + }, BlackBoxFunctionSolver, }; use acir::{ diff --git a/acvm-repo/acvm/src/pwg/blackbox/utils.rs b/acvm-repo/acvm/src/pwg/blackbox/utils.rs new file mode 100644 index 00000000000..700f30890ae --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/utils.rs @@ -0,0 +1,33 @@ +use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap}; + +use crate::pwg::{witness_to_value, OpcodeResolutionError}; + +pub(crate) fn to_u8_array( + initial_witness: &WitnessMap, + inputs: &[FunctionInput; N], +) -> Result<[u8; N], OpcodeResolutionError> { + let mut result = [0; N]; + for (it, input) in result.iter_mut().zip(inputs) { + let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); + let byte = witness_value_bytes + .last() + .expect("Field element must be represented by non-zero amount of bytes"); + *it = *byte; + } + Ok(result) +} + +pub(crate) fn to_u8_vec( + initial_witness: &WitnessMap, + inputs: &[FunctionInput], +) -> Result, OpcodeResolutionError> { + let mut result = Vec::with_capacity(inputs.len()); + for input in inputs { + let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); + let byte = witness_value_bytes + .last() + .expect("Field element must be represented by non-zero amount of bytes"); + result.push(*byte); + } + Ok(result) +} diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 67faf7f5007..c911202c823 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -3,9 +3,10 @@ use std::collections::HashMap; use acir::{ brillig::{ForeignCallParam, ForeignCallResult, Opcode as BrilligOpcode}, circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, + brillig::{BrilligInputs, BrilligOutputs}, opcodes::BlockId, - OpcodeLocation, + ErrorSelector, OpcodeLocation, RawAssertionPayload, ResolvedAssertionPayload, + STRING_ERROR_SELECTOR, }, native_types::WitnessMap, FieldElement, @@ -30,19 +31,6 @@ pub struct BrilligSolver<'b, B: BlackBoxFunctionSolver> { } impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { - /// Evaluates if the Brillig block should be skipped entirely - pub(super) fn should_skip( - witness: &WitnessMap, - brillig: &Brillig, - ) -> Result { - // If the predicate is `None`, the block should never be skipped - // If the predicate is `Some` but we cannot find a value, then we return stalled - match &brillig.predicate { - Some(pred) => Ok(get_value(pred, witness)?.is_zero()), - None => Ok(false), - } - } - /// Assigns the zero value to all outputs of the given [`Brillig`] bytecode. pub(super) fn zero_out_brillig_outputs( initial_witness: &mut WitnessMap, @@ -63,26 +51,6 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { Ok(()) } - // TODO: Delete this old method once `Brillig` is deleted - /// Constructs a solver for a Brillig block given the bytecode and initial - /// witness. - pub(crate) fn new( - initial_witness: &WitnessMap, - memory: &HashMap, - brillig: &'b Brillig, - bb_solver: &'b B, - acir_index: usize, - ) -> Result { - let vm = Self::setup_brillig_vm( - initial_witness, - memory, - &brillig.inputs, - &brillig.bytecode, - bb_solver, - )?; - Ok(Self { vm, acir_index }) - } - /// Constructs a solver for a Brillig block given the bytecode and initial /// witness. pub(crate) fn new_call( @@ -193,32 +161,55 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { VMStatus::Finished { .. } => Ok(BrilligSolverStatus::Finished), VMStatus::InProgress => Ok(BrilligSolverStatus::InProgress), VMStatus::Failure { reason, call_stack } => { - let message = match reason { - FailureReason::RuntimeError { message } => Some(message), + let payload = match reason { + FailureReason::RuntimeError { message } => { + Some(ResolvedAssertionPayload::String(message)) + } FailureReason::Trap { revert_data_offset, revert_data_size } => { // Since noir can only revert with strings currently, we can parse return data as a string if revert_data_size == 0 { None } else { let memory = self.vm.get_memory(); - let bytes = memory + let mut revert_values_iter = memory [revert_data_offset..(revert_data_offset + revert_data_size)] - .iter() - .map(|memory_value| { - memory_value - .try_into() - .expect("Assert message character is not a byte") - }) - .collect(); - Some( - String::from_utf8(bytes) - .expect("Assert message is not valid UTF-8"), - ) + .iter(); + let error_selector = ErrorSelector::new( + revert_values_iter + .next() + .expect("Incorrect revert data size") + .try_into() + .expect("Error selector is not u64"), + ); + + match error_selector { + STRING_ERROR_SELECTOR => { + // If the error selector is 0, it means the error is a string + let string = revert_values_iter + .map(|memory_value| { + let as_u8: u8 = memory_value + .try_into() + .expect("String item is not u8"); + as_u8 as char + }) + .collect(); + Some(ResolvedAssertionPayload::String(string)) + } + _ => { + // If the error selector is not 0, it means the error is a custom error + Some(ResolvedAssertionPayload::Raw(RawAssertionPayload { + selector: error_selector, + data: revert_values_iter + .map(|value| value.to_field()) + .collect(), + })) + } + } } } }; Err(OpcodeResolutionError::BrilligFunctionFailed { - message, + payload, call_stack: call_stack .iter() .map(|brillig_index| OpcodeLocation::Brillig { diff --git a/acvm-repo/acvm/src/pwg/directives/mod.rs b/acvm-repo/acvm/src/pwg/directives/mod.rs index ee544521fc7..db79379a374 100644 --- a/acvm-repo/acvm/src/pwg/directives/mod.rs +++ b/acvm-repo/acvm/src/pwg/directives/mod.rs @@ -26,6 +26,7 @@ pub(crate) fn solve_directives( if b.len() < decomposed_integer.len() { return Err(OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Unresolved, + payload: None, }); } diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index 652e173867a..a4219adbfa6 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -4,7 +4,11 @@ use std::collections::HashMap; use acir::{ brillig::ForeignCallResult, - circuit::{brillig::BrilligBytecode, opcodes::BlockId, Opcode, OpcodeLocation}, + circuit::{ + brillig::BrilligBytecode, opcodes::BlockId, AssertionPayload, ErrorSelector, + ExpressionOrMemory, Opcode, OpcodeLocation, RawAssertionPayload, ResolvedAssertionPayload, + STRING_ERROR_SELECTOR, + }, native_types::{Expression, Witness, WitnessMap}, BlackBoxFunc, FieldElement, }; @@ -117,13 +121,19 @@ pub enum OpcodeResolutionError { #[error("Cannot solve opcode: {0}")] OpcodeNotSolvable(#[from] OpcodeNotSolvable), #[error("Cannot satisfy constraint")] - UnsatisfiedConstrain { opcode_location: ErrorLocation }, + UnsatisfiedConstrain { + opcode_location: ErrorLocation, + payload: Option, + }, #[error("Index out of bounds, array has size {array_size:?}, but index was {index:?}")] IndexOutOfBounds { opcode_location: ErrorLocation, index: u32, array_size: u32 }, #[error("Failed to solve blackbox function: {0}, reason: {1}")] BlackBoxFunctionFailed(BlackBoxFunc, String), - #[error("Failed to solve brillig function{}", .message.as_ref().map(|m| format!(", reason: {}", m)).unwrap_or_default())] - BrilligFunctionFailed { message: Option, call_stack: Vec }, + #[error("Failed to solve brillig function")] + BrilligFunctionFailed { + call_stack: Vec, + payload: Option, + }, #[error("Attempted to call `main` with a `Call` opcode")] AcirMainCallAttempted { opcode_location: ErrorLocation }, #[error("{results_size:?} result values were provided for {outputs_size:?} call output witnesses, most likely due to bad ACIR codegen")] @@ -168,6 +178,8 @@ pub struct ACVM<'a, B: BlackBoxFunctionSolver> { // Each unconstrained function referenced in the program unconstrained_functions: &'a [BrilligBytecode], + + assertion_payloads: &'a [(OpcodeLocation, AssertionPayload)], } impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { @@ -176,6 +188,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { opcodes: &'a [Opcode], initial_witness: WitnessMap, unconstrained_functions: &'a [BrilligBytecode], + assertion_payloads: &'a [(OpcodeLocation, AssertionPayload)], ) -> Self { let status = if opcodes.is_empty() { ACVMStatus::Solved } else { ACVMStatus::InProgress }; ACVM { @@ -190,6 +203,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { acir_call_counter: 0, acir_call_results: Vec::default(), unconstrained_functions, + assertion_payloads, } } @@ -329,10 +343,6 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { let solver = self.block_solvers.entry(*block_id).or_default(); solver.solve_memory_op(op, &mut self.witness_map, predicate) } - Opcode::Brillig(_) => match self.solve_brillig_opcode() { - Ok(Some(foreign_call)) => return self.wait_for_foreign_call(foreign_call), - res => res.map(|_| ()), - }, Opcode::BrilligCall { .. } => match self.solve_brillig_call_opcode() { Ok(Some(foreign_call)) => return self.wait_for_foreign_call(foreign_call), res => res.map(|_| ()), @@ -366,14 +376,19 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { OpcodeResolutionError::IndexOutOfBounds { opcode_location: opcode_index, .. - } - | OpcodeResolutionError::UnsatisfiedConstrain { - opcode_location: opcode_index, } => { *opcode_index = ErrorLocation::Resolved(OpcodeLocation::Acir( self.instruction_pointer(), )); } + OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: opcode_index, + payload: assertion_payload, + } => { + let location = OpcodeLocation::Acir(self.instruction_pointer()); + *opcode_index = ErrorLocation::Resolved(location); + *assertion_payload = self.extract_assertion_payload(location); + } // All other errors are thrown normally. _ => (), }; @@ -382,44 +397,61 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { } } - fn solve_brillig_opcode( - &mut self, - ) -> Result, OpcodeResolutionError> { - let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] else { - unreachable!("Not executing a Brillig opcode"); - }; - - let witness = &mut self.witness_map; - if is_predicate_false(witness, &brillig.predicate)? { - return BrilligSolver::::zero_out_brillig_outputs(witness, &brillig.outputs) - .map(|_| None); - } - - // If we're resuming execution after resolving a foreign call then - // there will be a cached `BrilligSolver` to avoid recomputation. - let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { - Some(solver) => solver, - None => BrilligSolver::new( - witness, - &self.block_solvers, - brillig, - self.backend, - self.instruction_pointer, - )?, - }; - match solver.solve()? { - BrilligSolverStatus::ForeignCallWait(foreign_call) => { - // Cache the current state of the solver - self.brillig_solver = Some(solver); - Ok(Some(foreign_call)) + fn extract_assertion_payload( + &self, + location: OpcodeLocation, + ) -> Option { + let (_, found_assertion_payload) = + self.assertion_payloads.iter().find(|(loc, _)| location == *loc)?; + match found_assertion_payload { + AssertionPayload::StaticString(string) => { + Some(ResolvedAssertionPayload::String(string.clone())) } - BrilligSolverStatus::InProgress => { - unreachable!("Brillig solver still in progress") - } - BrilligSolverStatus::Finished => { - // Write execution outputs - solver.finalize(witness, &brillig.outputs)?; - Ok(None) + AssertionPayload::Dynamic(error_selector, expression) => { + let mut fields = vec![]; + for expr in expression { + match expr { + ExpressionOrMemory::Expression(expr) => { + let value = get_value(expr, &self.witness_map).ok()?; + fields.push(value); + } + ExpressionOrMemory::Memory(block_id) => { + let memory_block = self.block_solvers.get(block_id)?; + fields.extend((0..memory_block.block_len).map(|memory_index| { + *memory_block + .block_value + .get(&memory_index) + .expect("All memory is initialized on creation") + })); + } + } + } + let error_selector = ErrorSelector::new(*error_selector); + + Some(match error_selector { + STRING_ERROR_SELECTOR => { + // If the error selector is 0, it means the error is a string + let string = fields + .iter() + .map(|field| { + let as_u8: u8 = field + .try_to_u64() + .expect("String character doesn't fit in u64") + .try_into() + .expect("String character doesn't fit in u8"); + as_u8 as char + }) + .collect(); + ResolvedAssertionPayload::String(string) + } + _ => { + // If the error selector is not 0, it means the error is a custom error + ResolvedAssertionPayload::Raw(RawAssertionPayload { + selector: error_selector, + data: fields, + }) + } + }) } } } @@ -430,12 +462,12 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { let Opcode::BrilligCall { id, inputs, outputs, predicate } = &self.opcodes[self.instruction_pointer] else { - unreachable!("Not executing a Brillig opcode"); + unreachable!("Not executing a BrilligCall opcode"); }; - let witness = &mut self.witness_map; - if is_predicate_false(witness, predicate)? { - return BrilligSolver::::zero_out_brillig_outputs(witness, outputs).map(|_| None); + if is_predicate_false(&self.witness_map, predicate)? { + return BrilligSolver::::zero_out_brillig_outputs(&mut self.witness_map, outputs) + .map(|_| None); } // If we're resuming execution after resolving a foreign call then @@ -443,7 +475,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { Some(solver) => solver, None => BrilligSolver::new_call( - witness, + &self.witness_map, &self.block_solvers, inputs, &self.unconstrained_functions[*id as usize].bytecode, @@ -451,7 +483,10 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { self.instruction_pointer, )?, }; - match solver.solve()? { + + let result = solver.solve().map_err(|err| self.map_brillig_error(err))?; + + match result { BrilligSolverStatus::ForeignCallWait(foreign_call) => { // Cache the current state of the solver self.brillig_solver = Some(solver); @@ -462,33 +497,59 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { } BrilligSolverStatus::Finished => { // Write execution outputs - solver.finalize(witness, outputs)?; + solver.finalize(&mut self.witness_map, outputs)?; Ok(None) } } } - pub fn step_into_brillig_opcode(&mut self) -> StepResult<'a, B> { - let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] else { + fn map_brillig_error(&self, mut err: OpcodeResolutionError) -> OpcodeResolutionError { + match &mut err { + OpcodeResolutionError::BrilligFunctionFailed { call_stack, payload } => { + // Some brillig errors have static strings as payloads, we can resolve them here + let last_location = + call_stack.last().expect("Call stacks should have at least one item"); + let assertion_descriptor = + self.assertion_payloads.iter().find_map(|(loc, payload)| { + if loc == last_location { + Some(payload) + } else { + None + } + }); + + if let Some(AssertionPayload::StaticString(string)) = assertion_descriptor { + *payload = Some(ResolvedAssertionPayload::String(string.clone())); + } + + err + } + _ => err, + } + } + + pub fn step_into_brillig(&mut self) -> StepResult<'a, B> { + let Opcode::BrilligCall { id, inputs, outputs, predicate } = + &self.opcodes[self.instruction_pointer] + else { return StepResult::Status(self.solve_opcode()); }; let witness = &mut self.witness_map; - let should_skip = match BrilligSolver::::should_skip(witness, brillig) { + let should_skip = match is_predicate_false(witness, predicate) { Ok(result) => result, Err(err) => return StepResult::Status(self.handle_opcode_resolution(Err(err))), }; - if should_skip { - let resolution = - BrilligSolver::::zero_out_brillig_outputs(witness, &brillig.outputs); + let resolution = BrilligSolver::::zero_out_brillig_outputs(witness, outputs); return StepResult::Status(self.handle_opcode_resolution(resolution)); } - let solver = BrilligSolver::new( + let solver = BrilligSolver::new_call( witness, &self.block_solvers, - brillig, + inputs, + &self.unconstrained_functions[*id as usize].bytecode, self.backend, self.instruction_pointer, ); @@ -499,8 +560,8 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { } pub fn finish_brillig_with_solver(&mut self, solver: BrilligSolver<'a, B>) -> ACVMStatus { - if !matches!(&self.opcodes[self.instruction_pointer], Opcode::Brillig(..)) { - unreachable!("Not executing a Brillig opcode"); + if !matches!(self.opcodes[self.instruction_pointer], Opcode::BrilligCall { .. }) { + unreachable!("Not executing a Brillig/BrilligCall opcode"); } self.brillig_solver = Some(solver); self.solve_opcode() @@ -604,6 +665,7 @@ pub fn insert_value( if old_value != value_to_insert { return Err(OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Unresolved, + payload: None, }); } diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index f009e2c05b8..df61083eee4 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -1,9 +1,9 @@ use std::collections::BTreeMap; use acir::{ - brillig::{BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray}, + brillig::{BinaryFieldOp, HeapArray, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray}, circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, + brillig::{BrilligBytecode, BrilligInputs, BrilligOutputs}, opcodes::{BlockId, MemOp}, Opcode, OpcodeLocation, }, @@ -43,44 +43,26 @@ fn inversion_brillig_oracle_equivalence() { destination: MemoryAddress::from(2), }; - let brillig_data = Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - // Input Register 0 - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], - q_c: fe_0, - }), - BrilligInputs::Single(Expression::default()), // Input Register 1 - ], - // This tells the BrilligSolver which witnesses its output values correspond to - outputs: vec![ - BrilligOutputs::Simple(w_x_plus_y), // Output Register 0 - from input - BrilligOutputs::Simple(w_oracle), // Output Register 1 - BrilligOutputs::Simple(w_equal_res), // Output Register 2 - ], - bytecode: vec![ - BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(0), - size: 2, - offset: 0, - }, - equal_opcode, - // Oracles are named 'foreign calls' in brillig - BrilligOpcode::ForeignCall { - function: "invert".into(), - destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], - destination_value_types: vec![HeapValueType::field()], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], - input_value_types: vec![HeapValueType::field()], - }, - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 3 }, - ], - predicate: None, - }; - let opcodes = vec![ - Opcode::Brillig(brillig_data), + Opcode::BrilligCall { + id: 0, + inputs: vec![ + BrilligInputs::Single(Expression { + // Input Register 0 + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], + q_c: fe_0, + }), + BrilligInputs::Single(Expression::default()), // Input Register 1 + ], + // This tells the BrilligSolver which witnesses its output values correspond to + outputs: vec![ + BrilligOutputs::Simple(w_x_plus_y), // Output Register 0 - from input + BrilligOutputs::Simple(w_oracle), // Output Register 1 + BrilligOutputs::Simple(w_equal_res), // Output Register 2 + ], + predicate: None, + }, Opcode::AssertZero(Expression { mul_terms: vec![], linear_combinations: vec![(fe_1, w_x), (fe_1, w_y), (-fe_1, w_z)], @@ -99,14 +81,39 @@ fn inversion_brillig_oracle_equivalence() { }), ]; + let brillig_bytecode = BrilligBytecode { + bytecode: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(0), + size: 2, + offset: 0, + }, + equal_opcode, + // Oracles are named 'foreign calls' in brillig + BrilligOpcode::ForeignCall { + function: "invert".into(), + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::field()], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::field()], + }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 3 }, + ], + }; + let witness_assignments = BTreeMap::from([ (Witness(1), FieldElement::from(2u128)), (Witness(2), FieldElement::from(3u128)), ]) .into(); - let unconstrained_functions = vec![]; - let mut acvm = - ACVM::new(&StubbedBlackBoxSolver, &opcodes, witness_assignments, &unconstrained_functions); + let unconstrained_functions = vec![brillig_bytecode]; + let mut acvm = ACVM::new( + &StubbedBlackBoxSolver, + &opcodes, + witness_assignments, + &unconstrained_functions, + &[], + ); // use the partial witness generation solver with our acir program let solver_status = acvm.solve(); @@ -165,29 +172,52 @@ fn double_inversion_brillig_oracle() { destination: MemoryAddress::from(4), }; - let brillig_data = Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - // Input Register 0 - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], - q_c: fe_0, - }), - BrilligInputs::Single(Expression::default()), // Input Register 1 - BrilligInputs::Single(Expression { - // Input Register 2 - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_i), (fe_1, w_j)], - q_c: fe_0, - }), - ], - outputs: vec![ - BrilligOutputs::Simple(w_x_plus_y), // Output Register 0 - from input - BrilligOutputs::Simple(w_oracle), // Output Register 1 - BrilligOutputs::Simple(w_i_plus_j), // Output Register 2 - from input - BrilligOutputs::Simple(w_ij_oracle), // Output Register 3 - BrilligOutputs::Simple(w_equal_res), // Output Register 4 - ], + let opcodes = vec![ + Opcode::BrilligCall { + id: 0, + inputs: vec![ + BrilligInputs::Single(Expression { + // Input Register 0 + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], + q_c: fe_0, + }), + BrilligInputs::Single(Expression::default()), // Input Register 1 + BrilligInputs::Single(Expression { + // Input Register 2 + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_i), (fe_1, w_j)], + q_c: fe_0, + }), + ], + outputs: vec![ + BrilligOutputs::Simple(w_x_plus_y), // Output Register 0 - from input + BrilligOutputs::Simple(w_oracle), // Output Register 1 + BrilligOutputs::Simple(w_i_plus_j), // Output Register 2 - from input + BrilligOutputs::Simple(w_ij_oracle), // Output Register 3 + BrilligOutputs::Simple(w_equal_res), // Output Register 4 + ], + predicate: None, + }, + Opcode::AssertZero(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y), (-fe_1, w_z)], + q_c: fe_0, + }), + // Opcode::Directive(Directive::Invert { x: w_z, result: w_z_inverse }), + Opcode::AssertZero(Expression { + mul_terms: vec![(fe_1, w_z, w_z_inverse)], + linear_combinations: vec![], + q_c: -fe_1, + }), + Opcode::AssertZero(Expression { + mul_terms: vec![], + linear_combinations: vec![(-fe_1, w_oracle), (fe_1, w_z_inverse)], + q_c: fe_0, + }), + ]; + + let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::CalldataCopy { destination_address: MemoryAddress(0), @@ -212,29 +242,8 @@ fn double_inversion_brillig_oracle() { }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 5 }, ], - predicate: None, }; - let opcodes = vec![ - Opcode::Brillig(brillig_data), - Opcode::AssertZero(Expression { - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_x), (fe_1, w_y), (-fe_1, w_z)], - q_c: fe_0, - }), - // Opcode::Directive(Directive::Invert { x: w_z, result: w_z_inverse }), - Opcode::AssertZero(Expression { - mul_terms: vec![(fe_1, w_z, w_z_inverse)], - linear_combinations: vec![], - q_c: -fe_1, - }), - Opcode::AssertZero(Expression { - mul_terms: vec![], - linear_combinations: vec![(-fe_1, w_oracle), (fe_1, w_z_inverse)], - q_c: fe_0, - }), - ]; - let witness_assignments = BTreeMap::from([ (Witness(1), FieldElement::from(2u128)), (Witness(2), FieldElement::from(3u128)), @@ -242,9 +251,14 @@ fn double_inversion_brillig_oracle() { (Witness(9), FieldElement::from(10u128)), ]) .into(); - let unconstrained_functions = vec![]; - let mut acvm = - ACVM::new(&StubbedBlackBoxSolver, &opcodes, witness_assignments, &unconstrained_functions); + let unconstrained_functions = vec![brillig_bytecode]; + let mut acvm = ACVM::new( + &StubbedBlackBoxSolver, + &opcodes, + witness_assignments, + &unconstrained_functions, + &[], + ); // use the partial witness generation solver with our acir program let solver_status = acvm.solve(); @@ -311,18 +325,7 @@ fn oracle_dependent_execution() { let w_x_inv = Witness(3); let w_y_inv = Witness(4); - let brillig_data = Brillig { - inputs: vec![ - BrilligInputs::Single(w_x.into()), // Input Register 0 - BrilligInputs::Single(Expression::default()), // Input Register 1 - BrilligInputs::Single(w_y.into()), // Input Register 2, - ], - outputs: vec![ - BrilligOutputs::Simple(w_x), // Output Register 0 - from input - BrilligOutputs::Simple(w_y_inv), // Output Register 1 - BrilligOutputs::Simple(w_y), // Output Register 2 - from input - BrilligOutputs::Simple(w_y_inv), // Output Register 3 - ], + let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::CalldataCopy { destination_address: MemoryAddress(0), @@ -346,7 +349,6 @@ fn oracle_dependent_execution() { }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 4 }, ], - predicate: None, }; // This equality check can be executed immediately before resolving any foreign calls. @@ -366,15 +368,34 @@ fn oracle_dependent_execution() { let opcodes = vec![ Opcode::AssertZero(equality_check), - Opcode::Brillig(brillig_data), + Opcode::BrilligCall { + id: 0, + inputs: vec![ + BrilligInputs::Single(w_x.into()), // Input Register 0 + BrilligInputs::Single(Expression::default()), // Input Register 1 + BrilligInputs::Single(w_y.into()), // Input Register 2, + ], + outputs: vec![ + BrilligOutputs::Simple(w_x), // Output Register 0 - from input + BrilligOutputs::Simple(w_y_inv), // Output Register 1 + BrilligOutputs::Simple(w_y), // Output Register 2 - from input + BrilligOutputs::Simple(w_y_inv), // Output Register 3 + ], + predicate: None, + }, Opcode::AssertZero(inverse_equality_check), ]; let witness_assignments = BTreeMap::from([(w_x, FieldElement::from(2u128)), (w_y, FieldElement::from(2u128))]).into(); - let unconstrained_functions = vec![]; - let mut acvm = - ACVM::new(&StubbedBlackBoxSolver, &opcodes, witness_assignments, &unconstrained_functions); + let unconstrained_functions = vec![brillig_bytecode]; + let mut acvm = ACVM::new( + &StubbedBlackBoxSolver, + &opcodes, + witness_assignments, + &unconstrained_functions, + &[], + ); // use the partial witness generation solver with our acir program let solver_status = acvm.solve(); @@ -436,21 +457,7 @@ fn brillig_oracle_predicate() { destination: MemoryAddress::from(2), }; - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], - q_c: fe_0, - }), - BrilligInputs::Single(Expression::default()), - ], - outputs: vec![ - BrilligOutputs::Simple(w_x_plus_y), - BrilligOutputs::Simple(w_oracle), - BrilligOutputs::Simple(w_equal_res), - BrilligOutputs::Simple(w_lt_res), - ], + let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::CalldataCopy { destination_address: MemoryAddress(0), @@ -467,19 +474,40 @@ fn brillig_oracle_predicate() { input_value_types: vec![HeapValueType::field()], }, ], - predicate: Some(Expression::default()), - }); + }; - let opcodes = vec![brillig_opcode]; + let opcodes = vec![Opcode::BrilligCall { + id: 0, + inputs: vec![ + BrilligInputs::Single(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x), (fe_1, w_y)], + q_c: fe_0, + }), + BrilligInputs::Single(Expression::default()), + ], + outputs: vec![ + BrilligOutputs::Simple(w_x_plus_y), + BrilligOutputs::Simple(w_oracle), + BrilligOutputs::Simple(w_equal_res), + BrilligOutputs::Simple(w_lt_res), + ], + predicate: Some(Expression::default()), + }]; let witness_assignments = BTreeMap::from([ (Witness(1), FieldElement::from(2u128)), (Witness(2), FieldElement::from(3u128)), ]) .into(); - let unconstrained_functions = vec![]; - let mut acvm = - ACVM::new(&StubbedBlackBoxSolver, &opcodes, witness_assignments, &unconstrained_functions); + let unconstrained_functions = vec![brillig_bytecode]; + let mut acvm = ACVM::new( + &StubbedBlackBoxSolver, + &opcodes, + witness_assignments, + &unconstrained_functions, + &[], + ); let solver_status = acvm.solve(); assert_eq!(solver_status, ACVMStatus::Solved, "should be fully solved"); @@ -514,12 +542,14 @@ fn unsatisfied_opcode_resolved() { let opcodes = vec![Opcode::AssertZero(opcode_a)]; let unconstrained_functions = vec![]; - let mut acvm = ACVM::new(&StubbedBlackBoxSolver, &opcodes, values, &unconstrained_functions); + let mut acvm = + ACVM::new(&StubbedBlackBoxSolver, &opcodes, values, &unconstrained_functions, &[]); let solver_status = acvm.solve(); assert_eq!( solver_status, ACVMStatus::Failure(OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Resolved(OpcodeLocation::Acir(0)), + payload: None }), "The first opcode is not satisfiable, expected an error indicating this" ); @@ -554,26 +584,12 @@ fn unsatisfied_opcode_resolved_brillig() { let jmp_if_opcode = BrilligOpcode::JumpIf { condition: MemoryAddress::from(2), location: location_of_stop }; - let trap_opcode = BrilligOpcode::Trap { revert_data_offset: 0, revert_data_size: 0 }; + let trap_opcode = BrilligOpcode::Trap { revert_data: HeapArray::default() }; let stop_opcode = BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }; - let brillig_opcode = Opcode::Brillig(Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_x)], - q_c: fe_0, - }), - BrilligInputs::Single(Expression { - mul_terms: vec![], - linear_combinations: vec![(fe_1, w_y)], - q_c: fe_0, - }), - ], - outputs: vec![BrilligOutputs::Simple(w_result)], + let brillig_bytecode = BrilligBytecode { bytecode: vec![calldata_copy_opcode, equal_opcode, jmp_if_opcode, trap_opcode, stop_opcode], - predicate: Some(Expression::one()), - }); + }; let opcode_a = Expression { mul_terms: vec![], @@ -595,14 +611,34 @@ fn unsatisfied_opcode_resolved_brillig() { values.insert(w_y, FieldElement::from(1_i128)); values.insert(w_result, FieldElement::from(0_i128)); - let opcodes = vec![brillig_opcode, Opcode::AssertZero(opcode_a)]; - let unconstrained_functions = vec![]; - let mut acvm = ACVM::new(&StubbedBlackBoxSolver, &opcodes, values, &unconstrained_functions); + let opcodes = vec![ + Opcode::BrilligCall { + id: 0, + inputs: vec![ + BrilligInputs::Single(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_x)], + q_c: fe_0, + }), + BrilligInputs::Single(Expression { + mul_terms: vec![], + linear_combinations: vec![(fe_1, w_y)], + q_c: fe_0, + }), + ], + outputs: vec![BrilligOutputs::Simple(w_result)], + predicate: Some(Expression::one()), + }, + Opcode::AssertZero(opcode_a), + ]; + let unconstrained_functions = vec![brillig_bytecode]; + let mut acvm = + ACVM::new(&StubbedBlackBoxSolver, &opcodes, values, &unconstrained_functions, &[]); let solver_status = acvm.solve(); assert_eq!( solver_status, ACVMStatus::Failure(OpcodeResolutionError::BrilligFunctionFailed { - message: None, + payload: None, call_stack: vec![OpcodeLocation::Brillig { acir_index: 0, brillig_index: 3 }] }), "The first opcode is not satisfiable, expected an error indicating this" @@ -642,7 +678,7 @@ fn memory_operations() { let opcodes = vec![init, read_op, expression]; let unconstrained_functions = vec![]; let mut acvm = - ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions); + ACVM::new(&StubbedBlackBoxSolver, &opcodes, initial_witness, &unconstrained_functions, &[]); let solver_status = acvm.solve(); assert_eq!(solver_status, ACVMStatus::Solved); let witness_map = acvm.finalize(); diff --git a/acvm-repo/acvm_js/Cargo.toml b/acvm-repo/acvm_js/Cargo.toml index 4635dc8663e..1675d601351 100644 --- a/acvm-repo/acvm_js/Cargo.toml +++ b/acvm-repo/acvm_js/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_js" description = "Typescript wrapper around the ACVM allowing execution of ACIR code" # x-release-please-start-version -version = "0.43.0" +version = "0.45.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/acvm_js/build.sh b/acvm-repo/acvm_js/build.sh index 16fb26e55db..c07d2d8a4c1 100755 --- a/acvm-repo/acvm_js/build.sh +++ b/acvm-repo/acvm_js/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -require_command wasm-opt +#require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/acvm-repo/acvm_js/package.json b/acvm-repo/acvm_js/package.json index 63f12942018..5be2f164ac4 100644 --- a/acvm-repo/acvm_js/package.json +++ b/acvm-repo/acvm_js/package.json @@ -1,6 +1,6 @@ { "name": "@noir-lang/acvm_js", - "version": "0.43.0", + "version": "0.45.0", "publishConfig": { "access": "public" }, diff --git a/acvm-repo/acvm_js/src/execute.rs b/acvm-repo/acvm_js/src/execute.rs index 2fab684467e..338511874c9 100644 --- a/acvm-repo/acvm_js/src/execute.rs +++ b/acvm-repo/acvm_js/src/execute.rs @@ -1,6 +1,7 @@ use std::{future::Future, pin::Pin}; use acvm::acir::circuit::brillig::BrilligBytecode; +use acvm::acir::circuit::ResolvedAssertionPayload; use acvm::BlackBoxFunctionSolver; use acvm::{ acir::circuit::{Circuit, Program}, @@ -78,7 +79,7 @@ pub async fn execute_circuit_with_return_witness( console_error_panic_hook::set_once(); let program: Program = Program::deserialize_program(&program) - .map_err(|_| JsExecutionError::new("Failed to deserialize circuit. This is likely due to differing serialization formats between ACVM_JS and your compiler".to_string(), None))?; + .map_err(|_| JsExecutionError::new("Failed to deserialize circuit. This is likely due to differing serialization formats between ACVM_JS and your compiler".to_string(), None, None))?; let mut witness_stack = execute_program_with_native_program_and_return( solver, @@ -93,7 +94,7 @@ pub async fn execute_circuit_with_return_witness( let main_circuit = &program.functions[0]; let return_witness = extract_indices(&solved_witness, main_circuit.return_values.0.iter().copied().collect()) - .map_err(|err| JsExecutionError::new(err, None))?; + .map_err(|err| JsExecutionError::new(err, None, None))?; Ok((solved_witness, return_witness).into()) } @@ -165,7 +166,10 @@ async fn execute_program_with_native_type_return( foreign_call_executor: &ForeignCallHandler, ) -> Result { let program: Program = Program::deserialize_program(&program) - .map_err(|_| JsExecutionError::new("Failed to deserialize circuit. This is likely due to differing serialization formats between ACVM_JS and your compiler".to_string(), None))?; + .map_err(|_| JsExecutionError::new( + "Failed to deserialize circuit. This is likely due to differing serialization formats between ACVM_JS and your compiler".to_string(), + None, + None))?; execute_program_with_native_program_and_return( solver, @@ -239,6 +243,7 @@ impl<'a, B: BlackBoxFunctionSolver> ProgramExecutor<'a, B> { &circuit.opcodes, initial_witness, self.unconstrained_functions, + &circuit.assert_messages, ); loop { @@ -250,39 +255,48 @@ impl<'a, B: BlackBoxFunctionSolver> ProgramExecutor<'a, B> { unreachable!("Execution should not stop while in `InProgress` state.") } ACVMStatus::Failure(error) => { - let (assert_message, call_stack): (Option<&str>, _) = match &error { + // Fetch call stack + let call_stack = match &error { OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Resolved(opcode_location), + .. } | OpcodeResolutionError::IndexOutOfBounds { opcode_location: ErrorLocation::Resolved(opcode_location), .. - } => ( - circuit.get_assert_message(*opcode_location), - Some(vec![*opcode_location]), - ), - OpcodeResolutionError::BrilligFunctionFailed { - call_stack, - message, - } => { - let revert_message = message.as_ref().map(String::as_str); - let failing_opcode = call_stack - .last() - .expect("Brillig error call stacks cannot be empty"); - ( - revert_message.or(circuit.get_assert_message(*failing_opcode)), - Some(call_stack.clone()), - ) + } => Some(vec![*opcode_location]), + OpcodeResolutionError::BrilligFunctionFailed { call_stack, .. } => { + Some(call_stack.clone()) } - _ => (None, None), + _ => None, }; - - let error_string = match &assert_message { - Some(assert_message) => format!("Assertion failed: {}", assert_message), - None => error.to_string(), + // If the failed opcode has an assertion message, integrate it into the error message for backwards compatibility. + // Otherwise, pass the raw assertion payload as is. + let (message, raw_assertion_payload) = match error { + OpcodeResolutionError::UnsatisfiedConstrain { + payload: Some(payload), + .. + } + | OpcodeResolutionError::BrilligFunctionFailed { + payload: Some(payload), + .. + } => match payload { + ResolvedAssertionPayload::Raw(raw_payload) => { + ("Assertion failed".to_string(), Some(raw_payload)) + } + ResolvedAssertionPayload::String(message) => { + (format!("Assertion failed: {}", message), None) + } + }, + _ => (error.to_string(), None), }; - return Err(JsExecutionError::new(error_string, call_stack).into()); + return Err(JsExecutionError::new( + message, + call_stack, + raw_assertion_payload, + ) + .into()); } ACVMStatus::RequiresForeignCall(foreign_call) => { let result = @@ -304,7 +318,7 @@ impl<'a, B: BlackBoxFunctionSolver> ProgramExecutor<'a, B> { call_resolved_outputs.push(*return_value); } else { // TODO: look at changing this call stack from None - return Err(JsExecutionError::new(format!("Failed to read from solved witness of ACIR call at witness {}", return_witness_index), None).into()); + return Err(JsExecutionError::new(format!("Failed to read from solved witness of ACIR call at witness {}", return_witness_index), None, None).into()); } } acvm.resolve_pending_acir_call(call_resolved_outputs); diff --git a/acvm-repo/acvm_js/src/js_execution_error.rs b/acvm-repo/acvm_js/src/js_execution_error.rs index d91a9425f7e..b34ea5ddb60 100644 --- a/acvm-repo/acvm_js/src/js_execution_error.rs +++ b/acvm-repo/acvm_js/src/js_execution_error.rs @@ -1,11 +1,17 @@ -use acvm::acir::circuit::OpcodeLocation; +use acvm::acir::circuit::{OpcodeLocation, RawAssertionPayload}; +use gloo_utils::format::JsValueSerdeExt; use js_sys::{Array, Error, JsString, Reflect}; use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; #[wasm_bindgen(typescript_custom_section)] const EXECUTION_ERROR: &'static str = r#" +export type RawAssertionPayload = { + selector: string; + data: string[]; +}; export type ExecutionError = Error & { callStack?: string[]; + rawAssertionPayload?: RawAssertionPayload; }; "#; @@ -25,7 +31,11 @@ extern "C" { impl JsExecutionError { /// Creates a new execution error with the given call stack. /// Call stacks won't be optional in the future, after removing ErrorLocation in ACVM. - pub fn new(message: String, call_stack: Option>) -> Self { + pub fn new( + message: String, + call_stack: Option>, + assertion_payload: Option, + ) -> Self { let mut error = JsExecutionError::constructor(JsString::from(message)); let js_call_stack = match call_stack { Some(call_stack) => { @@ -37,8 +47,14 @@ impl JsExecutionError { } None => JsValue::UNDEFINED, }; + let assertion_payload = match assertion_payload { + Some(raw) => ::from_serde(&raw) + .expect("Cannot serialize assertion payload"), + None => JsValue::UNDEFINED, + }; error.set_property("callStack", js_call_stack); + error.set_property("rawAssertionPayload", assertion_payload); error } diff --git a/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts b/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts index 259c51ed1c6..625cc91cfe9 100644 --- a/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts +++ b/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts @@ -93,8 +93,8 @@ it('successfully executes a Pedersen opcode', async function () { expect(solvedWitness).to.be.deep.eq(expectedWitnessMap); }); -it('successfully executes a FixedBaseScalarMul opcode', async () => { - const { bytecode, initialWitnessMap, expectedWitnessMap } = await import('../shared/fixed_base_scalar_mul'); +it('successfully executes a MultiScalarMul opcode', async () => { + const { bytecode, initialWitnessMap, expectedWitnessMap } = await import('../shared/multi_scalar_mul'); const solvedWitness: WitnessMap = await executeCircuit(bytecode, initialWitnessMap, () => { throw Error('unexpected oracle'); diff --git a/acvm-repo/acvm_js/test/node/execute_circuit.test.ts b/acvm-repo/acvm_js/test/node/execute_circuit.test.ts index 32487f8bbba..3f9bde2898e 100644 --- a/acvm-repo/acvm_js/test/node/execute_circuit.test.ts +++ b/acvm-repo/acvm_js/test/node/execute_circuit.test.ts @@ -90,8 +90,8 @@ it('successfully executes a Pedersen opcode', async function () { expect(solvedWitness).to.be.deep.eq(expectedWitnessMap); }); -it('successfully executes a FixedBaseScalarMul opcode', async () => { - const { bytecode, initialWitnessMap, expectedWitnessMap } = await import('../shared/fixed_base_scalar_mul'); +it('successfully executes a MultiScalarMul opcode', async () => { + const { bytecode, initialWitnessMap, expectedWitnessMap } = await import('../shared/multi_scalar_mul'); const solvedWitness: WitnessMap = await executeCircuit(bytecode, initialWitnessMap, () => { throw Error('unexpected oracle'); diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index 722bae8e015..0d6fab0e1f3 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,13 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 77, 218, 209, 145, 217, 205, 13, 6, 198, 3, 84, 79, - 224, 93, 196, 157, 162, 75, 79, 47, 22, 124, 197, 16, 186, 17, 43, 104, 32, 36, 109, 126, 143, 36, 45, 211, 70, 133, - 103, 134, 110, 61, 27, 232, 140, 179, 164, 224, 215, 64, 186, 115, 84, 113, 186, 92, 238, 42, 140, 230, 1, 24, 237, 5, - 24, 195, 62, 220, 116, 222, 41, 231, 146, 180, 127, 54, 242, 126, 94, 158, 51, 207, 57, 206, 111, 200, 2, 247, 4, 219, - 79, 245, 157, 132, 31, 137, 89, 52, 73, 176, 214, 46, 167, 125, 23, 89, 213, 254, 8, 156, 237, 56, 76, 125, 55, 91, - 229, 170, 161, 254, 133, 94, 42, 59, 171, 184, 69, 197, 46, 66, 202, 47, 40, 86, 39, 220, 155, 3, 185, 191, 180, 183, - 55, 163, 72, 98, 70, 66, 221, 251, 40, 173, 255, 35, 68, 62, 61, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 131, 64, 12, 77, 102, 90, 43, 221, 245, 6, 133, 246, 0, 211, 158, + 192, 187, 136, 59, 69, 151, 158, 94, 116, 48, 131, 241, 233, 70, 28, 65, 3, 195, 155, 79, 62, 47, 9, 25, 166, 81, 210, + 97, 177, 236, 239, 130, 70, 208, 223, 91, 154, 75, 208, 205, 4, 221, 62, 249, 113, 60, 95, 238, 40, 142, 230, 2, 28, + 237, 1, 28, 73, 245, 255, 132, 253, 142, 217, 151, 168, 245, 179, 43, 243, 115, 163, 113, 190, 18, 57, 63, 4, 83, 44, + 180, 55, 50, 180, 28, 188, 153, 224, 196, 122, 175, 111, 112, 68, 24, 65, 50, 204, 162, 100, 249, 119, 137, 226, 193, + 16, 251, 169, 50, 204, 235, 170, 41, 139, 214, 130, 42, 82, 253, 168, 253, 23, 222, 25, 236, 58, 176, 237, 20, 234, + 207, 107, 45, 78, 184, 55, 27, 124, 191, 104, 42, 111, 40, 121, 15, 94, 163, 77, 128, 65, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts b/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts deleted file mode 100644 index 97b5041121a..00000000000 --- a/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts +++ /dev/null @@ -1,17 +0,0 @@ -// See `fixed_base_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. -export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 138, 81, 10, 0, 48, 8, 66, 87, 219, 190, 118, 233, 29, 61, 35, 3, 19, 228, 137, - 60, 91, 149, 139, 26, 119, 242, 145, 31, 117, 114, 163, 135, 142, 139, 219, 91, 127, 117, 71, 2, 117, 84, 50, 98, 113, - 0, 0, 0, -]); -export const initialWitnessMap = new Map([ - [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [2, '0x0000000000000000000000000000000000000000000000000000000000000000'], -]); - -export const expectedWitnessMap = new Map([ - [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [2, '0x0000000000000000000000000000000000000000000000000000000000000000'], - [3, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [4, '0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c'], -]); diff --git a/acvm-repo/acvm_js/test/shared/foreign_call.ts b/acvm-repo/acvm_js/test/shared/foreign_call.ts index 0e3d77f62a9..3c66ba18629 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 61, 10, 192, 32, 12, 133, 19, 11, 165, 116, 235, 77, 236, 13, 122, 153, - 14, 93, 58, 136, 120, 124, 241, 47, 129, 12, 42, 130, 126, 16, 18, 146, 16, 222, 11, 66, 225, 136, 129, 84, 111, 162, - 150, 112, 239, 161, 172, 231, 184, 113, 221, 45, 45, 245, 42, 242, 144, 216, 43, 250, 153, 83, 204, 191, 223, 189, - 198, 246, 92, 39, 60, 244, 63, 195, 59, 87, 99, 150, 165, 113, 83, 193, 0, 1, 19, 247, 29, 5, 160, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 193, 10, 192, 32, 8, 134, 117, 99, 99, 236, 182, 55, 105, 111, 176, 151, + 217, 161, 75, 135, 136, 30, 63, 42, 82, 144, 8, 47, 245, 65, 252, 230, 47, 162, 34, 52, 174, 242, 144, 226, 131, 148, + 255, 18, 206, 125, 164, 102, 142, 23, 215, 245, 50, 114, 222, 173, 15, 80, 38, 65, 217, 108, 39, 61, 7, 30, 115, 11, + 223, 186, 248, 251, 160, 221, 170, 146, 64, 191, 39, 215, 60, 3, 47, 3, 99, 171, 188, 84, 164, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/acvm_js/test/shared/memory_op.ts b/acvm-repo/acvm_js/test/shared/memory_op.ts index a69ae443259..20ea88c7130 100644 --- a/acvm-repo/acvm_js/test/shared/memory_op.ts +++ b/acvm-repo/acvm_js/test/shared/memory_op.ts @@ -1,9 +1,9 @@ // See `memory_op_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 81, 57, 14, 0, 32, 8, 147, 195, 255, 224, 15, 252, 255, 171, 212, 200, 208, - 129, 77, 24, 108, 66, 90, 150, 166, 20, 106, 23, 125, 143, 128, 62, 96, 103, 114, 173, 45, 198, 116, 182, 55, 140, - 106, 95, 74, 246, 149, 60, 47, 171, 46, 215, 126, 43, 87, 179, 111, 23, 8, 202, 176, 99, 248, 240, 9, 11, 137, 33, - 212, 110, 35, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 82, 65, 10, 0, 32, 8, 203, 180, 255, 216, 15, 250, 255, 171, 10, 154, 16, 210, + 45, 61, 52, 144, 13, 132, 49, 135, 84, 54, 218, 26, 134, 22, 112, 5, 19, 180, 237, 61, 6, 88, 223, 208, 179, 125, 41, + 216, 151, 227, 188, 52, 187, 92, 253, 173, 92, 137, 190, 157, 143, 160, 254, 155, 45, 188, 148, 11, 38, 213, 237, 188, + 16, 35, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts b/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts new file mode 100644 index 00000000000..8ee0a067a3a --- /dev/null +++ b/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts @@ -0,0 +1,21 @@ +// See `multi_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. +export const bytecode = Uint8Array.from([ + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 76, 65, 14, 0, 32, 8, 82, 179, 186, 244, 104, 159, 30, 45, 218, 136, 141, 33, + 40, 186, 93, 76, 208, 57, 31, 93, 96, 136, 47, 250, 146, 188, 209, 39, 181, 131, 131, 187, 148, 110, 240, 246, 101, + 38, 63, 180, 243, 97, 3, 125, 173, 118, 131, 153, 0, 0, 0, +]); +export const initialWitnessMap = new Map([ + [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [2, '0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c'], + [3, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [4, '0x0000000000000000000000000000000000000000000000000000000000000000'], +]); + +export const expectedWitnessMap = new Map([ + [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [2, '0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c'], + [3, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [4, '0x0000000000000000000000000000000000000000000000000000000000000000'], + [5, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [6, '0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c'], +]); diff --git a/acvm-repo/acvm_js/test/shared/nested_acir_call.ts b/acvm-repo/acvm_js/test/shared/nested_acir_call.ts index 4b73d01bb01..64051dff93f 100644 --- a/acvm-repo/acvm_js/test/shared/nested_acir_call.ts +++ b/acvm-repo/acvm_js/test/shared/nested_acir_call.ts @@ -2,13 +2,13 @@ import { WitnessMap, StackItem, WitnessStack } from '@noir-lang/acvm_js'; // See `nested_acir_call_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 205, 146, 65, 10, 3, 33, 12, 69, 163, 46, 230, 58, 137, 209, 49, 238, 122, 149, 74, - 157, 251, 31, 161, 83, 154, 161, 86, 132, 89, 212, 194, 124, 248, 24, 36, 132, 228, 241, 29, 188, 229, 212, 47, 45, - 187, 205, 110, 11, 31, 25, 53, 28, 255, 103, 77, 14, 58, 29, 141, 55, 125, 241, 55, 145, 109, 102, 49, 174, 33, 212, - 228, 43, 49, 221, 209, 231, 34, 17, 67, 44, 171, 144, 80, 148, 248, 240, 194, 92, 37, 72, 202, 37, 39, 204, 20, 184, - 210, 22, 51, 111, 58, 204, 205, 219, 11, 161, 129, 208, 214, 6, 6, 114, 29, 193, 127, 193, 130, 137, 176, 236, 188, - 189, 252, 162, 183, 218, 230, 238, 97, 138, 250, 152, 245, 245, 87, 220, 12, 140, 113, 95, 153, 170, 129, 185, 17, 60, - 3, 54, 212, 19, 104, 145, 195, 151, 14, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 205, 146, 97, 10, 195, 32, 12, 133, 163, 66, 207, 147, 24, 173, 241, 223, 174, 50, + 153, 189, 255, 17, 214, 177, 148, 57, 17, 250, 99, 14, 250, 224, 97, 144, 16, 146, 143, 231, 224, 45, 167, 126, 105, + 217, 109, 118, 91, 248, 200, 168, 225, 248, 63, 107, 114, 208, 233, 104, 188, 233, 139, 191, 137, 108, 51, 139, 113, + 13, 161, 38, 95, 137, 233, 142, 62, 23, 137, 24, 98, 89, 133, 132, 162, 196, 135, 23, 230, 42, 65, 82, 46, 57, 97, + 166, 192, 149, 182, 152, 121, 211, 97, 110, 222, 94, 8, 13, 132, 182, 54, 48, 144, 235, 8, 254, 11, 22, 76, 132, 101, + 231, 237, 229, 23, 189, 213, 54, 119, 15, 83, 212, 199, 172, 175, 191, 226, 102, 96, 140, 251, 202, 84, 13, 204, 141, + 224, 25, 176, 161, 158, 53, 121, 144, 73, 14, 4, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ diff --git a/acvm-repo/acvm_js/test/shared/pedersen.ts b/acvm-repo/acvm_js/test/shared/pedersen.ts index e8ddc893d87..6e3ec403d65 100644 --- a/acvm-repo/acvm_js/test/shared/pedersen.ts +++ b/acvm-repo/acvm_js/test/shared/pedersen.ts @@ -1,7 +1,7 @@ // See `pedersen_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 9, 10, 0, 0, 4, 115, 149, 255, 127, 88, 8, 133, 213, 218, 137, 80, 144, 32, - 182, 79, 213, 151, 173, 61, 5, 121, 245, 91, 103, 255, 191, 3, 7, 16, 26, 112, 158, 113, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 73, 10, 0, 0, 4, 180, 29, 252, 255, 193, 66, 40, 76, 77, 179, 34, 20, 36, + 136, 237, 83, 245, 101, 107, 79, 65, 94, 253, 214, 217, 255, 239, 192, 1, 43, 124, 181, 238, 113, 0, 0, 0, ]); export const initialWitnessMap = new Map([[1, '0x0000000000000000000000000000000000000000000000000000000000000001']]); diff --git a/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/acvm-repo/acvm_js/test/shared/schnorr_verify.ts index a207aa12b2c..05fcc47e3aa 100644 --- a/acvm-repo/acvm_js/test/shared/schnorr_verify.ts +++ b/acvm-repo/acvm_js/test/shared/schnorr_verify.ts @@ -2,7 +2,7 @@ export const bytecode = Uint8Array.from([ 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 210, 85, 78, 67, 81, 24, 133, 209, 226, 238, 238, 238, 238, 238, 165, 148, 82, 102, 193, 252, 135, 64, 232, 78, 87, 147, 114, 147, 147, 5, 47, 132, 252, 251, 107, 41, 212, 191, 159, 218, 107, 241, - 115, 236, 228, 111, 237, 181, 178, 173, 246, 186, 107, 175, 157, 29, 236, 100, 23, 27, 175, 135, 189, 236, 99, 63, 7, + 115, 236, 226, 111, 237, 181, 178, 173, 246, 186, 107, 175, 157, 29, 236, 100, 23, 27, 175, 135, 189, 236, 99, 63, 7, 56, 200, 33, 14, 115, 132, 163, 28, 227, 56, 39, 56, 201, 41, 78, 115, 134, 179, 156, 227, 60, 23, 184, 200, 37, 46, 115, 133, 171, 92, 227, 58, 55, 184, 201, 45, 110, 115, 135, 187, 220, 227, 62, 15, 120, 200, 35, 30, 243, 132, 167, 60, 227, 57, 47, 120, 201, 43, 94, 243, 134, 183, 188, 227, 61, 31, 248, 200, 39, 62, 243, 133, 175, 77, 59, 230, 123, @@ -11,7 +11,7 @@ export const bytecode = Uint8Array.from([ 210, 72, 250, 72, 27, 233, 34, 77, 164, 135, 180, 144, 14, 210, 64, 246, 95, 46, 212, 119, 207, 230, 217, 59, 91, 103, 231, 108, 156, 125, 183, 237, 186, 107, 207, 125, 59, 30, 218, 239, 216, 110, 167, 246, 58, 183, 211, 165, 125, 174, 237, 114, 107, 143, 123, 59, 60, 186, 255, 179, 187, 191, 186, 115, 209, 125, 75, 238, 90, 118, 207, 138, 59, 54, 110, - 214, 184, 91, 161, 233, 158, 255, 190, 63, 165, 188, 93, 151, 233, 3, 0, 0, + 214, 184, 91, 161, 233, 158, 255, 190, 63, 71, 59, 68, 130, 233, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm-repo/blackbox_solver/Cargo.toml b/acvm-repo/blackbox_solver/Cargo.toml index 1d6629c8223..f40046acad6 100644 --- a/acvm-repo/blackbox_solver/Cargo.toml +++ b/acvm-repo/blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "acvm_blackbox_solver" description = "A solver for the blackbox functions found in ACIR and Brillig" # x-release-please-start-version -version = "0.43.0" +version = "0.45.0" # x-release-please-end authors.workspace = true edition.workspace = true @@ -37,6 +37,7 @@ p256 = { version = "0.11.0", features = [ "arithmetic", ] } +libaes = "0.7.0" [features] default = ["bn254"] diff --git a/acvm-repo/blackbox_solver/src/aes128.rs b/acvm-repo/blackbox_solver/src/aes128.rs new file mode 100644 index 00000000000..a4c6a228744 --- /dev/null +++ b/acvm-repo/blackbox_solver/src/aes128.rs @@ -0,0 +1,12 @@ +use crate::BlackBoxResolutionError; +use libaes::Cipher; + +pub fn aes128_encrypt( + inputs: &[u8], + iv: [u8; 16], + key: [u8; 16], +) -> Result, BlackBoxResolutionError> { + let cipher = Cipher::new_128(&key); + let encrypted = cipher.cbc_encrypt(&iv, inputs); + Ok(encrypted) +} diff --git a/acvm-repo/blackbox_solver/src/curve_specific_solver.rs b/acvm-repo/blackbox_solver/src/curve_specific_solver.rs index fab67467d9a..3403b0fe232 100644 --- a/acvm-repo/blackbox_solver/src/curve_specific_solver.rs +++ b/acvm-repo/blackbox_solver/src/curve_specific_solver.rs @@ -24,10 +24,10 @@ pub trait BlackBoxFunctionSolver { inputs: &[FieldElement], domain_separator: u32, ) -> Result; - fn fixed_base_scalar_mul( + fn multi_scalar_mul( &self, - low: &FieldElement, - high: &FieldElement, + points: &[FieldElement], + scalars: &[FieldElement], ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError>; fn ec_add( &self, @@ -78,12 +78,12 @@ impl BlackBoxFunctionSolver for StubbedBlackBoxSolver { ) -> Result { Err(Self::fail(BlackBoxFunc::PedersenHash)) } - fn fixed_base_scalar_mul( + fn multi_scalar_mul( &self, - _low: &FieldElement, - _high: &FieldElement, + _points: &[FieldElement], + _scalars: &[FieldElement], ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - Err(Self::fail(BlackBoxFunc::FixedBaseScalarMul)) + Err(Self::fail(BlackBoxFunc::MultiScalarMul)) } fn ec_add( &self, diff --git a/acvm-repo/blackbox_solver/src/lib.rs b/acvm-repo/blackbox_solver/src/lib.rs index 0f57f2ce7da..a68b52a2a62 100644 --- a/acvm-repo/blackbox_solver/src/lib.rs +++ b/acvm-repo/blackbox_solver/src/lib.rs @@ -10,11 +10,13 @@ use acir::BlackBoxFunc; use thiserror::Error; +mod aes128; mod bigint; mod curve_specific_solver; mod ecdsa; mod hash; +pub use aes128::aes128_encrypt; pub use bigint::BigIntSolver; pub use curve_specific_solver::{BlackBoxFunctionSolver, StubbedBlackBoxSolver}; pub use ecdsa::{ecdsa_secp256k1_verify, ecdsa_secp256r1_verify}; diff --git a/acvm-repo/bn254_blackbox_solver/Cargo.toml b/acvm-repo/bn254_blackbox_solver/Cargo.toml index 448642e1a9e..3a6c9b1d55b 100644 --- a/acvm-repo/bn254_blackbox_solver/Cargo.toml +++ b/acvm-repo/bn254_blackbox_solver/Cargo.toml @@ -2,7 +2,7 @@ name = "bn254_blackbox_solver" description = "Solvers for black box functions which are specific for the bn254 curve" # x-release-please-start-version -version = "0.43.0" +version = "0.45.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/bn254_blackbox_solver/src/embedded_curve_ops.rs b/acvm-repo/bn254_blackbox_solver/src/embedded_curve_ops.rs new file mode 100644 index 00000000000..3f6d2ac86c1 --- /dev/null +++ b/acvm-repo/bn254_blackbox_solver/src/embedded_curve_ops.rs @@ -0,0 +1,241 @@ +// TODO(https://github.com/noir-lang/noir/issues/4932): rename this file to something more generic +use ark_ec::AffineRepr; +use ark_ff::MontConfig; +use num_bigint::BigUint; + +use acir::{BlackBoxFunc, FieldElement}; + +use crate::BlackBoxResolutionError; + +/// Performs multi scalar multiplication of points with scalars. +pub fn multi_scalar_mul( + points: &[FieldElement], + scalars: &[FieldElement], +) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { + if points.len() != scalars.len() { + return Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::MultiScalarMul, + "Points and scalars must have the same length".to_string(), + )); + } + + let mut output_point = grumpkin::SWAffine::zero(); + + for i in (0..points.len()).step_by(2) { + let point = create_point(points[i], points[i + 1]) + .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::MultiScalarMul, e))?; + + let scalar_low: u128 = scalars[i].try_into_u128().ok_or_else(|| { + BlackBoxResolutionError::Failed( + BlackBoxFunc::MultiScalarMul, + format!("Limb {} is not less than 2^128", scalars[i].to_hex()), + ) + })?; + + let scalar_high: u128 = scalars[i + 1].try_into_u128().ok_or_else(|| { + BlackBoxResolutionError::Failed( + BlackBoxFunc::MultiScalarMul, + format!("Limb {} is not less than 2^128", scalars[i + 1].to_hex()), + ) + })?; + + let mut bytes = scalar_high.to_be_bytes().to_vec(); + bytes.extend_from_slice(&scalar_low.to_be_bytes()); + + // Check if this is smaller than the grumpkin modulus + let grumpkin_integer = BigUint::from_bytes_be(&bytes); + + if grumpkin_integer >= grumpkin::FrConfig::MODULUS.into() { + return Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::MultiScalarMul, + format!("{} is not a valid grumpkin scalar", grumpkin_integer.to_str_radix(16)), + )); + } + + let iteration_output_point = + grumpkin::SWAffine::from(point.mul_bigint(grumpkin_integer.to_u64_digits())); + + output_point = grumpkin::SWAffine::from(output_point + iteration_output_point); + } + + if let Some((out_x, out_y)) = output_point.xy() { + Ok((FieldElement::from_repr(*out_x), FieldElement::from_repr(*out_y))) + } else { + Ok((FieldElement::zero(), FieldElement::zero())) + } +} + +pub fn embedded_curve_add( + input1_x: FieldElement, + input1_y: FieldElement, + input2_x: FieldElement, + input2_y: FieldElement, +) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { + let point1 = create_point(input1_x, input1_y) + .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::EmbeddedCurveAdd, e))?; + let point2 = create_point(input2_x, input2_y) + .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::EmbeddedCurveAdd, e))?; + let res = grumpkin::SWAffine::from(point1 + point2); + if let Some((res_x, res_y)) = res.xy() { + Ok((FieldElement::from_repr(*res_x), FieldElement::from_repr(*res_y))) + } else { + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::EmbeddedCurveAdd, + "Point is not on curve".to_string(), + )) + } +} + +fn create_point(x: FieldElement, y: FieldElement) -> Result { + let point = grumpkin::SWAffine::new_unchecked(x.into_repr(), y.into_repr()); + if !point.is_on_curve() { + return Err(format!("Point ({}, {}) is not on curve", x.to_hex(), y.to_hex())); + }; + if !point.is_in_correct_subgroup_assuming_on_curve() { + return Err(format!("Point ({}, {}) is not in correct subgroup", x.to_hex(), y.to_hex())); + }; + Ok(point) +} + +#[cfg(test)] +mod tests { + use ark_ff::BigInteger; + + use super::*; + + fn get_generator() -> [FieldElement; 2] { + let generator = grumpkin::SWAffine::generator(); + let generator_x = FieldElement::from_repr(*generator.x().unwrap()); + let generator_y = FieldElement::from_repr(*generator.y().unwrap()); + [generator_x, generator_y] + } + + #[test] + fn smoke_test() -> Result<(), BlackBoxResolutionError> { + // We check that multiplying 1 by generator results in the generator + let generator = get_generator(); + + let res = multi_scalar_mul(&generator, &[FieldElement::one(), FieldElement::zero()])?; + + assert_eq!(generator[0], res.0); + assert_eq!(generator[1], res.1); + Ok(()) + } + + #[test] + fn low_high_smoke_test() -> Result<(), BlackBoxResolutionError> { + let points = get_generator(); + let scalars = [FieldElement::one(), FieldElement::from(2u128)]; + + let res = multi_scalar_mul(&points, &scalars)?; + let x = "0702ab9c7038eeecc179b4f209991bcb68c7cb05bf4c532d804ccac36199c9a9"; + let y = "23f10e9e43a3ae8d75d24154e796aae12ae7af546716e8f81a2564f1b5814130"; + + assert_eq!(x, res.0.to_hex()); + assert_eq!(y, res.1.to_hex()); + Ok(()) + } + + #[test] + fn rejects_invalid_scalar_limbs() { + let points = get_generator(); + + let max_limb = FieldElement::from(u128::MAX); + let invalid_limb = max_limb + FieldElement::one(); + + let expected_error = Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::MultiScalarMul, + "Limb 0000000000000000000000000000000100000000000000000000000000000000 is not less than 2^128".into(), + )); + + let res = multi_scalar_mul(&points, &[FieldElement::one(), invalid_limb]); + assert_eq!(res, expected_error); + + let res = multi_scalar_mul(&points, &[invalid_limb, FieldElement::one()]); + assert_eq!(res, expected_error); + } + + #[test] + fn rejects_grumpkin_modulus() { + let x = grumpkin::FrConfig::MODULUS.to_bytes_be(); + + let low = FieldElement::from_be_bytes_reduce(&x[16..32]); + let high = FieldElement::from_be_bytes_reduce(&x[0..16]); + + let res = multi_scalar_mul(&get_generator(), &[low, high]); + + assert_eq!( + res, + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::MultiScalarMul, + "30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 is not a valid grumpkin scalar".into(), + )) + ); + } + + #[test] + fn rejects_invalid_point() { + let invalid_point_x = FieldElement::one(); + let invalid_point_y = FieldElement::one(); + let valid_scalar_low = FieldElement::zero(); + let valid_scalar_high = FieldElement::zero(); + + let res = multi_scalar_mul( + &[invalid_point_x, invalid_point_y], + &[valid_scalar_low, valid_scalar_high], + ); + + assert_eq!( + res, + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::MultiScalarMul, + "Point (0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000001) is not on curve".into(), + )) + ); + } + + #[test] + fn throws_on_args_length_mismatch() { + let points = get_generator(); + let scalars = [FieldElement::from(2u128)]; + + let res = multi_scalar_mul(&points, &scalars); + + assert_eq!( + res, + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::MultiScalarMul, + "Points and scalars must have the same length".into(), + )) + ); + } + + #[test] + fn rejects_addition_of_points_not_in_curve() { + let x = FieldElement::from(1u128); + let y = FieldElement::from(2u128); + + let res = embedded_curve_add(x, y, x, y); + + assert_eq!( + res, + Err(BlackBoxResolutionError::Failed( + BlackBoxFunc::EmbeddedCurveAdd, + "Point (0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000002) is not on curve".into(), + )) + ); + } + + #[test] + fn output_of_msm_matches_add() -> Result<(), BlackBoxResolutionError> { + let points = get_generator(); + let scalars = [FieldElement::from(2u128), FieldElement::zero()]; + + let msm_res = multi_scalar_mul(&points, &scalars)?; + let add_res = embedded_curve_add(points[0], points[1], points[0], points[1])?; + + assert_eq!(msm_res.0, add_res.0); + assert_eq!(msm_res.1, add_res.1); + Ok(()) + } +} diff --git a/acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs b/acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs deleted file mode 100644 index cd91c290f49..00000000000 --- a/acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs +++ /dev/null @@ -1,165 +0,0 @@ -use ark_ec::AffineRepr; -use ark_ff::MontConfig; -use num_bigint::BigUint; - -use acir::{BlackBoxFunc, FieldElement}; - -use crate::BlackBoxResolutionError; - -pub fn fixed_base_scalar_mul( - low: &FieldElement, - high: &FieldElement, -) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - let low: u128 = low.try_into_u128().ok_or_else(|| { - BlackBoxResolutionError::Failed( - BlackBoxFunc::FixedBaseScalarMul, - format!("Limb {} is not less than 2^128", low.to_hex()), - ) - })?; - - let high: u128 = high.try_into_u128().ok_or_else(|| { - BlackBoxResolutionError::Failed( - BlackBoxFunc::FixedBaseScalarMul, - format!("Limb {} is not less than 2^128", high.to_hex()), - ) - })?; - - let mut bytes = high.to_be_bytes().to_vec(); - bytes.extend_from_slice(&low.to_be_bytes()); - - // Check if this is smaller than the grumpkin modulus - let grumpkin_integer = BigUint::from_bytes_be(&bytes); - - if grumpkin_integer >= grumpkin::FrConfig::MODULUS.into() { - return Err(BlackBoxResolutionError::Failed( - BlackBoxFunc::FixedBaseScalarMul, - format!("{} is not a valid grumpkin scalar", grumpkin_integer.to_str_radix(16)), - )); - } - - let result = grumpkin::SWAffine::from( - grumpkin::SWAffine::generator().mul_bigint(grumpkin_integer.to_u64_digits()), - ); - if let Some((res_x, res_y)) = result.xy() { - Ok((FieldElement::from_repr(*res_x), FieldElement::from_repr(*res_y))) - } else { - Ok((FieldElement::zero(), FieldElement::zero())) - } -} - -fn create_point(x: FieldElement, y: FieldElement) -> Result { - let point = grumpkin::SWAffine::new_unchecked(x.into_repr(), y.into_repr()); - if !point.is_on_curve() { - return Err(format!("Point ({}, {}) is not on curve", x.to_hex(), y.to_hex())); - }; - if !point.is_in_correct_subgroup_assuming_on_curve() { - return Err(format!("Point ({}, {}) is not in correct subgroup", x.to_hex(), y.to_hex())); - }; - Ok(point) -} - -pub fn embedded_curve_add( - input1_x: FieldElement, - input1_y: FieldElement, - input2_x: FieldElement, - input2_y: FieldElement, -) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - let point1 = create_point(input1_x, input1_y) - .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::EmbeddedCurveAdd, e))?; - let point2 = create_point(input2_x, input2_y) - .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::EmbeddedCurveAdd, e))?; - let res = grumpkin::SWAffine::from(point1 + point2); - if let Some((res_x, res_y)) = res.xy() { - Ok((FieldElement::from_repr(*res_x), FieldElement::from_repr(*res_y))) - } else { - Err(BlackBoxResolutionError::Failed( - BlackBoxFunc::EmbeddedCurveAdd, - "Point is not on curve".to_string(), - )) - } -} - -#[cfg(test)] -mod grumpkin_fixed_base_scalar_mul { - use ark_ff::BigInteger; - - use super::*; - - #[test] - fn smoke_test() -> Result<(), BlackBoxResolutionError> { - let input = FieldElement::one(); - - let res = fixed_base_scalar_mul(&input, &FieldElement::zero())?; - let x = "0000000000000000000000000000000000000000000000000000000000000001"; - let y = "0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c"; - - assert_eq!(x, res.0.to_hex()); - assert_eq!(y, res.1.to_hex()); - Ok(()) - } - - #[test] - fn low_high_smoke_test() -> Result<(), BlackBoxResolutionError> { - let low = FieldElement::one(); - let high = FieldElement::from(2u128); - - let res = fixed_base_scalar_mul(&low, &high)?; - let x = "0702ab9c7038eeecc179b4f209991bcb68c7cb05bf4c532d804ccac36199c9a9"; - let y = "23f10e9e43a3ae8d75d24154e796aae12ae7af546716e8f81a2564f1b5814130"; - - assert_eq!(x, res.0.to_hex()); - assert_eq!(y, res.1.to_hex()); - Ok(()) - } - - #[test] - fn rejects_invalid_limbs() { - let max_limb = FieldElement::from(u128::MAX); - let invalid_limb = max_limb + FieldElement::one(); - - let expected_error = Err(BlackBoxResolutionError::Failed( - BlackBoxFunc::FixedBaseScalarMul, - "Limb 0000000000000000000000000000000100000000000000000000000000000000 is not less than 2^128".into(), - )); - - let res = fixed_base_scalar_mul(&invalid_limb, &FieldElement::zero()); - assert_eq!(res, expected_error); - - let res = fixed_base_scalar_mul(&FieldElement::zero(), &invalid_limb); - assert_eq!(res, expected_error); - } - - #[test] - fn rejects_grumpkin_modulus() { - let x = grumpkin::FrConfig::MODULUS.to_bytes_be(); - - let high = FieldElement::from_be_bytes_reduce(&x[0..16]); - let low = FieldElement::from_be_bytes_reduce(&x[16..32]); - - let res = fixed_base_scalar_mul(&low, &high); - - assert_eq!( - res, - Err(BlackBoxResolutionError::Failed( - BlackBoxFunc::FixedBaseScalarMul, - "30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 is not a valid grumpkin scalar".into(), - )) - ); - } - - #[test] - fn rejects_addition_of_points_not_in_curve() { - let x = FieldElement::from(1u128); - let y = FieldElement::from(2u128); - - let res = embedded_curve_add(x, y, x, y); - - assert_eq!( - res, - Err(BlackBoxResolutionError::Failed( - BlackBoxFunc::EmbeddedCurveAdd, - "Point (0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000002) is not on curve".into(), - )) - ); - } -} diff --git a/acvm-repo/bn254_blackbox_solver/src/lib.rs b/acvm-repo/bn254_blackbox_solver/src/lib.rs index 25b10252a78..4cb51b59755 100644 --- a/acvm-repo/bn254_blackbox_solver/src/lib.rs +++ b/acvm-repo/bn254_blackbox_solver/src/lib.rs @@ -5,11 +5,11 @@ use acir::{BlackBoxFunc, FieldElement}; use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; -mod fixed_base_scalar_mul; +mod embedded_curve_ops; mod poseidon2; mod wasm; -pub use fixed_base_scalar_mul::{embedded_curve_add, fixed_base_scalar_mul}; +pub use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul}; pub use poseidon2::poseidon2_permutation; use wasm::Barretenberg; @@ -89,12 +89,12 @@ impl BlackBoxFunctionSolver for Bn254BlackBoxSolver { }) } - fn fixed_base_scalar_mul( + fn multi_scalar_mul( &self, - low: &FieldElement, - high: &FieldElement, + points: &[FieldElement], + scalars: &[FieldElement], ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - fixed_base_scalar_mul(low, high) + multi_scalar_mul(points, scalars) } fn ec_add( diff --git a/acvm-repo/brillig/Cargo.toml b/acvm-repo/brillig/Cargo.toml index 463f6286d6b..081abe022ae 100644 --- a/acvm-repo/brillig/Cargo.toml +++ b/acvm-repo/brillig/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig" description = "Brillig is the bytecode ACIR uses for non-determinism." # x-release-please-start-version -version = "0.43.0" +version = "0.45.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index 29861d0fd84..15abc19ed90 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -5,6 +5,13 @@ use serde::{Deserialize, Serialize}; /// They are implemented as native functions in the VM. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum BlackBoxOp { + /// Encrypts a message using AES128. + AES128Encrypt { + inputs: HeapVector, + iv: HeapArray, + key: HeapArray, + outputs: HeapVector, + }, /// Calculates the SHA256 hash of the inputs. Sha256 { message: HeapVector, @@ -66,11 +73,11 @@ pub enum BlackBoxOp { domain_separator: MemoryAddress, output: MemoryAddress, }, - /// Performs scalar multiplication over the embedded curve. - FixedBaseScalarMul { - low: MemoryAddress, - high: MemoryAddress, - result: HeapArray, + /// Performs multi scalar multiplication over the embedded curve. + MultiScalarMul { + points: HeapVector, + scalars: HeapVector, + outputs: HeapArray, }, /// Performs addition over the embedded curve. EmbeddedCurveAdd { diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 468fd88db45..a060aa83d41 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -52,6 +52,12 @@ pub struct HeapArray { pub size: usize, } +impl Default for HeapArray { + fn default() -> Self { + Self { pointer: MemoryAddress(0), size: 0 } + } +} + /// A memory-sized vector passed starting from a Brillig memory location and with a memory-held size #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub struct HeapVector { @@ -179,8 +185,7 @@ pub enum BrilligOpcode { BlackBox(BlackBoxOp), /// Used to denote execution failure, returning data after the offset Trap { - revert_data_offset: usize, - revert_data_size: usize, + revert_data: HeapArray, }, /// Stop execution, returning data after the offset Stop { diff --git a/acvm-repo/brillig_vm/Cargo.toml b/acvm-repo/brillig_vm/Cargo.toml index 67e16c21d8b..57cf3be974a 100644 --- a/acvm-repo/brillig_vm/Cargo.toml +++ b/acvm-repo/brillig_vm/Cargo.toml @@ -2,7 +2,7 @@ name = "brillig_vm" description = "The virtual machine that processes Brillig bytecode, used to introduce non-determinism to the ACVM" # x-release-please-start-version -version = "0.43.0" +version = "0.45.0" # x-release-please-end authors.workspace = true edition.workspace = true diff --git a/acvm-repo/brillig_vm/src/arithmetic.rs b/acvm-repo/brillig_vm/src/arithmetic.rs index 2107d10c093..c17c019d11c 100644 --- a/acvm-repo/brillig_vm/src/arithmetic.rs +++ b/acvm-repo/brillig_vm/src/arithmetic.rs @@ -71,7 +71,9 @@ pub(crate) fn evaluate_binary_int_op( } } })?; - let rhs = rhs.expect_integer_with_bit_size(bit_size).map_err(|err| match err { + let rhs_bit_size = + if op == &BinaryIntOp::Shl || op == &BinaryIntOp::Shr { 8 } else { bit_size }; + let rhs = rhs.expect_integer_with_bit_size(rhs_bit_size).map_err(|err| match err { MemoryTypeError::MismatchedBitSize { value_bit_size, expected_bit_size } => { BrilligArithmeticError::MismatchedRhsBitSize { rhs_bit_size: value_bit_size, diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index 19407da52db..c999b5bf330 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -2,8 +2,8 @@ use acir::brillig::{BlackBoxOp, HeapArray, HeapVector}; use acir::{BlackBoxFunc, FieldElement}; use acvm_blackbox_solver::BigIntSolver; use acvm_blackbox_solver::{ - blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, keccakf1600, - sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError, + aes128_encrypt, blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, + keccakf1600, sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError, }; use crate::memory::MemoryValue; @@ -38,6 +38,25 @@ pub(crate) fn evaluate_black_box( bigint_solver: &mut BigIntSolver, ) -> Result<(), BlackBoxResolutionError> { match op { + BlackBoxOp::AES128Encrypt { inputs, iv, key, outputs } => { + let bb_func = black_box_function_from_op(op); + + let inputs = to_u8_vec(read_heap_vector(memory, inputs)); + + let iv: [u8; 16] = to_u8_vec(read_heap_array(memory, iv)).try_into().map_err(|_| { + BlackBoxResolutionError::Failed(bb_func, "Invalid iv length".to_string()) + })?; + let key: [u8; 16] = + to_u8_vec(read_heap_array(memory, key)).try_into().map_err(|_| { + BlackBoxResolutionError::Failed(bb_func, "Invalid ley length".to_string()) + })?; + let ciphertext = aes128_encrypt(&inputs, iv, key)?; + + memory.write(outputs.size, ciphertext.len().into()); + memory.write_slice(memory.read_ref(outputs.pointer), &to_value_vec(&ciphertext)); + + Ok(()) + } BlackBoxOp::Sha256 { message, output } => { let message = to_u8_vec(read_heap_vector(memory, message)); let bytes = sha256(message.as_slice())?; @@ -136,10 +155,13 @@ pub(crate) fn evaluate_black_box( memory.write(*result, verified.into()); Ok(()) } - BlackBoxOp::FixedBaseScalarMul { low, high, result } => { - let low = memory.read(*low).try_into().unwrap(); - let high = memory.read(*high).try_into().unwrap(); - let (x, y) = solver.fixed_base_scalar_mul(&low, &high)?; + BlackBoxOp::MultiScalarMul { points, scalars, outputs: result } => { + let points: Vec = + read_heap_vector(memory, points).iter().map(|x| x.try_into().unwrap()).collect(); + let scalars: Vec = + read_heap_vector(memory, scalars).iter().map(|x| x.try_into().unwrap()).collect(); + + let (x, y) = solver.multi_scalar_mul(&points, &scalars)?; memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); Ok(()) } @@ -278,6 +300,7 @@ pub(crate) fn evaluate_black_box( fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { match op { + BlackBoxOp::AES128Encrypt { .. } => BlackBoxFunc::AES128Encrypt, BlackBoxOp::Sha256 { .. } => BlackBoxFunc::SHA256, BlackBoxOp::Blake2s { .. } => BlackBoxFunc::Blake2s, BlackBoxOp::Blake3 { .. } => BlackBoxFunc::Blake3, @@ -288,7 +311,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { BlackBoxOp::SchnorrVerify { .. } => BlackBoxFunc::SchnorrVerify, BlackBoxOp::PedersenCommitment { .. } => BlackBoxFunc::PedersenCommitment, BlackBoxOp::PedersenHash { .. } => BlackBoxFunc::PedersenHash, - BlackBoxOp::FixedBaseScalarMul { .. } => BlackBoxFunc::FixedBaseScalarMul, + BlackBoxOp::MultiScalarMul { .. } => BlackBoxFunc::MultiScalarMul, BlackBoxOp::EmbeddedCurveAdd { .. } => BlackBoxFunc::EmbeddedCurveAdd, BlackBoxOp::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd, BlackBoxOp::BigIntSub { .. } => BlackBoxFunc::BigIntSub, diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 75299670f94..7901c313596 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -305,8 +305,12 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } self.increment_program_counter() } - Opcode::Trap { revert_data_offset, revert_data_size } => { - self.trap(*revert_data_offset, *revert_data_size) + Opcode::Trap { revert_data } => { + if revert_data.size > 0 { + self.trap(self.memory.read_ref(revert_data.pointer).0, revert_data.size) + } else { + self.trap(0, 0) + } } Opcode::Stop { return_data_offset, return_data_size } => { self.finish(*return_data_offset, *return_data_size) @@ -715,7 +719,7 @@ mod tests { let jump_opcode = Opcode::Jump { location: 3 }; - let trap_opcode = Opcode::Trap { revert_data_offset: 0, revert_data_size: 0 }; + let trap_opcode = Opcode::Trap { revert_data: HeapArray::default() }; let not_equal_cmp_opcode = Opcode::BinaryFieldOp { op: BinaryFieldOp::Equals, diff --git a/aztec_macros/src/transforms/contract_interface.rs b/aztec_macros/src/transforms/contract_interface.rs index 5f68ce98c8a..1afe0a30068 100644 --- a/aztec_macros/src/transforms/contract_interface.rs +++ b/aztec_macros/src/transforms/contract_interface.rs @@ -126,6 +126,7 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { target_contract: self.target_contract, selector: {}, args: args_acc, + gas_opts: dep::aztec::context::gas::GasOpts::default(), }}", args, is_void, fn_selector, ); diff --git a/aztec_macros/src/transforms/functions.rs b/aztec_macros/src/transforms/functions.rs index 24cad05b866..90563c6085c 100644 --- a/aztec_macros/src/transforms/functions.rs +++ b/aztec_macros/src/transforms/functions.rs @@ -1,8 +1,8 @@ use convert_case::{Case, Casing}; use noirc_errors::Span; -use noirc_frontend::ast; +use noirc_frontend::ast::{self, FunctionKind}; use noirc_frontend::ast::{ - BlockExpression, ConstrainKind, ConstrainStatement, Distinctness, Expression, ExpressionKind, + BlockExpression, ConstrainKind, ConstrainStatement, Expression, ExpressionKind, ForLoopStatement, ForRange, FunctionReturnType, Ident, Literal, NoirFunction, NoirStruct, Param, PathKind, Pattern, Signedness, Statement, StatementKind, UnresolvedType, UnresolvedTypeData, Visibility, @@ -38,6 +38,7 @@ pub fn transform_function( let inputs_name = format!("{}ContextInputs", ty); let return_type_name = format!("{}CircuitPublicInputs", ty); let is_avm = ty == "Avm"; + let is_private = ty == "Private"; // Add check that msg sender equals this address and flag function as internal if is_internal { @@ -102,14 +103,16 @@ pub fn transform_function( let return_type = create_return_type(&return_type_name); func.def.return_type = return_type; func.def.return_visibility = Visibility::Public; + } else { + func.def.return_visibility = Visibility::Public; } - // Distinct return types are only required for private functions // Public functions should have unconstrained auto-inferred - match ty { - "Private" => func.def.return_distinctness = Distinctness::Distinct, - "Public" | "Avm" => func.def.is_unconstrained = true, - _ => (), + func.def.is_unconstrained = matches!(ty, "Public" | "Avm"); + + // Private functions need to be recursive + if is_private { + func.kind = FunctionKind::Recursive; } Ok(()) diff --git a/aztec_macros/src/utils/hir_utils.rs b/aztec_macros/src/utils/hir_utils.rs index 3801ff1cc75..99b02acd606 100644 --- a/aztec_macros/src/utils/hir_utils.rs +++ b/aztec_macros/src/utils/hir_utils.rs @@ -228,6 +228,7 @@ pub fn inject_global( module_id, file_id, global.attributes.clone(), + false, ); // Add the statement to the scope so its path can be looked up later diff --git a/compiler/utils/arena/Cargo.toml b/compiler/noirc_arena/Cargo.toml similarity index 86% rename from compiler/utils/arena/Cargo.toml rename to compiler/noirc_arena/Cargo.toml index f6bd764ee62..b94f997b7b9 100644 --- a/compiler/utils/arena/Cargo.toml +++ b/compiler/noirc_arena/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "arena" +name = "noirc_arena" version.workspace = true authors.workspace = true edition.workspace = true diff --git a/compiler/utils/arena/src/lib.rs b/compiler/noirc_arena/src/lib.rs similarity index 94% rename from compiler/utils/arena/src/lib.rs rename to compiler/noirc_arena/src/lib.rs index 2d117304e16..9a25299d6c8 100644 --- a/compiler/utils/arena/src/lib.rs +++ b/compiler/noirc_arena/src/lib.rs @@ -3,6 +3,8 @@ #![warn(unreachable_pub)] #![warn(clippy::semicolon_if_nothing_returned)] +use std::fmt; + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct Index(usize); @@ -25,6 +27,12 @@ impl Index { } } +impl fmt::Display for Index { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + #[derive(Clone, Debug)] pub struct Arena { pub vec: Vec, diff --git a/compiler/noirc_driver/src/abi_gen.rs b/compiler/noirc_driver/src/abi_gen.rs index 51fe4986845..609c88b92c2 100644 --- a/compiler/noirc_driver/src/abi_gen.rs +++ b/compiler/noirc_driver/src/abi_gen.rs @@ -1,12 +1,13 @@ use std::collections::BTreeMap; +use acvm::acir::circuit::ErrorSelector; use acvm::acir::native_types::Witness; use iter_extended::{btree_map, vecmap}; -use noirc_abi::{Abi, AbiParameter, AbiReturnType, AbiType, AbiValue}; +use noirc_abi::{Abi, AbiErrorType, AbiParameter, AbiReturnType, AbiType, AbiValue}; use noirc_frontend::ast::Visibility; use noirc_frontend::{ hir::Context, - hir_def::{expr::HirArrayLiteral, function::Param, stmt::HirPattern}, + hir_def::{expr::HirArrayLiteral, function::Param, stmt::HirPattern, types::Type}, macros_api::{HirExpression, HirLiteral}, node_interner::{FuncId, NodeInterner}, }; @@ -20,12 +21,17 @@ pub(super) fn gen_abi( input_witnesses: Vec, return_witnesses: Vec, return_visibility: Visibility, + error_types: BTreeMap, ) -> Abi { let (parameters, return_type) = compute_function_abi(context, func_id); let param_witnesses = param_witnesses_from_abi_param(¶meters, input_witnesses); let return_type = return_type .map(|typ| AbiReturnType { abi_type: typ, visibility: return_visibility.into() }); - Abi { parameters, return_type, param_witnesses, return_witnesses } + let error_types = error_types + .into_iter() + .map(|(selector, typ)| (selector, AbiErrorType::from_type(context, &typ))) + .collect(); + Abi { parameters, return_type, param_witnesses, return_witnesses, error_types } } pub(super) fn compute_function_abi( diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 8a554879e9f..ef874d45f88 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -252,7 +252,7 @@ pub fn check_crate( let mut errors = vec![]; let diagnostics = CrateDefMap::collect_defs(crate_id, context, macros); errors.extend(diagnostics.into_iter().map(|(error, file_id)| { - let diagnostic: CustomDiagnostic = error.into(); + let diagnostic = CustomDiagnostic::from(&error); diagnostic.in_file(file_id) })); @@ -529,6 +529,7 @@ pub fn compile_no_check( main_input_witnesses, main_return_witnesses, names, + error_types, } = create_program( program, options.show_ssa, @@ -543,6 +544,7 @@ pub fn compile_no_check( main_input_witnesses, main_return_witnesses, visibility, + error_types, ); let file_map = filter_relevant_files(&debug, &context.file_manager); diff --git a/compiler/noirc_errors/Cargo.toml b/compiler/noirc_errors/Cargo.toml index c9cb7e2709f..41b1cd0ff58 100644 --- a/compiler/noirc_errors/Cargo.toml +++ b/compiler/noirc_errors/Cargo.toml @@ -20,4 +20,4 @@ serde_with = "3.2.0" tracing.workspace = true flate2.workspace = true serde_json.workspace = true -base64.workspace = true \ No newline at end of file +base64.workspace = true diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index ee047903743..d982d864d06 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -188,20 +188,20 @@ pub(crate) fn convert_black_box_call( unreachable!("ICE: Schnorr verify expects two registers for the public key, an array for signature, an array for the message hash and one result register") } } - BlackBoxFunc::FixedBaseScalarMul => { - if let ( - [BrilligVariable::SingleAddr(low), BrilligVariable::SingleAddr(high)], - [BrilligVariable::BrilligArray(result_array)], - ) = (function_arguments, function_results) + BlackBoxFunc::MultiScalarMul => { + if let ([points, scalars], [BrilligVariable::BrilligArray(outputs)]) = + (function_arguments, function_results) { - brillig_context.black_box_op_instruction(BlackBoxOp::FixedBaseScalarMul { - low: low.address, - high: high.address, - result: result_array.to_heap_array(), + let points = convert_array_or_vector(brillig_context, points, bb_func); + let scalars = convert_array_or_vector(brillig_context, scalars, bb_func); + brillig_context.black_box_op_instruction(BlackBoxOp::MultiScalarMul { + points: points.to_heap_vector(), + scalars: scalars.to_heap_vector(), + outputs: outputs.to_heap_array(), }); } else { unreachable!( - "ICE: FixedBaseScalarMul expects one register argument and one array result" + "ICE: MultiScalarMul expects two register arguments and one array result" ) } } @@ -401,6 +401,28 @@ pub(crate) fn convert_black_box_call( unreachable!("ICE: Sha256Compression expects two array argument, one array result") } } + BlackBoxFunc::AES128Encrypt => { + if let ( + [inputs, BrilligVariable::BrilligArray(iv), BrilligVariable::BrilligArray(key)], + [BrilligVariable::SingleAddr(out_len), outputs], + ) = (function_arguments, function_results) + { + let inputs = convert_array_or_vector(brillig_context, inputs, bb_func); + let outputs = convert_array_or_vector(brillig_context, outputs, bb_func); + let output_vec = outputs.to_heap_vector(); + brillig_context.black_box_op_instruction(BlackBoxOp::AES128Encrypt { + inputs: inputs.to_heap_vector(), + iv: iv.to_heap_array(), + key: key.to_heap_array(), + outputs: output_vec, + }); + brillig_context.mov_instruction(out_len.address, output_vec.size); + // Returns slice, so we need to allocate memory for it after the fact + brillig_context.increase_free_memory_pointer_instruction(output_vec.size); + } else { + unreachable!("ICE: AES128Encrypt expects three array arguments, one array result") + } + } } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 22407fc5695..873ebe51e6f 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -5,7 +5,7 @@ use crate::brillig::brillig_ir::{ BrilligBinaryOp, BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; use crate::ssa::ir::dfg::CallStack; -use crate::ssa::ir::instruction::{ConstrainError, UserDefinedConstrainError}; +use crate::ssa::ir::instruction::ConstrainError; use crate::ssa::ir::{ basic_block::{BasicBlock, BasicBlockId}, dfg::DataFlowGraph, @@ -248,34 +248,6 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_binary(binary, dfg, result_var); } Instruction::Constrain(lhs, rhs, assert_message) => { - let (has_revert_data, static_assert_message) = if let Some(error) = assert_message { - match error.as_ref() { - ConstrainError::Intrinsic(string) => (false, Some(string.clone())), - ConstrainError::UserDefined(UserDefinedConstrainError::Static(string)) => { - (true, Some(string.clone())) - } - ConstrainError::UserDefined(UserDefinedConstrainError::Dynamic( - call_instruction, - )) => { - let Instruction::Call { func, arguments } = call_instruction else { - unreachable!("expected a call instruction") - }; - - let Value::Function(func_id) = &dfg[*func] else { - unreachable!("expected a function value") - }; - - self.convert_ssa_function_call(*func_id, arguments, dfg, &[]); - - // Dynamic assert messages are handled in the generated function call. - // We then don't need to attach one to the constrain instruction. - (false, None) - } - } - } else { - (false, None) - }; - let condition = SingleAddrVariable { address: self.brillig_context.allocate_register(), bit_size: 1, @@ -286,11 +258,27 @@ impl<'block> BrilligBlock<'block> { dfg, condition, ); - if has_revert_data { - self.brillig_context - .codegen_constrain_with_revert_data(condition, static_assert_message); - } else { - self.brillig_context.codegen_constrain(condition, static_assert_message); + match assert_message { + Some(ConstrainError::UserDefined(selector, values)) => { + let payload_values = + vecmap(values, |value| self.convert_ssa_value(*value, dfg)); + let payload_as_params = vecmap(values, |value| { + let value_type = dfg.type_of_value(*value); + FunctionContext::ssa_type_to_parameter(&value_type) + }); + self.brillig_context.codegen_constrain_with_revert_data( + condition, + payload_values, + payload_as_params, + selector.as_u64(), + ); + } + Some(ConstrainError::Intrinsic(message)) => { + self.brillig_context.codegen_constrain(condition, Some(message.clone())); + } + None => { + self.brillig_context.codegen_constrain(condition, None); + } } self.brillig_context.deallocate_single_addr(condition); } @@ -631,7 +619,7 @@ impl<'block> BrilligBlock<'block> { destination_variable, ); } - Instruction::ArraySet { array, index, value, .. } => { + Instruction::ArraySet { array, index, value, mutable: _ } => { let source_variable = self.convert_ssa_value(*array, dfg); let index_register = self.convert_ssa_single_addr_value(*index, dfg); let value_variable = self.convert_ssa_value(*value, dfg); @@ -712,6 +700,9 @@ impl<'block> BrilligBlock<'block> { Instruction::EnableSideEffects { .. } => { todo!("enable_side_effects not supported by brillig") } + Instruction::IfElse { .. } => { + unreachable!("IfElse instructions should not be possible in brillig") + } }; let dead_variables = self @@ -1279,8 +1270,11 @@ impl<'block> BrilligBlock<'block> { dfg: &DataFlowGraph, result_variable: SingleAddrVariable, ) { - let binary_type = - type_of_binary_operation(dfg[binary.lhs].get_type(), dfg[binary.rhs].get_type()); + let binary_type = type_of_binary_operation( + dfg[binary.lhs].get_type(), + dfg[binary.rhs].get_type(), + binary.operator, + ); let left = self.convert_ssa_single_addr_value(binary.lhs, dfg); let right = self.convert_ssa_single_addr_value(binary.rhs, dfg); @@ -1766,7 +1760,7 @@ impl<'block> BrilligBlock<'block> { } /// Returns the type of the operation considering the types of the operands -pub(crate) fn type_of_binary_operation(lhs_type: &Type, rhs_type: &Type) -> Type { +pub(crate) fn type_of_binary_operation(lhs_type: &Type, rhs_type: &Type, op: BinaryOp) -> Type { match (lhs_type, rhs_type) { (_, Type::Function) | (Type::Function, _) => { unreachable!("Functions are invalid in binary operations") @@ -1782,12 +1776,15 @@ pub(crate) fn type_of_binary_operation(lhs_type: &Type, rhs_type: &Type) -> Type } // If both sides are numeric type, then we expect their types to be // the same. - (Type::Numeric(lhs_type), Type::Numeric(rhs_type)) => { + (Type::Numeric(lhs_type), Type::Numeric(rhs_type)) + if op != BinaryOp::Shl && op != BinaryOp::Shr => + { assert_eq!( lhs_type, rhs_type, "lhs and rhs types in a binary operation are always the same but got {lhs_type} and {rhs_type}" ); Type::Numeric(*lhs_type) } + _ => lhs_type.clone(), } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 7e37e1da434..fadcdb22c15 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -130,7 +130,7 @@ pub(crate) mod tests { use std::vec; use acvm::acir::brillig::{ - ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, ValueOrArray, + ForeignCallParam, ForeignCallResult, HeapArray, HeapVector, MemoryAddress, ValueOrArray, }; use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{VMStatus, VM}; @@ -167,10 +167,10 @@ pub(crate) mod tests { ) -> Result { Ok(6_u128.into()) } - fn fixed_base_scalar_mul( + fn multi_scalar_mul( &self, - _low: &FieldElement, - _high: &FieldElement, + _points: &[FieldElement], + _scalars: &[FieldElement], ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { Ok((4_u128.into(), 5_u128.into())) } @@ -270,7 +270,7 @@ pub(crate) mod tests { // uses unresolved jumps which requires a block to be constructed in SSA and // we don't need this for Brillig IR tests context.push_opcode(BrilligOpcode::JumpIf { condition: r_equality, location: 8 }); - context.push_opcode(BrilligOpcode::Trap { revert_data_offset: 0, revert_data_size: 0 }); + context.push_opcode(BrilligOpcode::Trap { revert_data: HeapArray::default() }); context.stop_instruction(); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs index 8a4f469f5c9..dee6c6076f4 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs @@ -29,7 +29,9 @@ pub(crate) struct GeneratedBrillig { /// It includes the bytecode of the function and all the metadata that allows linking with other functions. pub(crate) struct BrilligArtifact { pub(crate) byte_code: Vec, - /// A map of bytecode positions to assertion messages + /// A map of bytecode positions to assertion messages. + /// Some error messages (compiler intrinsics) are not emitted via revert data, + /// instead, they are handled externally so they don't add size to user programs. pub(crate) assert_messages: BTreeMap, /// The set of jumps that need to have their locations /// resolved. diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs index f8f39f03df4..d9109646338 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs @@ -1,7 +1,9 @@ -use acvm::acir::brillig::MemoryAddress; +use acvm::acir::brillig::{HeapArray, MemoryAddress}; use super::{ - brillig_variable::SingleAddrVariable, BrilligBinaryOp, BrilligContext, ReservedRegisters, + artifact::BrilligParameter, + brillig_variable::{BrilligVariable, SingleAddrVariable}, + BrilligBinaryOp, BrilligContext, ReservedRegisters, }; impl BrilligContext { @@ -144,25 +146,62 @@ impl BrilligContext { pub(crate) fn codegen_constrain_with_revert_data( &mut self, condition: SingleAddrVariable, - assert_message: Option, + revert_data_items: Vec, + revert_data_types: Vec, + error_selector: u64, ) { assert!(condition.bit_size == 1); self.codegen_if_not(condition.address, |ctx| { - let (revert_data_offset, revert_data_size) = - if let Some(assert_message) = assert_message { - let bytes = assert_message.as_bytes(); - for (i, byte) in bytes.iter().enumerate() { - ctx.const_instruction( - SingleAddrVariable::new(MemoryAddress(i), 8), - (*byte as usize).into(), + let revert_data = HeapArray { + pointer: ctx.allocate_register(), + // + 1 due to the revert data id being the first item returned + size: BrilligContext::flattened_tuple_size(&revert_data_types) + 1, + }; + ctx.codegen_allocate_fixed_length_array(revert_data.pointer, revert_data.size); + + let current_revert_data_pointer = ctx.allocate_register(); + ctx.mov_instruction(current_revert_data_pointer, revert_data.pointer); + let revert_data_id = + ctx.make_usize_constant_instruction((error_selector as u128).into()); + ctx.store_instruction(current_revert_data_pointer, revert_data_id.address); + + ctx.codegen_usize_op_in_place(current_revert_data_pointer, BrilligBinaryOp::Add, 1); + for (revert_variable, revert_param) in + revert_data_items.into_iter().zip(revert_data_types.into_iter()) + { + let flattened_size = BrilligContext::flattened_size(&revert_param); + match revert_param { + BrilligParameter::SingleAddr(_) => { + ctx.store_instruction( + current_revert_data_pointer, + revert_variable.extract_single_addr().address, + ); + } + BrilligParameter::Array(item_type, item_count) => { + let variable_pointer = revert_variable.extract_array().pointer; + + ctx.flatten_array( + &item_type, + item_count, + current_revert_data_pointer, + variable_pointer, ); } - (0, bytes.len()) - } else { - (0, 0) - }; - ctx.trap_instruction(revert_data_offset, revert_data_size); + BrilligParameter::Slice(_, _) => { + unimplemented!("Slices are not supported as revert data") + } + } + ctx.codegen_usize_op_in_place( + current_revert_data_pointer, + BrilligBinaryOp::Add, + flattened_size, + ); + } + ctx.trap_instruction(revert_data); + ctx.deallocate_register(revert_data.pointer); + ctx.deallocate_register(current_revert_data_pointer); + ctx.deallocate_single_addr(revert_data_id); }); } @@ -176,7 +215,7 @@ impl BrilligContext { assert!(condition.bit_size == 1); self.codegen_if_not(condition.address, |ctx| { - ctx.trap_instruction(0, 0); + ctx.trap_instruction(HeapArray::default()); if let Some(assert_message) = assert_message { ctx.obj.add_assert_message_to_last_opcode(assert_message); } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 41a6d1873e4..667ccf6ddbe 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -114,13 +114,8 @@ impl DebugShow { } /// Emits a `trap` instruction. - pub(crate) fn trap_instruction(&self, revert_data_offset: usize, revert_data_size: usize) { - debug_println!( - self.enable_debug_trace, - " TRAP {}..{}", - revert_data_offset, - revert_data_offset + revert_data_size - ); + pub(crate) fn trap_instruction(&self, revert_data: HeapArray) { + debug_println!(self.enable_debug_trace, " TRAP {}", revert_data); } /// Emits a `mov` instruction. @@ -271,6 +266,16 @@ impl DebugShow { /// Debug function for black_box_op pub(crate) fn black_box_op_instruction(&self, op: &BlackBoxOp) { match op { + BlackBoxOp::AES128Encrypt { inputs, iv, key, outputs } => { + debug_println!( + self.enable_debug_trace, + " AES128 ENCRYPT {} {} {} -> {}", + inputs, + iv, + key, + outputs + ); + } BlackBoxOp::Sha256 { message, output } => { debug_println!(self.enable_debug_trace, " SHA256 {} -> {}", message, output); } @@ -320,13 +325,13 @@ impl DebugShow { result ); } - BlackBoxOp::FixedBaseScalarMul { low, high, result } => { + BlackBoxOp::MultiScalarMul { points, scalars, outputs } => { debug_println!( self.enable_debug_trace, - " FIXED_BASE_SCALAR_MUL {} {} -> {}", - low, - high, - result + " MULTI_SCALAR_MUL {} {} -> {}", + points, + scalars, + outputs ); } BlackBoxOp::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, result } => { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 88cf987325d..732bd3cbc59 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -164,7 +164,7 @@ impl BrilligContext { } /// Computes the size of a parameter if it was flattened - fn flattened_size(param: &BrilligParameter) -> usize { + pub(super) fn flattened_size(param: &BrilligParameter) -> usize { match param { BrilligParameter::SingleAddr(_) => 1, BrilligParameter::Array(item_types, item_count) @@ -176,7 +176,7 @@ impl BrilligContext { } /// Computes the size of a parameter if it was flattened - fn flattened_tuple_size(tuple: &[BrilligParameter]) -> usize { + pub(super) fn flattened_tuple_size(tuple: &[BrilligParameter]) -> usize { tuple.iter().map(BrilligContext::flattened_size).sum() } @@ -369,7 +369,7 @@ impl BrilligContext { } // Flattens an array by recursively copying nested arrays and regular items. - fn flatten_array( + pub(super) fn flatten_array( &mut self, item_type: &[BrilligParameter], item_count: usize, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index 901ccc58036..5d2430208e4 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -1,6 +1,6 @@ use acvm::{ acir::brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, MemoryAddress, + BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapArray, HeapValueType, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, }, FieldElement, @@ -75,12 +75,6 @@ impl BrilligContext { result: SingleAddrVariable, operation: BrilligBinaryOp, ) { - assert!( - lhs.bit_size == rhs.bit_size, - "Not equal bit size for lhs and rhs: lhs {}, rhs {}", - lhs.bit_size, - rhs.bit_size - ); let is_field_op = lhs.bit_size == FieldElement::max_num_bits(); let expected_result_bit_size = BrilligContext::binary_result_bit_size(operation, lhs.bit_size); @@ -466,10 +460,10 @@ impl BrilligContext { }); } - pub(super) fn trap_instruction(&mut self, revert_data_offset: usize, revert_data_size: usize) { - self.debug_show.trap_instruction(revert_data_offset, revert_data_size); + pub(super) fn trap_instruction(&mut self, revert_data: HeapArray) { + self.debug_show.trap_instruction(revert_data); - self.push_opcode(BrilligOpcode::Trap { revert_data_offset, revert_data_size }); + self.push_opcode(BrilligOpcode::Trap { revert_data }); } } diff --git a/compiler/noirc_evaluator/src/errors.rs b/compiler/noirc_evaluator/src/errors.rs index b3e838e708e..1e922060100 100644 --- a/compiler/noirc_evaluator/src/errors.rs +++ b/compiler/noirc_evaluator/src/errors.rs @@ -7,7 +7,7 @@ //! An Error of the former is a user Error //! //! An Error of the latter is an error in the implementation of the compiler -use acvm::{acir::native_types::Expression, FieldElement}; +use acvm::FieldElement; use iter_extended::vecmap; use noirc_errors::{CustomDiagnostic as Diagnostic, FileDiagnostic}; use thiserror::Error; @@ -17,13 +17,6 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, PartialEq, Eq, Clone, Error)] pub enum RuntimeError { - #[error("{}", format_failed_constraint(.assert_message))] - FailedConstraint { - lhs: Box, - rhs: Box, - call_stack: CallStack, - assert_message: Option, - }, #[error(transparent)] InternalError(#[from] InternalError), #[error("Index out of bounds, array has size {array_size}, but index was {index}")] @@ -52,16 +45,6 @@ pub enum RuntimeError { UnconstrainedOracleReturnToConstrained { call_stack: CallStack }, } -// We avoid showing the actual lhs and rhs since most of the time they are just 0 -// and 1 respectively. This would confuse users if a constraint such as -// assert(foo < bar) fails with "failed constraint: 0 = 1." -fn format_failed_constraint(message: &Option) -> String { - match message { - Some(message) => format!("Failed constraint: '{message}'"), - None => "Failed constraint".to_owned(), - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub enum SsaReport { Warning(InternalWarning), @@ -129,7 +112,6 @@ impl RuntimeError { | InternalError::UndeclaredAcirVar { call_stack } | InternalError::Unexpected { call_stack, .. }, ) - | RuntimeError::FailedConstraint { call_stack, .. } | RuntimeError::IndexOutOfBounds { call_stack, .. } | RuntimeError::InvalidRangeConstraint { call_stack, .. } | RuntimeError::TypeConversion { call_stack, .. } diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index 3482a8c25c7..69e5f6ddfcc 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -7,15 +7,13 @@ //! This module heavily borrows from Cranelift #![allow(dead_code)] -use std::collections::BTreeSet; +use std::collections::{BTreeMap, BTreeSet}; -use crate::{ - brillig::Brillig, - errors::{RuntimeError, SsaReport}, -}; +use crate::errors::{RuntimeError, SsaReport}; use acvm::acir::{ circuit::{ - brillig::BrilligBytecode, Circuit, ExpressionWidth, Program as AcirProgram, PublicInputs, + brillig::BrilligBytecode, Circuit, ErrorSelector, ExpressionWidth, Program as AcirProgram, + PublicInputs, }, native_types::Witness, }; @@ -23,10 +21,16 @@ use acvm::acir::{ use noirc_errors::debug_info::{DebugFunctions, DebugInfo, DebugTypes, DebugVariables}; use noirc_frontend::ast::Visibility; -use noirc_frontend::{hir_def::function::FunctionSignature, monomorphization::ast::Program}; +use noirc_frontend::{ + hir_def::{function::FunctionSignature, types::Type as HirType}, + monomorphization::ast::Program, +}; use tracing::{span, Level}; -use self::{acir_gen::GeneratedAcir, ssa_gen::Ssa}; +use self::{ + acir_gen::{Artifacts, GeneratedAcir}, + ssa_gen::Ssa, +}; mod acir_gen; pub(super) mod function_builder; @@ -45,9 +49,7 @@ pub(crate) fn optimize_into_acir( print_brillig_trace: bool, force_brillig_output: bool, print_timings: bool, -) -> Result<(Vec, Vec), RuntimeError> { - let abi_distinctness = program.return_distinctness; - +) -> Result { let ssa_gen_span = span!(Level::TRACE, "ssa_generation"); let ssa_gen_span_guard = ssa_gen_span.enter(); let ssa = SsaBuilder::new(program, print_passes, force_brillig_output, print_timings)? @@ -64,6 +66,12 @@ pub(crate) fn optimize_into_acir( .run_pass(Ssa::remove_bit_shifts, "After Removing Bit Shifts:") // Run mem2reg once more with the flattened CFG to catch any remaining loads/stores .run_pass(Ssa::mem2reg, "After Mem2Reg:") + // Run the inlining pass again to handle functions with `InlineType::NoPredicates`. + // Before flattening is run, we treat functions marked with the `InlineType::NoPredicates` as an entry point. + // This pass must come immediately following `mem2reg` as the succeeding passes + // may create an SSA which inlining fails to handle. + .run_pass(Ssa::inline_functions_with_no_predicates, "After Inlining:") + .run_pass(Ssa::remove_if_else, "After Remove IfElse:") .run_pass(Ssa::fold_constants, "After Constant Folding:") .run_pass(Ssa::remove_enable_side_effects, "After EnableSideEffects removal:") .run_pass(Ssa::fold_constants_using_constraints, "After Constraint Folding:") @@ -75,7 +83,7 @@ pub(crate) fn optimize_into_acir( drop(ssa_gen_span_guard); - time("SSA to ACIR", print_timings, || ssa.into_acir(&brillig, abi_distinctness)) + time("SSA to ACIR", print_timings, || ssa.into_acir(&brillig)) } // Helper to time SSA passes @@ -99,10 +107,14 @@ pub struct SsaProgramArtifact { pub main_input_witnesses: Vec, pub main_return_witnesses: Vec, pub names: Vec, + pub error_types: BTreeMap, } impl SsaProgramArtifact { - fn new(unconstrained_functions: Vec) -> Self { + fn new( + unconstrained_functions: Vec, + error_types: BTreeMap, + ) -> Self { let program = AcirProgram { functions: Vec::default(), unconstrained_functions }; Self { program, @@ -111,6 +123,7 @@ impl SsaProgramArtifact { main_input_witnesses: Vec::default(), main_return_witnesses: Vec::default(), names: Vec::default(), + error_types, } } @@ -145,7 +158,7 @@ pub fn create_program( let func_sigs = program.function_signatures.clone(); let recursive = program.recursive; - let (generated_acirs, generated_brillig) = optimize_into_acir( + let (generated_acirs, generated_brillig, error_types) = optimize_into_acir( program, enable_ssa_logging, enable_brillig_logging, @@ -158,7 +171,7 @@ pub fn create_program( "The generated ACIRs should match the supplied function signatures" ); - let mut program_artifact = SsaProgramArtifact::new(generated_brillig); + let mut program_artifact = SsaProgramArtifact::new(generated_brillig, error_types); // For setting up the ABI we need separately specify main's input and return witnesses let mut is_main = true; for (acir, func_sig) in generated_acirs.into_iter().zip(func_sigs) { @@ -201,7 +214,7 @@ fn convert_generated_acir_into_circuit( return_witnesses, locations, input_witnesses, - assert_messages, + assertion_payloads: assert_messages, warnings, name, .. @@ -318,10 +331,6 @@ impl SsaBuilder { Ok(self.print(msg)) } - fn to_brillig(&self, print_brillig_trace: bool) -> Brillig { - self.ssa.to_brillig(print_brillig_trace) - } - fn print(self, msg: &str) -> Self { if self.print_ssa_passes { println!("{msg}\n{}", self.ssa); diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 3f5e4129dd0..407cdf0a17f 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -9,7 +9,7 @@ use crate::ssa::ir::types::Type as SsaType; use crate::ssa::ir::{instruction::Endian, types::NumericType}; use acvm::acir::circuit::brillig::{BrilligInputs, BrilligOutputs}; use acvm::acir::circuit::opcodes::{BlockId, MemOp}; -use acvm::acir::circuit::Opcode; +use acvm::acir::circuit::{AssertionPayload, ExpressionOrMemory, Opcode}; use acvm::blackbox_solver; use acvm::brillig_vm::{MemoryValue, VMStatus, VM}; use acvm::{ @@ -495,7 +495,7 @@ impl AcirContext { &mut self, lhs: AcirVar, rhs: AcirVar, - assert_message: Option, + assert_message: Option, ) -> Result<(), RuntimeError> { let lhs_expr = self.var_to_expression(lhs)?; let rhs_expr = self.var_to_expression(rhs)?; @@ -511,14 +511,38 @@ impl AcirContext { } self.acir_ir.assert_is_zero(diff_expr); - if let Some(message) = assert_message { - self.acir_ir.assert_messages.insert(self.acir_ir.last_acir_opcode_location(), message); + if let Some(payload) = assert_message { + self.acir_ir + .assertion_payloads + .insert(self.acir_ir.last_acir_opcode_location(), payload); } self.mark_variables_equivalent(lhs, rhs)?; Ok(()) } + pub(crate) fn vars_to_expressions_or_memory( + &self, + values: &[AcirValue], + ) -> Result, RuntimeError> { + let mut result = Vec::with_capacity(values.len()); + for value in values { + match value { + AcirValue::Var(var, _) => { + result.push(ExpressionOrMemory::Expression(self.var_to_expression(*var)?)); + } + AcirValue::Array(vars) => { + let vars_as_vec: Vec<_> = vars.iter().cloned().collect(); + result.extend(self.vars_to_expressions_or_memory(&vars_as_vec)?); + } + AcirValue::DynamicArray(AcirDynamicArray { block_id, .. }) => { + result.push(ExpressionOrMemory::Memory(*block_id)); + } + } + } + Ok(result) + } + /// Adds a new Variable to context whose value will /// be constrained to be the division of `lhs` and `rhs` pub(crate) fn div_var( @@ -985,9 +1009,10 @@ impl AcirContext { let witness = self.var_to_witness(witness_var)?; self.acir_ir.range_constraint(witness, *bit_size)?; if let Some(message) = message { - self.acir_ir - .assert_messages - .insert(self.acir_ir.last_acir_opcode_location(), message); + self.acir_ir.assertion_payloads.insert( + self.acir_ir.last_acir_opcode_location(), + AssertionPayload::StaticString(message.clone()), + ); } } NumericType::NativeField => { @@ -1299,6 +1324,21 @@ impl AcirContext { self.big_int_ctx.new_big_int(FieldElement::from(modulus_id as u128)); (modulus, vec![result_id.bigint_id(), result_id.modulus_id()]) } + BlackBoxFunc::AES128Encrypt => { + let invalid_input = "aes128_encrypt - operation requires a plaintext to encrypt"; + let input_size = match inputs.first().expect(invalid_input) { + AcirValue::Array(values) => Ok::(values.len()), + AcirValue::DynamicArray(dyn_array) => Ok::(dyn_array.len), + _ => { + return Err(RuntimeError::InternalError(InternalError::General { + message: "aes128_encrypt requires an array of inputs".to_string(), + call_stack: self.get_call_stack(), + })); + } + }?; + output_count = input_size + (16 - input_size % 16); + (vec![], vec![FieldElement::from(output_count as u128)]) + } _ => (vec![], vec![]), }; diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 0b04d1b63ab..c1249ae41c8 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -7,12 +7,11 @@ use crate::{ errors::{InternalError, RuntimeError, SsaReport}, ssa::ir::dfg::CallStack, }; - use acvm::acir::{ circuit::{ brillig::{BrilligInputs, BrilligOutputs}, opcodes::{BlackBoxFuncCall, FunctionInput, Opcode as AcirOpcode}, - OpcodeLocation, + AssertionPayload, OpcodeLocation, }, native_types::Witness, BlackBoxFunc, @@ -61,7 +60,7 @@ pub(crate) struct GeneratedAcir { pub(crate) call_stack: CallStack, /// Correspondence between an opcode index and the error message associated with it. - pub(crate) assert_messages: BTreeMap, + pub(crate) assertion_payloads: BTreeMap, pub(crate) warnings: Vec, @@ -189,6 +188,18 @@ impl GeneratedAcir { let outputs_clone = outputs.clone(); let black_box_func_call = match func_name { + BlackBoxFunc::AES128Encrypt => BlackBoxFuncCall::AES128Encrypt { + inputs: inputs[0].clone(), + iv: inputs[1] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + key: inputs[2] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + outputs, + }, BlackBoxFunc::AND => { BlackBoxFuncCall::AND { lhs: inputs[0][0], rhs: inputs[1][0], output: outputs[0] } } @@ -279,9 +290,9 @@ impl GeneratedAcir { output: outputs[0], } } - BlackBoxFunc::FixedBaseScalarMul => BlackBoxFuncCall::FixedBaseScalarMul { - low: inputs[0][0], - high: inputs[1][0], + BlackBoxFunc::MultiScalarMul => BlackBoxFuncCall::MultiScalarMul { + points: inputs[0].clone(), + scalars: inputs[1].clone(), outputs: (outputs[0], outputs[1]), }, BlackBoxFunc::EmbeddedCurveAdd => BlackBoxFuncCall::EmbeddedCurveAdd { @@ -420,55 +431,6 @@ impl GeneratedAcir { Ok(limb_witnesses) } - /// Returns an expression which represents `lhs * rhs` - /// - /// If one has multiplicative term and the other is of degree one or more, - /// the function creates [intermediate variables][`Witness`] accordingly. - /// There are two cases where we can optimize the multiplication between two expressions: - /// 1. If the sum of the degrees of both expressions is at most 2, then we can just multiply them - /// as each term in the result will be degree-2. - /// 2. If one expression is a constant, then we can just multiply the constant with the other expression - /// - /// (1) is because an [`Expression`] can hold at most a degree-2 univariate polynomial - /// which is what you get when you multiply two degree-1 univariate polynomials. - pub(crate) fn mul_with_witness(&mut self, lhs: &Expression, rhs: &Expression) -> Expression { - use std::borrow::Cow; - let lhs_is_linear = lhs.is_linear(); - let rhs_is_linear = rhs.is_linear(); - - // Case 1: The sum of the degrees of both expressions is at most 2. - // - // If one of the expressions is constant then it does not increase the degree when multiplying by another expression. - // If both of the expressions are linear (degree <=1) then the product will be at most degree 2. - let both_are_linear = lhs_is_linear && rhs_is_linear; - let either_is_const = lhs.is_const() || rhs.is_const(); - if both_are_linear || either_is_const { - return (lhs * rhs).expect("Both expressions are degree <= 1"); - } - - // Case 2: One or both of the sides needs to be reduced to a degree-1 univariate polynomial - let lhs_reduced = if lhs_is_linear { - Cow::Borrowed(lhs) - } else { - Cow::Owned(self.get_or_create_witness(lhs).into()) - }; - - // If the lhs and rhs are the same, then we do not need to reduce - // rhs, we only need to square the lhs. - if lhs == rhs { - return (&*lhs_reduced * &*lhs_reduced) - .expect("Both expressions are reduced to be degree <= 1"); - }; - - let rhs_reduced = if rhs_is_linear { - Cow::Borrowed(rhs) - } else { - Cow::Owned(self.get_or_create_witness(rhs).into()) - }; - - (&*lhs_reduced * &*rhs_reduced).expect("Both expressions are reduced to be degree <= 1") - } - /// Adds an inversion brillig opcode. /// /// This code will invert `expr` without applying constraints @@ -652,12 +614,12 @@ impl GeneratedAcir { ); } for (brillig_index, message) in generated_brillig.assert_messages.iter() { - self.assert_messages.insert( + self.assertion_payloads.insert( OpcodeLocation::Brillig { acir_index: self.opcodes.len() - 1, brillig_index: *brillig_index, }, - message.clone(), + AssertionPayload::StaticString(message.clone()), ); } } @@ -692,7 +654,8 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // All of the hash/cipher methods will take in a // variable number of inputs. - BlackBoxFunc::Keccak256 + BlackBoxFunc::AES128Encrypt + | BlackBoxFunc::Keccak256 | BlackBoxFunc::SHA256 | BlackBoxFunc::Blake2s | BlackBoxFunc::Blake3 @@ -715,9 +678,8 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { | BlackBoxFunc::EcdsaSecp256k1 | BlackBoxFunc::EcdsaSecp256r1 => None, - // Inputs for fixed based scalar multiplication - // is the low and high limbs of the scalar - BlackBoxFunc::FixedBaseScalarMul => Some(2), + // Inputs for multi scalar multiplication is an arbitrary number of [point, scalar] pairs. + BlackBoxFunc::MultiScalarMul => None, // Recursive aggregation has a variable number of inputs BlackBoxFunc::RecursiveAggregation => None, @@ -773,7 +735,7 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // Output of operations over the embedded curve // will be 2 field elements representing the point. - BlackBoxFunc::FixedBaseScalarMul | BlackBoxFunc::EmbeddedCurveAdd => Some(2), + BlackBoxFunc::MultiScalarMul | BlackBoxFunc::EmbeddedCurveAdd => Some(2), // Big integer operations return a big integer BlackBoxFunc::BigIntAdd @@ -787,6 +749,9 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // Recursive aggregation has a variable number of outputs BlackBoxFunc::RecursiveAggregation => None, + + // AES encryption returns a variable number of outputs + BlackBoxFunc::AES128Encrypt => None, } } diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index ee236df8eac..2e2f03a0012 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -9,7 +9,8 @@ use self::acir_ir::generated_acir::BrilligStdlibFunc; use super::function_builder::data_bus::DataBus; use super::ir::dfg::CallStack; use super::ir::function::FunctionId; -use super::ir::instruction::{ConstrainError, UserDefinedConstrainError}; +use super::ir::instruction::{ConstrainError, ErrorType}; +use super::ir::printer::try_to_extract_string_from_error_payload; use super::{ ir::{ dfg::DataFlowGraph, @@ -27,11 +28,11 @@ use crate::brillig::brillig_ir::artifact::{BrilligParameter, GeneratedBrillig}; use crate::brillig::brillig_ir::BrilligContext; use crate::brillig::{brillig_gen::brillig_fn::FunctionContext as BrilligFunctionContext, Brillig}; use crate::errors::{InternalError, InternalWarning, RuntimeError, SsaReport}; -use crate::ssa::ir::function::InlineType; pub(crate) use acir_ir::generated_acir::GeneratedAcir; +use noirc_frontend::monomorphization::ast::InlineType; use acvm::acir::circuit::brillig::BrilligBytecode; -use acvm::acir::circuit::OpcodeLocation; +use acvm::acir::circuit::{AssertionPayload, ErrorSelector, OpcodeLocation}; use acvm::acir::native_types::Witness; use acvm::acir::BlackBoxFunc; use acvm::{ @@ -41,7 +42,6 @@ use acvm::{ use fxhash::FxHashMap as HashMap; use im::Vector; use iter_extended::{try_vecmap, vecmap}; -use noirc_frontend::ast::Distinctness; #[derive(Default)] struct SharedContext { @@ -276,13 +276,12 @@ impl AcirValue { } } +pub(crate) type Artifacts = + (Vec, Vec, BTreeMap); + impl Ssa { #[tracing::instrument(level = "trace", skip_all)] - pub(crate) fn into_acir( - self, - brillig: &Brillig, - abi_distinctness: Distinctness, - ) -> Result<(Vec, Vec), RuntimeError> { + pub(crate) fn into_acir(self, brillig: &Brillig) -> Result { let mut acirs = Vec::new(); // TODO: can we parallelise this? let mut shared_context = SharedContext::default(); @@ -329,34 +328,38 @@ impl Ssa { bytecode: brillig.byte_code, }); - // TODO: check whether doing this for a single circuit's return witnesses is correct. - // We probably need it for all foldable circuits, as any circuit being folded is essentially an entry point. However, I do not know how that - // plays a part when we potentially want not inlined functions normally as part of the compiler. - // Also at the moment we specify Distinctness as part of the ABI exclusively rather than the function itself - // so this will need to be updated. - let main_func_acir = &mut acirs[0]; - match abi_distinctness { - Distinctness::Distinct => { - // Create a witness for each return witness we have - // to guarantee that the return witnesses are distinct - let distinct_return_witness: Vec<_> = main_func_acir - .return_witnesses - .clone() - .into_iter() - .map(|return_witness| { - main_func_acir - .create_witness_for_expression(&Expression::from(return_witness)) - }) - .collect(); - - main_func_acir.return_witnesses = distinct_return_witness; + let runtime_types = self.functions.values().map(|function| function.runtime()); + for (acir, runtime_type) in acirs.iter_mut().zip(runtime_types) { + if matches!(runtime_type, RuntimeType::Acir(_)) { + generate_distinct_return_witnesses(acir); } - Distinctness::DuplicationAllowed => {} } - Ok((acirs, brillig)) + + Ok((acirs, brillig, self.error_selector_to_type)) } } +fn generate_distinct_return_witnesses(acir: &mut GeneratedAcir) { + // Create a witness for each return witness we have to guarantee that the return witnesses match the standard + // layout for serializing those types as if they were being passed as inputs. + // + // This is required for recursion as otherwise in situations where we cannot make use of the program's ABI + // (e.g. for `std::verify_proof` or the solidity verifier), we need extra knowledge about the program we're + // working with rather than following the standard ABI encoding rules. + // + // TODO: We're being conservative here by generating a new witness for every expression. + // This means that we're likely to get a number of constraints which are just renumbering witnesses. + // This can be tackled by: + // - Tracking the last assigned public input witness and only renumbering a witness if it is below this value. + // - Modifying existing constraints to rearrange their outputs so they are suitable + // - See: https://github.com/noir-lang/noir/pull/4467 + let distinct_return_witness = vecmap(acir.return_witnesses.clone(), |return_witness| { + acir.create_witness_for_expression(&Expression::from(return_witness)) + }); + + acir.return_witnesses = distinct_return_witness; +} + impl<'a> Context<'a> { fn new(shared_context: &'a mut SharedContext) -> Context<'a> { let mut acir_context = AcirContext::default(); @@ -385,12 +388,15 @@ impl<'a> Context<'a> { match function.runtime() { RuntimeType::Acir(inline_type) => { match inline_type { - InlineType::Fold => {} InlineType::Inline => { if function.id() != ssa.main_id { panic!("ACIR function should have been inlined earlier if not marked otherwise"); } } + InlineType::NoPredicates => { + panic!("All ACIR functions marked with #[no_predicates] should be inlined before ACIR gen. This is an SSA exclusive codegen attribute"); + } + InlineType::Fold => {} } // We only want to convert entry point functions. This being `main` and those marked with `InlineType::Fold` Ok(Some(self.convert_acir_main(function, ssa, brillig)?)) @@ -611,24 +617,39 @@ impl<'a> Context<'a> { let lhs = self.convert_numeric_value(*lhs, dfg)?; let rhs = self.convert_numeric_value(*rhs, dfg)?; - let assert_message = if let Some(error) = assert_message { - match error.as_ref() { - ConstrainError::Intrinsic(string) - | ConstrainError::UserDefined(UserDefinedConstrainError::Static(string)) => { - Some(string.clone()) + let assert_payload = if let Some(error) = assert_message { + match error { + ConstrainError::Intrinsic(string) => { + Some(AssertionPayload::StaticString(string.clone())) } - ConstrainError::UserDefined(UserDefinedConstrainError::Dynamic( - call_instruction, - )) => { - self.convert_ssa_call(call_instruction, dfg, ssa, brillig, &[])?; - None + ConstrainError::UserDefined(error_selector, values) => { + if let Some(constant_string) = try_to_extract_string_from_error_payload( + *error_selector, + values, + dfg, + ) { + Some(AssertionPayload::StaticString(constant_string)) + } else { + let acir_vars: Vec<_> = values + .iter() + .map(|value| self.convert_value(*value, dfg)) + .collect(); + + let expressions_or_memory = + self.acir_context.vars_to_expressions_or_memory(&acir_vars)?; + + Some(AssertionPayload::Dynamic( + error_selector.as_u64(), + expressions_or_memory, + )) + } } } } else { None }; - self.acir_context.assert_eq_var(lhs, rhs, assert_message)?; + self.acir_context.assert_eq_var(lhs, rhs, assert_payload)?; } Instruction::Cast(value_id, _) => { let acir_var = self.convert_numeric_value(*value_id, dfg)?; @@ -684,6 +705,9 @@ impl<'a> Context<'a> { assert_message.clone(), )?; } + Instruction::IfElse { .. } => { + unreachable!("IfElse instruction remaining in acir-gen") + } } self.acir_context.set_call_stack(CallStack::new()); @@ -711,11 +735,10 @@ impl<'a> Context<'a> { assert!(!matches!(inline_type, InlineType::Inline), "ICE: Got an ACIR function named {} that should have already been inlined", func.name()); let inputs = vecmap(arguments, |arg| self.convert_value(*arg, dfg)); - // TODO(https://github.com/noir-lang/noir/issues/4608): handle complex return types from ACIR functions - let output_count = - result_ids.iter().fold(0usize, |sum, result_id| { - sum + dfg.try_get_array_length(*result_id).unwrap_or(1) - }); + let output_count = result_ids + .iter() + .map(|result_id| dfg.type_of_value(*result_id).flattened_size()) + .sum(); let acir_function_id = ssa .entry_point_to_generated_index @@ -727,6 +750,7 @@ impl<'a> Context<'a> { output_count, self.current_side_effects_enabled_var, )?; + let output_values = self.convert_vars_to_values(output_vars, dfg, result_ids); @@ -952,13 +976,39 @@ impl<'a> Context<'a> { return Ok(()); } - let (new_index, new_value) = - self.convert_array_operation_inputs(array, dfg, index, store_value)?; + // Get an offset such that the type of the array at the offset is the same as the type at the 'index' + // If we find one, we will use it when computing the index under the enable_side_effect predicate + // If not, array_get(..) will use a fallback costing one multiplication in the worst case. + // cf. https://github.com/noir-lang/noir/pull/4971 + let array_id = dfg.resolve(array); + let array_typ = dfg.type_of_value(array_id); + // For simplicity we compute the offset only for simple arrays + let is_simple_array = dfg.instruction_results(instruction).len() == 1 + && can_omit_element_sizes_array(&array_typ); + let offset = if is_simple_array { + let result_type = dfg.type_of_value(dfg.instruction_results(instruction)[0]); + match array_typ { + Type::Array(item_type, _) | Type::Slice(item_type) => item_type + .iter() + .enumerate() + .find_map(|(index, typ)| (result_type == *typ).then_some(index)), + _ => None, + } + } else { + None + }; + let (new_index, new_value) = self.convert_array_operation_inputs( + array, + dfg, + index, + store_value, + offset.unwrap_or_default(), + )?; if let Some(new_value) = new_value { self.array_set(instruction, new_index, new_value, dfg, mutable_array_set)?; } else { - self.array_get(instruction, array, new_index, dfg)?; + self.array_get(instruction, array, new_index, dfg, offset.is_none())?; } Ok(()) @@ -1007,6 +1057,7 @@ impl<'a> Context<'a> { }); } }; + if self.acir_context.is_constant_one(&self.current_side_effects_enabled_var) { // Report the error if side effects are enabled. if index >= array_size { @@ -1047,7 +1098,7 @@ impl<'a> Context<'a> { /// - new_index is the index of the array. ACIR memory operations work with a flat memory, so we fully flattened the specified index /// in case we have a nested array. The index for SSA array operations only represents the flattened index of the current array. /// Thus internal array element type sizes need to be computed to accurately transform the index. - /// - predicate_index is 0, or the index if the predicate is true + /// - predicate_index is offset, or the index if the predicate is true /// - new_value is the optional value when the operation is an array_set /// When there is a predicate, it is predicate*value + (1-predicate)*dummy, where dummy is the value of the array at the requested index. /// It is a dummy value because in the case of a false predicate, the value stored at the requested index will be itself. @@ -1057,14 +1108,18 @@ impl<'a> Context<'a> { dfg: &DataFlowGraph, index: ValueId, store_value: Option, + offset: usize, ) -> Result<(AcirVar, Option), RuntimeError> { let (array_id, array_typ, block_id) = self.check_array_is_initialized(array, dfg)?; let index_var = self.convert_numeric_value(index, dfg)?; let index_var = self.get_flattened_index(&array_typ, array_id, index_var, dfg)?; - let predicate_index = - self.acir_context.mul_var(index_var, self.current_side_effects_enabled_var)?; + // predicate_index = index*predicate + (1-predicate)*offset + let offset = self.acir_context.add_constant(offset); + let sub = self.acir_context.sub_var(index_var, offset)?; + let pred = self.acir_context.mul_var(sub, self.current_side_effects_enabled_var)?; + let predicate_index = self.acir_context.add_var(pred, offset)?; let new_value = if let Some(store) = store_value { let store_value = self.convert_value(store, dfg); @@ -1165,12 +1220,14 @@ impl<'a> Context<'a> { } /// Generates a read opcode for the array + /// `index_side_effect == false` means that we ensured `var_index` will have a type matching the value in the array fn array_get( &mut self, instruction: InstructionId, array: ValueId, mut var_index: AcirVar, dfg: &DataFlowGraph, + mut index_side_effect: bool, ) -> Result { let (array_id, _, block_id) = self.check_array_is_initialized(array, dfg)?; let results = dfg.instruction_results(instruction); @@ -1189,7 +1246,7 @@ impl<'a> Context<'a> { self.data_bus.call_data_map[&array_id] as i128, )); let new_index = self.acir_context.add_var(offset, bus_index)?; - return self.array_get(instruction, call_data, new_index, dfg); + return self.array_get(instruction, call_data, new_index, dfg, index_side_effect); } } @@ -1198,7 +1255,28 @@ impl<'a> Context<'a> { !res_typ.contains_slice_element(), "ICE: Nested slice result found during ACIR generation" ); - let value = self.array_get_value(&res_typ, block_id, &mut var_index)?; + let mut value = self.array_get_value(&res_typ, block_id, &mut var_index)?; + + if let AcirValue::Var(value_var, typ) = &value { + let array_id = dfg.resolve(array_id); + let array_typ = dfg.type_of_value(array_id); + if let (Type::Numeric(numeric_type), AcirType::NumericType(num)) = + (array_typ.first(), typ) + { + if numeric_type.bit_size() <= num.bit_size() { + // first element is compatible + index_side_effect = false; + } + } + // Fallback to multiplication if the index side_effects have not already been handled + if index_side_effect { + // Set the value to 0 if current_side_effects is 0, to ensure it fits in any value type + value = AcirValue::Var( + self.acir_context.mul_var(*value_var, self.current_side_effects_enabled_var)?, + typ.clone(), + ); + } + } self.define_result(dfg, instruction, value.clone()); @@ -2610,25 +2688,22 @@ mod test { }, FieldElement, }; + use noirc_frontend::monomorphization::ast::InlineType; use crate::{ brillig::Brillig, ssa::{ acir_gen::acir_ir::generated_acir::BrilligStdlibFunc, function_builder::FunctionBuilder, - ir::{ - function::{FunctionId, InlineType}, - instruction::BinaryOp, - map::Id, - types::Type, - }, + ir::{function::FunctionId, instruction::BinaryOp, map::Id, types::Type}, }, }; fn build_basic_foo_with_return( builder: &mut FunctionBuilder, foo_id: FunctionId, - is_brillig_func: bool, + // `InlineType` can only exist on ACIR functions, so if the option is `None` we should generate a Brillig function + inline_type: Option, ) { // fn foo f1 { // b0(v0: Field, v1: Field): @@ -2636,10 +2711,10 @@ mod test { // constrain v2 == u1 0 // return v0 // } - if is_brillig_func { - builder.new_brillig_function("foo".into(), foo_id); + if let Some(inline_type) = inline_type { + builder.new_function("foo".into(), foo_id, inline_type); } else { - builder.new_function("foo".into(), foo_id, InlineType::Fold); + builder.new_brillig_function("foo".into(), foo_id); } let foo_v0 = builder.add_parameter(Type::field()); let foo_v1 = builder.add_parameter(Type::field()); @@ -2650,8 +2725,29 @@ mod test { builder.terminate_with_return(vec![foo_v0]); } + /// Check that each `InlineType` which prevents inlining functions generates code in the same manner + #[test] + fn basic_calls_fold() { + basic_call_with_outputs_assert(InlineType::Fold); + call_output_as_next_call_input(InlineType::Fold); + basic_nested_call(InlineType::Fold); + } + #[test] - fn basic_call_with_outputs_assert() { + #[should_panic] + fn basic_calls_no_predicates() { + basic_call_with_outputs_assert(InlineType::NoPredicates); + call_output_as_next_call_input(InlineType::NoPredicates); + basic_nested_call(InlineType::NoPredicates); + } + + #[test] + #[should_panic] + fn call_without_inline_attribute() { + basic_call_with_outputs_assert(InlineType::Inline); + } + + fn basic_call_with_outputs_assert(inline_type: InlineType) { // acir(inline) fn main f0 { // b0(v0: Field, v1: Field): // v2 = call f1(v0, v1) @@ -2679,12 +2775,12 @@ mod test { builder.insert_constrain(main_call1_results[0], main_call2_results[0], None); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, false); + build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); let ssa = builder.finish(); - let (acir_functions, _) = ssa - .into_acir(&Brillig::default(), noirc_frontend::ast::Distinctness::Distinct) + let (acir_functions, _, _) = ssa + .into_acir(&Brillig::default()) .expect("Should compile manually written SSA into ACIR"); // Expected result: // main f0 @@ -2745,8 +2841,7 @@ mod test { } } - #[test] - fn call_output_as_next_call_input() { + fn call_output_as_next_call_input(inline_type: InlineType) { // acir(inline) fn main f0 { // b0(v0: Field, v1: Field): // v3 = call f1(v0, v1) @@ -2775,14 +2870,14 @@ mod test { builder.insert_constrain(main_call1_results[0], main_call2_results[0], None); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, false); + build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); let ssa = builder.finish(); - let (acir_functions, _) = ssa - .into_acir(&Brillig::default(), noirc_frontend::ast::Distinctness::Distinct) + let (acir_functions, _, _) = ssa + .into_acir(&Brillig::default()) .expect("Should compile manually written SSA into ACIR"); - // The expected result should look very similar to the abvoe test expect that the input witnesses of the `Call` + // The expected result should look very similar to the above test expect that the input witnesses of the `Call` // opcodes will be different. The changes can discerned from the checks below. let main_acir = &acir_functions[0]; @@ -2794,8 +2889,7 @@ mod test { check_call_opcode(&main_opcodes[1], 1, vec![Witness(2), Witness(1)], vec![Witness(3)]); } - #[test] - fn basic_nested_call() { + fn basic_nested_call(inline_type: InlineType) { // SSA for the following Noir program: // fn main(x: Field, y: pub Field) { // let z = func_with_nested_foo_call(x, y); @@ -2851,7 +2945,7 @@ mod test { builder.new_function( "func_with_nested_foo_call".into(), func_with_nested_foo_call_id, - InlineType::Fold, + inline_type, ); let func_with_nested_call_v0 = builder.add_parameter(Type::field()); let func_with_nested_call_v1 = builder.add_parameter(Type::field()); @@ -2866,12 +2960,12 @@ mod test { .to_vec(); builder.terminate_with_return(vec![foo_call[0]]); - build_basic_foo_with_return(&mut builder, foo_id, false); + build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); let ssa = builder.finish(); - let (acir_functions, _) = ssa - .into_acir(&Brillig::default(), noirc_frontend::ast::Distinctness::Distinct) + let (acir_functions, _, _) = ssa + .into_acir(&Brillig::default()) .expect("Should compile manually written SSA into ACIR"); assert_eq!(acir_functions.len(), 3, "Should have three ACIR functions"); @@ -2887,9 +2981,10 @@ mod test { let func_with_nested_call_acir = &acir_functions[1]; let func_with_nested_call_opcodes = func_with_nested_call_acir.opcodes(); + assert_eq!( func_with_nested_call_opcodes.len(), - 2, + 3, "Should have an expression and a call to a nested `foo`" ); // Should call foo f2 @@ -2977,16 +3072,14 @@ mod test { builder.insert_call(bar, vec![main_v0, main_v1], vec![Type::field()]).to_vec(); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, true); - build_basic_foo_with_return(&mut builder, bar_id, true); + build_basic_foo_with_return(&mut builder, foo_id, None); + build_basic_foo_with_return(&mut builder, bar_id, None); let ssa = builder.finish(); let brillig = ssa.to_brillig(false); - println!("{}", ssa); - let (acir_functions, brillig_functions) = ssa - .into_acir(&brillig, noirc_frontend::ast::Distinctness::Distinct) - .expect("Should compile manually written SSA into ACIR"); + let (acir_functions, brillig_functions, _) = + ssa.into_acir(&brillig).expect("Should compile manually written SSA into ACIR"); assert_eq!(acir_functions.len(), 1, "Should only have a `main` ACIR function"); assert_eq!(brillig_functions.len(), 2, "Should only have generated two Brillig functions"); @@ -3041,8 +3134,8 @@ mod test { // The Brillig bytecode we insert for the stdlib is hardcoded so we do not need to provide any // Brillig artifacts to the ACIR gen pass. - let (acir_functions, brillig_functions) = ssa - .into_acir(&Brillig::default(), noirc_frontend::ast::Distinctness::Distinct) + let (acir_functions, brillig_functions, _) = ssa + .into_acir(&Brillig::default()) .expect("Should compile manually written SSA into ACIR"); assert_eq!(acir_functions.len(), 1, "Should only have a `main` ACIR function"); @@ -3106,16 +3199,15 @@ mod test { builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, true); + build_basic_foo_with_return(&mut builder, foo_id, None); let ssa = builder.finish(); // We need to generate Brillig artifacts for the regular Brillig function and pass them to the ACIR generation pass. let brillig = ssa.to_brillig(false); println!("{}", ssa); - let (acir_functions, brillig_functions) = ssa - .into_acir(&brillig, noirc_frontend::ast::Distinctness::Distinct) - .expect("Should compile manually written SSA into ACIR"); + let (acir_functions, brillig_functions, _) = + ssa.into_acir(&brillig).expect("Should compile manually written SSA into ACIR"); assert_eq!(acir_functions.len(), 1, "Should only have a `main` ACIR function"); // We expect 3 brillig functions: @@ -3192,17 +3284,18 @@ mod test { builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, true); - build_basic_foo_with_return(&mut builder, bar_id, false); + // Build a Brillig function + build_basic_foo_with_return(&mut builder, foo_id, None); + // Build an ACIR function which has the same logic as the Brillig function above + build_basic_foo_with_return(&mut builder, bar_id, Some(InlineType::Fold)); let ssa = builder.finish(); // We need to generate Brillig artifacts for the regular Brillig function and pass them to the ACIR generation pass. let brillig = ssa.to_brillig(false); println!("{}", ssa); - let (acir_functions, brillig_functions) = ssa - .into_acir(&brillig, noirc_frontend::ast::Distinctness::Distinct) - .expect("Should compile manually written SSA into ACIR"); + let (acir_functions, brillig_functions, _) = + ssa.into_acir(&brillig).expect("Should compile manually written SSA into ACIR"); assert_eq!(acir_functions.len(), 2, "Should only have two ACIR functions"); // We expect 3 brillig functions: @@ -3277,18 +3370,15 @@ mod test { // This check right now expects to only call one Brillig function. let mut num_normal_brillig_calls = 0; for (i, opcode) in opcodes.iter().enumerate() { - match opcode { - Opcode::BrilligCall { id, .. } => { - if brillig_stdlib_function_locations.get(&OpcodeLocation::Acir(i)).is_some() { - // We should have already checked Brillig stdlib functions and only want to check normal Brillig calls here - continue; - } - // We only generate one normal Brillig call so we should expect a function ID of `0` - let expected_id = 0u32; - assert_eq!(*id, expected_id, "Expected an id of {expected_id} but got {id}"); - num_normal_brillig_calls += 1; + if let Opcode::BrilligCall { id, .. } = opcode { + if brillig_stdlib_function_locations.get(&OpcodeLocation::Acir(i)).is_some() { + // We should have already checked Brillig stdlib functions and only want to check normal Brillig calls here + continue; } - _ => {} + // We only generate one normal Brillig call so we should expect a function ID of `0` + let expected_id = 0u32; + assert_eq!(*id, expected_id, "Expected an id of {expected_id} but got {id}"); + num_normal_brillig_calls += 1; } } diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index 75a427397b6..f5afbfae1bb 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -1,9 +1,10 @@ pub(crate) mod data_bus; -use std::{borrow::Cow, rc::Rc}; +use std::{borrow::Cow, collections::BTreeMap, rc::Rc}; -use acvm::FieldElement; +use acvm::{acir::circuit::ErrorSelector, FieldElement}; use noirc_errors::Location; +use noirc_frontend::monomorphization::ast::InlineType; use crate::ssa::ir::{ basic_block::BasicBlockId, @@ -17,8 +18,8 @@ use super::{ ir::{ basic_block::BasicBlock, dfg::{CallStack, InsertInstructionResult}, - function::{InlineType, RuntimeType}, - instruction::{ConstrainError, InstructionId, Intrinsic}, + function::RuntimeType, + instruction::{ConstrainError, ErrorType, InstructionId, Intrinsic}, }, ssa_gen::Ssa, }; @@ -35,6 +36,7 @@ pub(crate) struct FunctionBuilder { current_block: BasicBlockId, finished_functions: Vec, call_stack: CallStack, + error_types: BTreeMap, } impl FunctionBuilder { @@ -50,6 +52,7 @@ impl FunctionBuilder { current_function: new_function, finished_functions: Vec::new(), call_stack: CallStack::new(), + error_types: BTreeMap::default(), } } @@ -99,7 +102,7 @@ impl FunctionBuilder { /// Consume the FunctionBuilder returning all the functions it has generated. pub(crate) fn finish(mut self) -> Ssa { self.finished_functions.push(self.current_function); - Ssa::new(self.finished_functions) + Ssa::new(self.finished_functions, self.error_types) } /// Add a parameter to the current function with the given parameter type. @@ -229,7 +232,12 @@ impl FunctionBuilder { ) -> ValueId { let lhs_type = self.type_of_value(lhs); let rhs_type = self.type_of_value(rhs); - assert_eq!(lhs_type, rhs_type, "ICE - Binary instruction operands must have the same type"); + if operator != BinaryOp::Shl && operator != BinaryOp::Shr { + assert_eq!( + lhs_type, rhs_type, + "ICE - Binary instruction operands must have the same type" + ); + } let instruction = Instruction::Binary(Binary { lhs, rhs, operator }); self.insert_instruction(instruction, None).first() } @@ -263,7 +271,7 @@ impl FunctionBuilder { &mut self, lhs: ValueId, rhs: ValueId, - assert_message: Option>, + assert_message: Option, ) { self.insert_instruction(Instruction::Constrain(lhs, rhs, assert_message), None); } @@ -474,6 +482,10 @@ impl FunctionBuilder { } } } + + pub(crate) fn record_error_type(&mut self, selector: ErrorSelector, typ: ErrorType) { + self.error_types.insert(selector, typ); + } } impl std::ops::Index for FunctionBuilder { diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 6b950c327cf..85630b75614 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -554,7 +554,10 @@ impl<'dfg> InsertInstructionResult<'dfg> { match self { InsertInstructionResult::SimplifiedTo(value) => *value, InsertInstructionResult::SimplifiedToMultiple(values) => values[0], - InsertInstructionResult::Results(_, results) => results[0], + InsertInstructionResult::Results(_, results) => { + assert_eq!(results.len(), 1); + results[0] + } InsertInstructionResult::InstructionRemoved => { panic!("Instruction was removed, no results") } @@ -583,6 +586,24 @@ impl<'dfg> InsertInstructionResult<'dfg> { } } +impl<'dfg> std::ops::Index for InsertInstructionResult<'dfg> { + type Output = ValueId; + + fn index(&self, index: usize) -> &Self::Output { + match self { + InsertInstructionResult::Results(_, results) => &results[index], + InsertInstructionResult::SimplifiedTo(result) => { + assert_eq!(index, 0); + result + } + InsertInstructionResult::SimplifiedToMultiple(results) => &results[index], + InsertInstructionResult::InstructionRemoved => { + panic!("Cannot index into InsertInstructionResult::InstructionRemoved") + } + } + } +} + #[cfg(test)] mod tests { use super::DataFlowGraph; diff --git a/compiler/noirc_evaluator/src/ssa/ir/function.rs b/compiler/noirc_evaluator/src/ssa/ir/function.rs index 011bee36661..a49e02b0380 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/function.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/function.rs @@ -1,6 +1,7 @@ use std::collections::BTreeSet; use iter_extended::vecmap; +use noirc_frontend::monomorphization::ast::InlineType; use super::basic_block::BasicBlockId; use super::dfg::DataFlowGraph; @@ -17,18 +18,6 @@ pub(crate) enum RuntimeType { Brillig, } -/// Represents how a RuntimeType::Acir function should be inlined. -/// This type is only relevant for ACIR functions as we do not inline any Brillig functions -#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub(crate) enum InlineType { - /// The most basic entry point can expect all its functions to be inlined. - /// All function calls are expected to be inlined into a single ACIR. - #[default] - Inline, - /// Functions marked as foldable will not be inlined and compiled separately into ACIR - Fold, -} - impl RuntimeType { /// Returns whether the runtime type represents an entry point. /// We return `false` for InlineType::Inline on default, which is true @@ -36,10 +25,7 @@ impl RuntimeType { /// handling in any places where this function determines logic. pub(crate) fn is_entry_point(&self) -> bool { match self { - RuntimeType::Acir(inline_type) => match inline_type { - InlineType::Inline => false, - InlineType::Fold => true, - }, + RuntimeType::Acir(inline_type) => inline_type.is_entry_point(), RuntimeType::Brillig => true, } } @@ -99,6 +85,13 @@ impl Function { self.runtime = runtime; } + pub(crate) fn is_no_predicates(&self) -> bool { + match self.runtime() { + RuntimeType::Acir(inline_type) => matches!(inline_type, InlineType::NoPredicates), + RuntimeType::Brillig => false, + } + } + /// Retrieves the entry block of a function. /// /// A function's entry block contains the instructions @@ -163,15 +156,6 @@ impl std::fmt::Display for RuntimeType { } } -impl std::fmt::Display for InlineType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - InlineType::Inline => write!(f, "inline"), - InlineType::Fold => write!(f, "fold"), - } - } -} - /// FunctionId is a reference for a function /// /// This Id is how each function refers to other functions diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 04f33d528cd..7cc19e9f2b8 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -1,5 +1,17 @@ -use acvm::{acir::BlackBoxFunc, FieldElement}; +use std::hash::{Hash, Hasher}; + +use acvm::{ + acir::{ + circuit::{ErrorSelector, STRING_ERROR_SELECTOR}, + BlackBoxFunc, + }, + FieldElement, +}; +use fxhash::FxHasher; use iter_extended::vecmap; +use noirc_frontend::hir_def::types::Type as HirType; + +use crate::ssa::opt::flatten_cfg::value_merger::ValueMerger; use super::{ basic_block::BasicBlockId, @@ -157,7 +169,7 @@ pub(crate) enum Instruction { Truncate { value: ValueId, bit_size: u32, max_bit_size: u32 }, /// Constrains two values to be equal to one another. - Constrain(ValueId, ValueId, Option>), + Constrain(ValueId, ValueId, Option), /// Range constrain `value` to `max_bit_size` RangeCheck { value: ValueId, max_bit_size: u32, assert_message: Option }, @@ -206,6 +218,14 @@ pub(crate) enum Instruction { /// implemented via reference counting. In ACIR code this is done with im::Vector and these /// DecrementRc instructions are ignored. DecrementRc { value: ValueId }, + + /// Merge two values returned from opposite branches of a conditional into one. + IfElse { + then_condition: ValueId, + then_value: ValueId, + else_condition: ValueId, + else_value: ValueId, + }, } impl Instruction { @@ -219,10 +239,12 @@ impl Instruction { match self { Instruction::Binary(binary) => binary.result_type(), Instruction::Cast(_, typ) => InstructionResultType::Known(typ.clone()), - Instruction::Not(value) | Instruction::Truncate { value, .. } => { + Instruction::Not(value) + | Instruction::Truncate { value, .. } + | Instruction::ArraySet { array: value, .. } + | Instruction::IfElse { then_value: value, .. } => { InstructionResultType::Operand(*value) } - Instruction::ArraySet { array, .. } => InstructionResultType::Operand(*array), Instruction::Constrain(..) | Instruction::Store { .. } | Instruction::IncrementRc { .. } @@ -242,20 +264,11 @@ impl Instruction { matches!(self.result_type(), InstructionResultType::Unknown) } - /// Pure `Instructions` are instructions which have no side-effects and results are a function of the inputs only, - /// i.e. there are no interactions with memory. - /// - /// Pure instructions can be replaced with the results of another pure instruction with the same inputs. - pub(crate) fn is_pure(&self, dfg: &DataFlowGraph) -> bool { + /// Indicates if the instruction can be safely replaced with the results of another instruction with the same inputs. + pub(crate) fn can_be_deduplicated(&self, dfg: &DataFlowGraph) -> bool { use Instruction::*; match self { - Binary(bin) => { - // In ACIR, a division with a false predicate outputs (0,0), so it cannot replace another instruction unless they have the same predicate - bin.operator != BinaryOp::Div - } - Cast(_, _) | Truncate { .. } | Not(_) => true, - // These either have side-effects or interact with memory Constrain(..) | EnableSideEffects { .. } @@ -266,31 +279,37 @@ impl Instruction { | DecrementRc { .. } | RangeCheck { .. } => false, - // These can have different behavior depending on the EnableSideEffectsIf context. - // Enabling constant folding for these potentially enables replacing an enabled - // array get with one that was disabled. See - // https://github.com/noir-lang/noir/pull/4716#issuecomment-2047846328. - ArrayGet { .. } | ArraySet { .. } => false, - Call { func, .. } => match dfg[*func] { Value::Intrinsic(intrinsic) => !intrinsic.has_side_effects(), _ => false, }, + + // These can have different behavior depending on the EnableSideEffectsIf context. + // Replacing them with a similar instruction potentially enables replacing an instruction + // with one that was disabled. See + // https://github.com/noir-lang/noir/pull/4716#issuecomment-2047846328. + Binary(_) + | Cast(_, _) + | Not(_) + | Truncate { .. } + | IfElse { .. } + | ArrayGet { .. } + | ArraySet { .. } => !self.requires_acir_gen_predicate(dfg), } } - pub(crate) fn has_side_effects(&self, dfg: &DataFlowGraph) -> bool { + pub(crate) fn can_eliminate_if_unused(&self, dfg: &DataFlowGraph) -> bool { use Instruction::*; match self { Binary(binary) => { if matches!(binary.operator, BinaryOp::Div | BinaryOp::Mod) { if let Some(rhs) = dfg.get_numeric_constant(binary.rhs) { - rhs == FieldElement::zero() + rhs != FieldElement::zero() } else { - true + false } } else { - false + true } } Cast(_, _) @@ -299,32 +318,67 @@ impl Instruction { | Allocate | Load { .. } | ArrayGet { .. } - | ArraySet { .. } => false, + | IfElse { .. } + | ArraySet { .. } => true, Constrain(..) | Store { .. } | EnableSideEffects { .. } | IncrementRc { .. } | DecrementRc { .. } - | RangeCheck { .. } => true, + | RangeCheck { .. } => false, // Some `Intrinsic`s have side effects so we must check what kind of `Call` this is. Call { func, .. } => match dfg[*func] { - Value::Intrinsic(intrinsic) => intrinsic.has_side_effects(), + Value::Intrinsic(intrinsic) => !intrinsic.has_side_effects(), // All foreign functions are treated as having side effects. // This is because they can be used to pass information // from the ACVM to the external world during execution. - Value::ForeignFunction(_) => true, + Value::ForeignFunction(_) => false, // We must assume that functions contain a side effect as we cannot inspect more deeply. - Value::Function(_) => true, + Value::Function(_) => false, _ => false, }, } } + /// If true the instruction will depends on enable_side_effects context during acir-gen + fn requires_acir_gen_predicate(&self, dfg: &DataFlowGraph) -> bool { + match self { + Instruction::Binary(binary) + if matches!(binary.operator, BinaryOp::Div | BinaryOp::Mod) => + { + true + } + Instruction::EnableSideEffects { .. } + | Instruction::ArrayGet { .. } + | Instruction::ArraySet { .. } => true, + + Instruction::Call { func, .. } => match dfg[*func] { + Value::Function(_) => true, + Value::Intrinsic(intrinsic) => { + matches!(intrinsic, Intrinsic::SliceInsert | Intrinsic::SliceRemove) + } + _ => false, + }, + Instruction::Cast(_, _) + | Instruction::Binary(_) + | Instruction::Not(_) + | Instruction::Truncate { .. } + | Instruction::Constrain(_, _, _) + | Instruction::RangeCheck { .. } + | Instruction::Allocate + | Instruction::Load { .. } + | Instruction::Store { .. } + | Instruction::IfElse { .. } + | Instruction::IncrementRc { .. } + | Instruction::DecrementRc { .. } => false, + } + } + /// Maps each ValueId inside this instruction to a new ValueId, returning the new instruction. /// Note that the returned instruction is fresh and will not have an assigned InstructionId /// until it is manually inserted in a DataFlowGraph later. @@ -346,12 +400,12 @@ impl Instruction { // Must map the `lhs` and `rhs` first as the value `f` is moved with the closure let lhs = f(*lhs); let rhs = f(*rhs); - let assert_message = assert_message.as_ref().map(|error| match error.as_ref() { - ConstrainError::UserDefined(UserDefinedConstrainError::Dynamic(call_instr)) => { - let new_instr = call_instr.map_values(f); - Box::new(ConstrainError::UserDefined(UserDefinedConstrainError::Dynamic( - new_instr, - ))) + let assert_message = assert_message.as_ref().map(|error| match error { + ConstrainError::UserDefined(selector, payload_values) => { + ConstrainError::UserDefined( + *selector, + payload_values.iter().map(|&value| f(value)).collect(), + ) } _ => error.clone(), }); @@ -387,6 +441,14 @@ impl Instruction { assert_message: assert_message.clone(), } } + Instruction::IfElse { then_condition, then_value, else_condition, else_value } => { + Instruction::IfElse { + then_condition: f(*then_condition), + then_value: f(*then_value), + else_condition: f(*else_condition), + else_value: f(*else_value), + } + } } } @@ -412,13 +474,10 @@ impl Instruction { Instruction::Constrain(lhs, rhs, assert_error) => { f(*lhs); f(*rhs); - if let Some(error) = assert_error.as_ref() { - if let ConstrainError::UserDefined(UserDefinedConstrainError::Dynamic( - call_instr, - )) = error.as_ref() - { - call_instr.for_each_value(f); - } + if let Some(ConstrainError::UserDefined(_, values)) = assert_error.as_ref() { + values.iter().for_each(|&val| { + f(val); + }); } } @@ -444,6 +503,12 @@ impl Instruction { | Instruction::RangeCheck { value, .. } => { f(*value); } + Instruction::IfElse { then_condition, then_value, else_condition, else_value } => { + f(*then_condition); + f(*then_value); + f(*else_condition); + f(*else_value); + } } } @@ -595,6 +660,51 @@ impl Instruction { None } } + Instruction::IfElse { then_condition, then_value, else_condition, else_value } => { + let typ = dfg.type_of_value(*then_value); + + if let Some(constant) = dfg.get_numeric_constant(*then_condition) { + if constant.is_one() { + return SimplifiedTo(*then_value); + } else if constant.is_zero() { + return SimplifiedTo(*else_value); + } + } + + if matches!(&typ, Type::Numeric(_)) { + let then_condition = *then_condition; + let then_value = *then_value; + let else_condition = *else_condition; + let else_value = *else_value; + + let result = ValueMerger::merge_numeric_values( + dfg, + block, + then_condition, + else_condition, + then_value, + else_value, + ); + SimplifiedTo(result) + } else { + None + } + } + } + } +} + +pub(crate) type ErrorType = HirType; + +pub(crate) fn error_selector_from_type(typ: &ErrorType) -> ErrorSelector { + match typ { + ErrorType::String(_) => STRING_ERROR_SELECTOR, + _ => { + let mut hasher = FxHasher::default(); + typ.hash(&mut hasher); + let hash = hasher.finish(); + assert!(hash != 0, "ICE: Error type {} collides with the string error type", typ); + ErrorSelector::new(hash) } } } @@ -604,17 +714,7 @@ pub(crate) enum ConstrainError { // These are errors which have been hardcoded during SSA gen Intrinsic(String), // These are errors issued by the user - UserDefined(UserDefinedConstrainError), -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub(crate) enum UserDefinedConstrainError { - // These are errors which come from static strings specified by a Noir program - Static(String), - // These are errors which come from runtime expressions specified by a Noir program - // We store an `Instruction` as we want this Instruction to be atomic in SSA with - // a constrain instruction, and leave codegen of this instruction to lower level passes. - Dynamic(Instruction), + UserDefined(ErrorSelector, Vec), } impl From for ConstrainError { diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 1187ea8cb07..7ad6a625f9c 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -87,8 +87,18 @@ pub(super) fn simplify_call( Intrinsic::AsSlice => { let array = dfg.get_array_constant(arguments[0]); if let Some((array, array_type)) = array { - let slice_length = dfg.make_constant(array.len().into(), Type::length_type()); + // Compute the resulting slice length by dividing the flattened + // array length by the size of each array element + let elements_size = array_type.element_size(); let inner_element_types = array_type.element_types(); + assert_eq!( + 0, + array.len() % elements_size, + "expected array length to be multiple of its elements size" + ); + let slice_length_value = array.len() / elements_size; + let slice_length = + dfg.make_constant(slice_length_value.into(), Type::length_type()); let new_slice = dfg.make_array(array, Type::Slice(inner_element_types)); SimplifyResult::SimplifiedToMultiple(vec![slice_length, new_slice]) } else { @@ -354,7 +364,9 @@ fn simplify_slice_push_back( slice_sizes.insert(set_last_slice_value, slice_size / element_size); slice_sizes.insert(new_slice, slice_size / element_size); - let mut value_merger = ValueMerger::new(dfg, block, &mut slice_sizes); + let unknown = &mut HashMap::default(); + let mut value_merger = ValueMerger::new(dfg, block, &mut slice_sizes, unknown, None); + let new_slice = value_merger.merge_values( len_not_equals_capacity, len_equals_capacity, @@ -452,7 +464,7 @@ fn simplify_black_box_func( simplify_signature(dfg, arguments, acvm::blackbox_solver::ecdsa_secp256r1_verify) } - BlackBoxFunc::FixedBaseScalarMul + BlackBoxFunc::MultiScalarMul | BlackBoxFunc::SchnorrVerify | BlackBoxFunc::PedersenCommitment | BlackBoxFunc::PedersenHash @@ -480,6 +492,7 @@ fn simplify_black_box_func( ) } BlackBoxFunc::Sha256Compression => SimplifyResult::None, //TODO(Guillaume) + BlackBoxFunc::AES128Encrypt => SimplifyResult::None, } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs index b4198e2cfec..d844f350927 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs @@ -7,7 +7,7 @@ use super::{Binary, BinaryOp, ConstrainError, DataFlowGraph, Instruction, Type, pub(super) fn decompose_constrain( lhs: ValueId, rhs: ValueId, - msg: &Option>, + msg: &Option, dfg: &mut DataFlowGraph, ) -> Vec { let lhs = dfg.resolve(lhs); diff --git a/compiler/noirc_evaluator/src/ssa/ir/post_order.rs b/compiler/noirc_evaluator/src/ssa/ir/post_order.rs index d95ec451779..94ff96ba1d7 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/post_order.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/post_order.rs @@ -51,7 +51,7 @@ impl PostOrder { // stack, we push the item that's due for a visit first to the top. for successor_id in func.dfg[block_id].successors().rev() { if !visited.contains(&successor_id) { - // This not visited check would also be cover by the the next + // This not visited check would also be cover by the next // iteration, but checking here two saves an iteration per successor. stack.push((Visit::First, successor_id)); } diff --git a/compiler/noirc_evaluator/src/ssa/ir/printer.rs b/compiler/noirc_evaluator/src/ssa/ir/printer.rs index d17d2989341..58c593b0ad6 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/printer.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/printer.rs @@ -4,16 +4,15 @@ use std::{ fmt::{Formatter, Result}, }; +use acvm::acir::circuit::{ErrorSelector, STRING_ERROR_SELECTOR}; use iter_extended::vecmap; use super::{ basic_block::BasicBlockId, + dfg::DataFlowGraph, function::Function, - instruction::{ - ConstrainError, Instruction, InstructionId, TerminatorInstruction, - UserDefinedConstrainError, - }, - value::ValueId, + instruction::{ConstrainError, Instruction, InstructionId, TerminatorInstruction}, + value::{Value, ValueId}, }; /// Helper function for Function's Display impl to pretty-print the function with the given formatter. @@ -63,7 +62,6 @@ pub(crate) fn display_block( /// Specialize displaying value ids so that if they refer to a numeric /// constant or a function we print those directly. fn value(function: &Function, id: ValueId) -> String { - use super::value::Value; let id = function.dfg.resolve(id); match &function.dfg[id] { Value::NumericConstant { constant, typ } => { @@ -159,7 +157,6 @@ fn display_instruction_inner( Instruction::Constrain(lhs, rhs, error) => { write!(f, "constrain {} == {}", show(*lhs), show(*rhs))?; if let Some(error) = error { - write!(f, " ")?; display_constrain_error(function, error, f) } else { writeln!(f) @@ -184,7 +181,7 @@ fn display_instruction_inner( let index = show(*index); let value = show(*value); let mutable = if *mutable { " mut" } else { "" }; - writeln!(f, "array_set{mutable} {array}, index {index}, value {value}",) + writeln!(f, "array_set{mutable} {array}, index {index}, value {value}") } Instruction::IncrementRc { value } => { writeln!(f, "inc_rc {}", show(*value)) @@ -195,21 +192,64 @@ fn display_instruction_inner( Instruction::RangeCheck { value, max_bit_size, .. } => { writeln!(f, "range_check {} to {} bits", show(*value), *max_bit_size,) } + Instruction::IfElse { then_condition, then_value, else_condition, else_value } => { + let then_condition = show(*then_condition); + let then_value = show(*then_value); + let else_condition = show(*else_condition); + let else_value = show(*else_value); + writeln!( + f, + "if {then_condition} then {then_value} else if {else_condition} then {else_value}" + ) + } } } +/// Tries to extract a constant string from an error payload. +pub(crate) fn try_to_extract_string_from_error_payload( + error_selector: ErrorSelector, + values: &[ValueId], + dfg: &DataFlowGraph, +) -> Option { + ((error_selector == STRING_ERROR_SELECTOR) && (values.len() == 1)) + .then_some(()) + .and_then(|()| { + let Value::Array { array: values, .. } = &dfg[values[0]] else { + return None; + }; + let fields: Option> = + values.iter().map(|value_id| dfg.get_numeric_constant(*value_id)).collect(); + + fields + }) + .map(|fields| { + fields + .iter() + .map(|field| { + let as_u8 = field.try_to_u64().unwrap_or_default() as u8; + as_u8 as char + }) + .collect() + }) +} + fn display_constrain_error( function: &Function, error: &ConstrainError, f: &mut Formatter, ) -> Result { match error { - ConstrainError::Intrinsic(assert_message_string) - | ConstrainError::UserDefined(UserDefinedConstrainError::Static(assert_message_string)) => { - writeln!(f, "{assert_message_string:?}") - } - ConstrainError::UserDefined(UserDefinedConstrainError::Dynamic(assert_message_call)) => { - display_instruction_inner(function, assert_message_call, f) + ConstrainError::Intrinsic(assert_message_string) => { + writeln!(f, " '{assert_message_string:?}'") + } + ConstrainError::UserDefined(selector, values) => { + if let Some(constant_string) = + try_to_extract_string_from_error_payload(*selector, values, &function.dfg) + { + writeln!(f, " '{}'", constant_string) + } else { + writeln!(f, ", data {}", value_list(function, values)) + } } } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/types.rs b/compiler/noirc_evaluator/src/ssa/ir/types.rs index 48036580d29..d72ad487f66 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/types.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/types.rs @@ -166,6 +166,14 @@ impl Type { other => panic!("element_types: Expected array or slice, found {other}"), } } + + pub(crate) fn first(&self) -> Type { + match self { + Type::Numeric(_) | Type::Function => self.clone(), + Type::Reference(typ) => typ.first(), + Type::Slice(element_types) | Type::Array(element_types, _) => element_types[0].first(), + } + } } /// Composite Types are essentially flattened struct or tuple types. diff --git a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs index 5a7134f3486..ac2f6424332 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -6,9 +6,8 @@ //! by the [`DataFlowGraph`] automatically as new instructions are pushed. //! - Check whether any input values have been constrained to be equal to a value of a simpler form //! by a [constrain instruction][Instruction::Constrain]. If so, replace the input value with the simpler form. -//! - Check whether the instruction is [pure][Instruction::is_pure()] -//! and there exists a duplicate instruction earlier in the same block. -//! If so, the instruction can be replaced with the results of this previous instruction. +//! - Check whether the instruction [can_be_replaced][Instruction::can_be_replaced()] +//! by duplicate instruction earlier in the same block. //! //! These operations are done in parallel so that they can each benefit from each other //! without the need for multiple passes. @@ -257,9 +256,9 @@ impl Context { } } - // If the instruction doesn't have side-effects, cache the results so we can reuse them if - // the same instruction appears again later in the block. - if instruction.is_pure(dfg) { + // If the instruction doesn't have side-effects and if it won't interact with enable_side_effects during acir_gen, + // we cache the results so we can reuse them if the same instruction appears again later in the block. + if instruction.can_be_deduplicated(dfg) { instruction_result_cache.insert(instruction, instruction_results); } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs b/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs index aa0368cc2dd..cfeb8751f25 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs @@ -14,7 +14,7 @@ use crate::ssa::{ ir::{ basic_block::BasicBlockId, function::{Function, FunctionId, Signature}, - instruction::{BinaryOp, ConstrainError, Instruction, UserDefinedConstrainError}, + instruction::{BinaryOp, Instruction}, types::{NumericType, Type}, value::{Value, ValueId}, }, @@ -90,18 +90,6 @@ impl DefunctionalizationContext { Instruction::Call { func: target_func_id, arguments } => { (*target_func_id, arguments) } - // Constrain instruction potentially hold a call instruction themselves - // thus we need to account for them. - Instruction::Constrain(_, _, Some(constrain_error)) => { - if let ConstrainError::UserDefined(UserDefinedConstrainError::Dynamic( - Instruction::Call { func: target_func_id, arguments }, - )) = constrain_error.as_ref() - { - (*target_func_id, arguments) - } else { - continue; - } - } _ => continue, }; @@ -133,22 +121,7 @@ impl DefunctionalizationContext { } _ => {} } - if let Some(mut new_instruction) = replacement_instruction { - if let Instruction::Constrain(lhs, rhs, constrain_error_call) = instruction { - let new_error_call = if let Some(error) = constrain_error_call { - match error.as_ref() { - ConstrainError::UserDefined( - UserDefinedConstrainError::Dynamic(_), - ) => Some(Box::new(ConstrainError::UserDefined( - UserDefinedConstrainError::Dynamic(new_instruction), - ))), - _ => None, - } - } else { - None - }; - new_instruction = Instruction::Constrain(lhs, rhs, new_error_call); - } + if let Some(new_instruction) = replacement_instruction { func.dfg[instruction_id] = new_instruction; } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/die.rs b/compiler/noirc_evaluator/src/ssa/opt/die.rs index d1b3e1e83f5..d045762f9e9 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/die.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/die.rs @@ -108,12 +108,12 @@ impl Context { fn is_unused(&self, instruction_id: InstructionId, function: &Function) -> bool { let instruction = &function.dfg[instruction_id]; - if instruction.has_side_effects(&function.dfg) { - // If the instruction has side effects we should never remove it. - false - } else { + if instruction.can_eliminate_if_unused(&function.dfg) { let results = function.dfg.instruction_results(instruction_id); results.iter().all(|result| !self.used_values.contains(result)) + } else { + // If the instruction has side effects we should never remove it. + false } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 07771397ce8..0f8b49b40ec 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -155,9 +155,6 @@ mod branch_analysis; mod capacity_tracker; pub(crate) mod value_merger; -use capacity_tracker::SliceCapacityTracker; -use value_merger::ValueMerger; - impl Ssa { /// Flattens the control flow graph of main such that the function is left with a /// single block containing all instructions and no more control-flow. @@ -311,18 +308,6 @@ impl<'f> Context<'f> { if self.inserter.function.entry_block() == block { // we do not inline the entry block into itself // for the outer block before we start inlining - let outer_block_instructions = self.inserter.function.dfg[block].instructions(); - let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); - for instruction in outer_block_instructions { - let results = self.inserter.function.dfg.instruction_results(*instruction); - let instruction = &self.inserter.function.dfg[*instruction]; - capacity_tracker.collect_slice_information( - instruction, - &mut self.slice_sizes, - results.to_vec(), - ); - } - return; } @@ -333,14 +318,7 @@ impl<'f> Context<'f> { // unnecessary, when removing it actually causes an aliasing/mutability error. let instructions = self.inserter.function.dfg[block].instructions().to_vec(); for instruction in instructions.iter() { - let results = self.push_instruction(*instruction); - let (instruction, _) = self.inserter.map_instruction(*instruction); - let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); - capacity_tracker.collect_slice_information( - &instruction, - &mut self.slice_sizes, - results, - ); + self.push_instruction(*instruction); } } @@ -543,24 +521,19 @@ impl<'f> Context<'f> { let block = self.inserter.function.entry_block(); - // Make sure we have tracked the slice capacities of any block arguments - let capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); - for (then_arg, else_arg) in args.iter() { - capacity_tracker.compute_slice_capacity(*then_arg, &mut self.slice_sizes); - capacity_tracker.compute_slice_capacity(*else_arg, &mut self.slice_sizes); - } - - let mut value_merger = - ValueMerger::new(&mut self.inserter.function.dfg, block, &mut self.slice_sizes); - // Cannot include this in the previous vecmap since it requires exclusive access to self let args = vecmap(args, |(then_arg, else_arg)| { - value_merger.merge_values( - cond_context.then_branch.condition, - cond_context.else_branch.clone().unwrap().condition, - then_arg, - else_arg, - ) + let instruction = Instruction::IfElse { + then_condition: cond_context.then_branch.condition, + then_value: then_arg, + else_condition: cond_context.else_branch.as_ref().unwrap().condition, + else_value: else_arg, + }; + self.inserter + .function + .dfg + .insert_instruction_and_results(instruction, block, None, CallStack::new()) + .first() }); self.merge_stores(cond_context.then_branch, cond_context.else_branch); @@ -643,15 +616,6 @@ impl<'f> Context<'f> { } } - // Most slice information is collected when instructions are inlined. - // We need to collect information on slice values here as we may possibly merge stores - // before any inlining occurs. - let capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); - for (then_case, else_case, _) in new_map.values() { - capacity_tracker.compute_slice_capacity(*then_case, &mut self.slice_sizes); - capacity_tracker.compute_slice_capacity(*else_case, &mut self.slice_sizes); - } - let then_condition = then_branch.condition; let else_condition = if let Some(branch) = else_branch { branch.condition @@ -660,13 +624,22 @@ impl<'f> Context<'f> { }; let block = self.inserter.function.entry_block(); - let mut value_merger = - ValueMerger::new(&mut self.inserter.function.dfg, block, &mut self.slice_sizes); // Merging must occur in a separate loop as we cannot borrow `self` as mutable while `value_merger` does let mut new_values = HashMap::default(); for (address, (then_case, else_case, _)) in &new_map { - let value = - value_merger.merge_values(then_condition, else_condition, *then_case, *else_case); + let instruction = Instruction::IfElse { + then_condition, + then_value: *then_case, + else_condition, + else_value: *else_case, + }; + let value = self + .inserter + .function + .dfg + .insert_instruction_and_results(instruction, block, None, CallStack::new()) + .first(); + new_values.insert(address, value); } @@ -683,16 +656,6 @@ impl<'f> Context<'f> { .insert(address, Store { old_value: *old_value, new_value: value }); } } - - // Collect any potential slice information on the stores we are merging - for (address, (_, _, _)) in &new_map { - let value = new_values[address]; - let address = *address; - let instruction = Instruction::Store { address, value }; - - let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); - capacity_tracker.collect_slice_information(&instruction, &mut self.slice_sizes, vec![]); - } } fn remember_store(&mut self, address: ValueId, new_value: ValueId) { @@ -706,14 +669,6 @@ impl<'f> Context<'f> { let old_value = self.insert_instruction_with_typevars(load.clone(), load_type).first(); - // Need this or else we will be missing a the previous value of a slice that we wish to merge - let mut capacity_tracker = SliceCapacityTracker::new(&self.inserter.function.dfg); - capacity_tracker.collect_slice_information( - &load, - &mut self.slice_sizes, - vec![old_value], - ); - self.store_values.insert(address, Store { old_value, new_value }); } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs index 93e52542278..4fc19acd2ac 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -19,10 +19,10 @@ impl<'a> SliceCapacityTracker<'a> { /// Determine how the slice sizes map needs to be updated according to the provided instruction. pub(crate) fn collect_slice_information( - &mut self, + &self, instruction: &Instruction, slice_sizes: &mut HashMap, - results: Vec, + results: &[ValueId], ) { match instruction { Instruction::ArrayGet { array, .. } => { diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs index 0a351148fa3..80f6529b7b3 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs @@ -1,20 +1,25 @@ use acvm::FieldElement; -use fxhash::FxHashMap as HashMap; +use fxhash::{FxHashMap as HashMap, FxHashSet}; use crate::ssa::ir::{ basic_block::BasicBlockId, - dfg::{CallStack, DataFlowGraph}, + dfg::{CallStack, DataFlowGraph, InsertInstructionResult}, instruction::{BinaryOp, Instruction}, types::Type, - value::ValueId, + value::{Value, ValueId}, }; pub(crate) struct ValueMerger<'a> { dfg: &'a mut DataFlowGraph, block: BasicBlockId, + + current_condition: Option, + // Maps SSA array values with a slice type to their size. // This must be computed before merging values. slice_sizes: &'a mut HashMap, + + array_set_conditionals: &'a mut HashMap, } impl<'a> ValueMerger<'a> { @@ -22,8 +27,10 @@ impl<'a> ValueMerger<'a> { dfg: &'a mut DataFlowGraph, block: BasicBlockId, slice_sizes: &'a mut HashMap, + array_set_conditionals: &'a mut HashMap, + current_condition: Option, ) -> Self { - ValueMerger { dfg, block, slice_sizes } + ValueMerger { dfg, block, slice_sizes, array_set_conditionals, current_condition } } /// Merge two values a and b from separate basic blocks to a single value. @@ -42,9 +49,14 @@ impl<'a> ValueMerger<'a> { else_value: ValueId, ) -> ValueId { match self.dfg.type_of_value(then_value) { - Type::Numeric(_) => { - self.merge_numeric_values(then_condition, else_condition, then_value, else_value) - } + Type::Numeric(_) => Self::merge_numeric_values( + self.dfg, + self.block, + then_condition, + else_condition, + then_value, + else_value, + ), typ @ Type::Array(_, _) => { self.merge_array_values(typ, then_condition, else_condition, then_value, else_value) } @@ -59,58 +71,57 @@ impl<'a> ValueMerger<'a> { /// Merge two numeric values a and b from separate basic blocks to a single value. This /// function would return the result of `if c { a } else { b }` as `c*a + (!c)*b`. pub(crate) fn merge_numeric_values( - &mut self, + dfg: &mut DataFlowGraph, + block: BasicBlockId, then_condition: ValueId, else_condition: ValueId, then_value: ValueId, else_value: ValueId, ) -> ValueId { - let then_type = self.dfg.type_of_value(then_value); - let else_type = self.dfg.type_of_value(else_value); + let then_type = dfg.type_of_value(then_value); + let else_type = dfg.type_of_value(else_value); assert_eq!( then_type, else_type, "Expected values merged to be of the same type but found {then_type} and {else_type}" ); - let then_call_stack = self.dfg.get_value_call_stack(then_value); - let else_call_stack = self.dfg.get_value_call_stack(else_value); + if then_value == else_value { + return then_value; + } + + let then_call_stack = dfg.get_value_call_stack(then_value); + let else_call_stack = dfg.get_value_call_stack(else_value); let call_stack = if then_call_stack.is_empty() { else_call_stack } else { then_call_stack }; // We must cast the bool conditions to the actual numeric type used by each value. - let then_condition = self - .dfg + let then_condition = dfg .insert_instruction_and_results( Instruction::Cast(then_condition, then_type), - self.block, + block, None, call_stack.clone(), ) .first(); - let else_condition = self - .dfg + let else_condition = dfg .insert_instruction_and_results( Instruction::Cast(else_condition, else_type), - self.block, + block, None, call_stack.clone(), ) .first(); let mul = Instruction::binary(BinaryOp::Mul, then_condition, then_value); - let then_value = self - .dfg - .insert_instruction_and_results(mul, self.block, None, call_stack.clone()) - .first(); + let then_value = + dfg.insert_instruction_and_results(mul, block, None, call_stack.clone()).first(); let mul = Instruction::binary(BinaryOp::Mul, else_condition, else_value); - let else_value = self - .dfg - .insert_instruction_and_results(mul, self.block, None, call_stack.clone()) - .first(); + let else_value = + dfg.insert_instruction_and_results(mul, block, None, call_stack.clone()).first(); let add = Instruction::binary(BinaryOp::Add, then_value, else_value); - self.dfg.insert_instruction_and_results(add, self.block, None, call_stack).first() + dfg.insert_instruction_and_results(add, block, None, call_stack).first() } /// Given an if expression that returns an array: `if c { array1 } else { array2 }`, @@ -131,6 +142,18 @@ impl<'a> ValueMerger<'a> { _ => panic!("Expected array type"), }; + let actual_length = len * element_types.len(); + + if let Some(result) = self.try_merge_only_changed_indices( + then_condition, + else_condition, + then_value, + else_value, + actual_length, + ) { + return result; + } + for i in 0..len { for (element_index, element_type) in element_types.iter().enumerate() { let index = ((i * element_types.len() + element_index) as u128).into(); @@ -175,12 +198,18 @@ impl<'a> ValueMerger<'a> { _ => panic!("Expected slice type"), }; - let then_len = *self.slice_sizes.get(&then_value_id).unwrap_or_else(|| { - panic!("ICE: Merging values during flattening encountered slice {then_value_id} without a preset size"); + let then_len = self.slice_sizes.get(&then_value_id).copied().unwrap_or_else(|| { + let (slice, typ) = self.dfg.get_array_constant(then_value_id).unwrap_or_else(|| { + panic!("ICE: Merging values during flattening encountered slice {then_value_id} without a preset size"); + }); + slice.len() / typ.element_types().len() }); - let else_len = *self.slice_sizes.get(&else_value_id).unwrap_or_else(|| { - panic!("ICE: Merging values during flattening encountered slice {else_value_id} without a preset size"); + let else_len = self.slice_sizes.get(&else_value_id).copied().unwrap_or_else(|| { + let (slice, typ) = self.dfg.get_array_constant(else_value_id).unwrap_or_else(|| { + panic!("ICE: Merging values during flattening encountered slice {else_value_id} without a preset size"); + }); + slice.len() / typ.element_types().len() }); let len = then_len.max(else_len); @@ -260,4 +289,157 @@ impl<'a> ValueMerger<'a> { } } } + + fn try_merge_only_changed_indices( + &mut self, + then_condition: ValueId, + else_condition: ValueId, + then_value: ValueId, + else_value: ValueId, + array_length: usize, + ) -> Option { + let mut found = false; + let current_condition = self.current_condition?; + + let mut current_then = then_value; + let mut current_else = else_value; + + // Arbitrarily limit this to looking at at most 10 past ArraySet operations. + // If there are more than that, we assume 2 completely separate arrays are being merged. + let max_iters = 2; + let mut seen_then = Vec::with_capacity(max_iters); + let mut seen_else = Vec::with_capacity(max_iters); + + // We essentially have a tree of ArraySets and want to find a common + // ancestor if it exists, alone with the path to it from each starting node. + // This path will be the indices that were changed to create each result array. + for _ in 0..max_iters { + if current_then == else_value { + seen_else.clear(); + found = true; + break; + } + + if current_else == then_value { + seen_then.clear(); + found = true; + break; + } + + if let Some(index) = seen_then.iter().position(|(elem, _, _, _)| *elem == current_else) + { + seen_else.truncate(index); + found = true; + break; + } + + if let Some(index) = seen_else.iter().position(|(elem, _, _, _)| *elem == current_then) + { + seen_then.truncate(index); + found = true; + break; + } + + current_then = self.find_previous_array_set(current_then, &mut seen_then); + current_else = self.find_previous_array_set(current_else, &mut seen_else); + } + + let changed_indices: FxHashSet<_> = seen_then + .into_iter() + .map(|(_, index, typ, condition)| (index, typ, condition)) + .chain(seen_else.into_iter().map(|(_, index, typ, condition)| (index, typ, condition))) + .collect(); + + if !found || changed_indices.len() >= array_length { + return None; + } + + let mut array = then_value; + + for (index, element_type, condition) in changed_indices { + let typevars = Some(vec![element_type.clone()]); + + let instruction = Instruction::EnableSideEffects { condition }; + self.insert_instruction(instruction); + + let mut get_element = |array, typevars| { + let get = Instruction::ArrayGet { array, index }; + self.dfg + .insert_instruction_and_results(get, self.block, typevars, CallStack::new()) + .first() + }; + + let then_element = get_element(then_value, typevars.clone()); + let else_element = get_element(else_value, typevars); + + let value = + self.merge_values(then_condition, else_condition, then_element, else_element); + + array = self.insert_array_set(array, index, value, Some(condition)).first(); + } + + let instruction = Instruction::EnableSideEffects { condition: current_condition }; + self.insert_instruction(instruction); + Some(array) + } + + fn insert_instruction(&mut self, instruction: Instruction) -> InsertInstructionResult { + self.dfg.insert_instruction_and_results(instruction, self.block, None, CallStack::new()) + } + + fn insert_array_set( + &mut self, + array: ValueId, + index: ValueId, + value: ValueId, + condition: Option, + ) -> InsertInstructionResult { + let instruction = Instruction::ArraySet { array, index, value, mutable: false }; + let result = self.dfg.insert_instruction_and_results( + instruction, + self.block, + None, + CallStack::new(), + ); + + if let Some(condition) = condition { + let result_index = if result.len() == 1 { + 0 + } else { + // Slices return (length, slice) + assert_eq!(result.len(), 2); + 1 + }; + + let result_value = result[result_index]; + self.array_set_conditionals.insert(result_value, condition); + } + + result + } + + fn find_previous_array_set( + &self, + result: ValueId, + changed_indices: &mut Vec<(ValueId, ValueId, Type, ValueId)>, + ) -> ValueId { + match &self.dfg[result] { + Value::Instruction { instruction, .. } => match &self.dfg[*instruction] { + Instruction::ArraySet { array, index, value, .. } => { + let condition = + *self.array_set_conditionals.get(&result).unwrap_or_else(|| { + panic!( + "Expected to have conditional for array set {result}\n{:?}", + self.array_set_conditionals + ) + }); + let element_type = self.dfg.type_of_value(*value); + changed_indices.push((result, *index, element_type, condition)); + *array + } + _ => result, + }, + _ => result, + } + } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index ead3cac071c..bddfb25f26c 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -36,13 +36,30 @@ impl Ssa { /// changes. This is because if the function's id later becomes known by a later /// pass, we would need to re-run all of inlining anyway to inline it, so we might /// as well save the work for later instead of performing it twice. + /// + /// There are some attributes that allow inlining a function at a different step of codegen. + /// Currently this is just `InlineType::NoPredicates` for which we have a flag indicating + /// whether treating that inline functions. The default is to treat these functions as entry points. #[tracing::instrument(level = "trace", skip(self))] - pub(crate) fn inline_functions(mut self) -> Ssa { - self.functions = btree_map(get_entry_point_functions(&self), |entry_point| { - let new_function = InlineContext::new(&self, entry_point).inline_all(&self); - (entry_point, new_function) - }); + pub(crate) fn inline_functions(self) -> Ssa { + Self::inline_functions_inner(self, true) + } + + // Run the inlining pass where functions marked with `InlineType::NoPredicates` as not entry points + pub(crate) fn inline_functions_with_no_predicates(self) -> Ssa { + Self::inline_functions_inner(self, false) + } + fn inline_functions_inner(mut self, no_predicates_is_entry_point: bool) -> Ssa { + self.functions = btree_map( + get_entry_point_functions(&self, no_predicates_is_entry_point), + |entry_point| { + let new_function = + InlineContext::new(&self, entry_point, no_predicates_is_entry_point) + .inline_all(&self); + (entry_point, new_function) + }, + ); self } } @@ -60,6 +77,8 @@ struct InlineContext { // The FunctionId of the entry point function we're inlining into in the old, unmodified Ssa. entry_point: FunctionId, + + no_predicates_is_entry_point: bool, } /// The per-function inlining context contains information that is only valid for one function. @@ -97,10 +116,19 @@ struct PerFunctionContext<'function> { /// should be left in the final program. /// This is the `main` function, any Acir functions with a [fold inline type][InlineType::Fold], /// and any brillig functions used. -fn get_entry_point_functions(ssa: &Ssa) -> BTreeSet { +fn get_entry_point_functions( + ssa: &Ssa, + no_predicates_is_entry_point: bool, +) -> BTreeSet { let functions = ssa.functions.iter(); let mut entry_points = functions - .filter(|(_, function)| function.runtime().is_entry_point()) + .filter(|(_, function)| { + // If we have not already finished the flattening pass, functions marked + // to not have predicates should be marked as entry points. + let no_predicates_is_entry_point = + no_predicates_is_entry_point && function.is_no_predicates(); + function.runtime().is_entry_point() || no_predicates_is_entry_point + }) .map(|(id, _)| *id) .collect::>(); @@ -114,11 +142,21 @@ impl InlineContext { /// The function being inlined into will always be the main function, although it is /// actually a copy that is created in case the original main is still needed from a function /// that could not be inlined calling it. - fn new(ssa: &Ssa, entry_point: FunctionId) -> InlineContext { + fn new( + ssa: &Ssa, + entry_point: FunctionId, + no_predicates_is_entry_point: bool, + ) -> InlineContext { let source = &ssa.functions[&entry_point]; let mut builder = FunctionBuilder::new(source.name().to_owned(), entry_point); builder.set_runtime(source.runtime()); - Self { builder, recursion_level: 0, entry_point, call_stack: CallStack::new() } + Self { + builder, + recursion_level: 0, + entry_point, + call_stack: CallStack::new(), + no_predicates_is_entry_point, + } } /// Start inlining the entry point function and all functions reachable from it. @@ -351,11 +389,17 @@ impl<'function> PerFunctionContext<'function> { for id in block.instructions() { match &self.source_function.dfg[*id] { Instruction::Call { func, arguments } => match self.get_function(*func) { - Some(function) => { - if ssa.functions[&function].runtime().is_entry_point() { + Some(func_id) => { + let function = &ssa.functions[&func_id]; + // If we have not already finished the flattening pass, functions marked + // to not have predicates should be marked as entry points. + let no_predicates_is_entry_point = + self.context.no_predicates_is_entry_point + && function.is_no_predicates(); + if function.runtime().is_entry_point() || no_predicates_is_entry_point { self.push_instruction(*id); } else { - self.inline_function(ssa, *id, function, arguments); + self.inline_function(ssa, *id, func_id, arguments); } } None => self.push_instruction(*id), @@ -517,12 +561,12 @@ impl<'function> PerFunctionContext<'function> { #[cfg(test)] mod test { use acvm::FieldElement; + use noirc_frontend::monomorphization::ast::InlineType; use crate::ssa::{ function_builder::FunctionBuilder, ir::{ basic_block::BasicBlockId, - function::InlineType, instruction::{BinaryOp, Intrinsic, TerminatorInstruction}, map::Id, types::Type, diff --git a/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/compiler/noirc_evaluator/src/ssa/opt/mod.rs index 4452840a28c..27536d59ea5 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/mod.rs @@ -16,5 +16,6 @@ mod mem2reg; mod rc; mod remove_bit_shifts; mod remove_enable_side_effects; +mod remove_if_else; mod simplify_cfg; mod unrolling; diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs index 1eb1e20d41d..42727054503 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs @@ -97,7 +97,7 @@ impl Context<'_> { let typ = self.function.dfg.type_of_value(lhs); let (max_bit, pow) = if let Some(rhs_constant) = self.function.dfg.get_numeric_constant(rhs) { - // Happy case is that we know precisely by how many bits the the integer will + // Happy case is that we know precisely by how many bits the integer will // increase: lhs_bit_size + rhs let bit_shift_size = rhs_constant.to_u128() as u32; @@ -117,7 +117,7 @@ impl Context<'_> { } else { // we use a predicate to nullify the result in case of overflow let bit_size_var = - self.numeric_constant(FieldElement::from(bit_size as u128), typ.clone()); + self.numeric_constant(FieldElement::from(bit_size as u128), Type::unsigned(8)); let overflow = self.insert_binary(rhs, BinaryOp::Lt, bit_size_var); let predicate = self.insert_cast(overflow, typ.clone()); // we can safely cast to unsigned because overflow_checks prevent bit-shift with a negative value diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs index 8535dc2661f..02b9202b209 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs @@ -125,6 +125,7 @@ impl Context { | Truncate { .. } | Constrain(..) | RangeCheck { .. } + | IfElse { .. } | IncrementRc { .. } | DecrementRc { .. } => false, diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs new file mode 100644 index 00000000000..fc915756110 --- /dev/null +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs @@ -0,0 +1,236 @@ +use std::collections::hash_map::Entry; + +use acvm::FieldElement; +use fxhash::FxHashMap as HashMap; + +use crate::ssa::ir::value::ValueId; +use crate::ssa::{ + ir::{ + dfg::DataFlowGraph, + function::Function, + instruction::{Instruction, Intrinsic}, + types::Type, + value::Value, + }, + opt::flatten_cfg::value_merger::ValueMerger, + Ssa, +}; + +impl Ssa { + /// This pass removes `inc_rc` and `dec_rc` instructions + /// as long as there are no `array_set` instructions to an array + /// of the same type in between. + /// + /// Note that this pass is very conservative since the array_set + /// instruction does not need to be to the same array. This is because + /// the given array may alias another array (e.g. function parameters or + /// a `load`ed array from a reference). + #[tracing::instrument(level = "trace", skip(self))] + pub(crate) fn remove_if_else(mut self) -> Ssa { + for function in self.functions.values_mut() { + // This should match the check in flatten_cfg + if let crate::ssa::ir::function::RuntimeType::Brillig = function.runtime() { + continue; + } + + Context::default().remove_if_else(function); + } + self + } +} + +#[derive(Default)] +struct Context { + slice_sizes: HashMap, + + // Maps array_set result -> element that was overwritten by that instruction. + // Used to undo array_sets while merging values + prev_array_set_elem_values: HashMap, + + // Maps array_set result -> enable_side_effects_if value which was active during it. + array_set_conditionals: HashMap, +} + +impl Context { + fn remove_if_else(&mut self, function: &mut Function) { + let block = function.entry_block(); + let instructions = function.dfg[block].take_instructions(); + let mut current_conditional = function.dfg.make_constant(FieldElement::one(), Type::bool()); + + for instruction in instructions { + match &function.dfg[instruction] { + Instruction::IfElse { then_condition, then_value, else_condition, else_value } => { + let then_condition = *then_condition; + let then_value = *then_value; + let else_condition = *else_condition; + let else_value = *else_value; + + let typ = function.dfg.type_of_value(then_value); + assert!(!matches!(typ, Type::Numeric(_))); + + let mut value_merger = ValueMerger::new( + &mut function.dfg, + block, + &mut self.slice_sizes, + &mut self.array_set_conditionals, + Some(current_conditional), + ); + + let value = value_merger.merge_values( + then_condition, + else_condition, + then_value, + else_value, + ); + + let _typ = function.dfg.type_of_value(value); + let results = function.dfg.instruction_results(instruction); + let result = results[0]; + // let result = match typ { + // Type::Array(..) => results[0], + // Type::Slice(..) => results[1], + // other => unreachable!("IfElse instructions should only have arrays or slices at this point. Found {other:?}"), + // }; + + function.dfg.set_value_from_id(result, value); + self.array_set_conditionals.insert(result, current_conditional); + } + Instruction::Call { func, arguments } => { + if let Value::Intrinsic(intrinsic) = function.dfg[*func] { + let results = function.dfg.instruction_results(instruction); + + match slice_capacity_change(&function.dfg, intrinsic, arguments, results) { + SizeChange::None => (), + SizeChange::SetTo(value, new_capacity) => { + self.slice_sizes.insert(value, new_capacity); + } + SizeChange::Inc { old, new } => { + let old_capacity = self.get_or_find_capacity(&function.dfg, old); + self.slice_sizes.insert(new, old_capacity + 1); + } + SizeChange::Dec { old, new } => { + let old_capacity = self.get_or_find_capacity(&function.dfg, old); + self.slice_sizes.insert(new, old_capacity - 1); + } + } + } + function.dfg[block].instructions_mut().push(instruction); + } + Instruction::ArraySet { array, .. } => { + let results = function.dfg.instruction_results(instruction); + let result = if results.len() == 2 { results[1] } else { results[0] }; + + self.array_set_conditionals.insert(result, current_conditional); + + let old_capacity = self.get_or_find_capacity(&function.dfg, *array); + self.slice_sizes.insert(result, old_capacity); + function.dfg[block].instructions_mut().push(instruction); + } + Instruction::EnableSideEffects { condition } => { + current_conditional = *condition; + function.dfg[block].instructions_mut().push(instruction); + } + _ => { + function.dfg[block].instructions_mut().push(instruction); + } + } + } + } + + fn get_or_find_capacity(&mut self, dfg: &DataFlowGraph, value: ValueId) -> usize { + match self.slice_sizes.entry(value) { + Entry::Occupied(entry) => return *entry.get(), + Entry::Vacant(entry) => { + if let Some((array, typ)) = dfg.get_array_constant(value) { + let length = array.len() / typ.element_types().len(); + return *entry.insert(length); + } + + if let Type::Array(_, length) = dfg.type_of_value(value) { + return *entry.insert(length); + } + } + } + + let dbg_value = &dfg[value]; + unreachable!("No size for slice {value} = {dbg_value:?}") + } +} + +enum SizeChange { + None, + SetTo(ValueId, usize), + + // These two variants store the old and new slice ids + // not their lengths which should be old_len = new_len +/- 1 + Inc { old: ValueId, new: ValueId }, + Dec { old: ValueId, new: ValueId }, +} + +/// Find the change to a slice's capacity an instruction would have +fn slice_capacity_change( + dfg: &DataFlowGraph, + intrinsic: Intrinsic, + arguments: &[ValueId], + results: &[ValueId], +) -> SizeChange { + match intrinsic { + Intrinsic::SlicePushBack | Intrinsic::SlicePushFront | Intrinsic::SliceInsert => { + // Expecting: len, slice = ... + assert_eq!(results.len(), 2); + let old = arguments[1]; + let new = results[1]; + assert!(matches!(dfg.type_of_value(old), Type::Slice(_))); + assert!(matches!(dfg.type_of_value(new), Type::Slice(_))); + SizeChange::Inc { old, new } + } + + Intrinsic::SlicePopBack | Intrinsic::SliceRemove => { + let old = arguments[1]; + let new = results[1]; + assert!(matches!(dfg.type_of_value(old), Type::Slice(_))); + assert!(matches!(dfg.type_of_value(new), Type::Slice(_))); + SizeChange::Dec { old, new } + } + + Intrinsic::SlicePopFront => { + let old = arguments[1]; + let new = results[results.len() - 1]; + assert!(matches!(dfg.type_of_value(old), Type::Slice(_))); + assert!(matches!(dfg.type_of_value(new), Type::Slice(_))); + SizeChange::Dec { old, new } + } + + Intrinsic::ToBits(_) => { + assert_eq!(results.len(), 2); + // Some tests fail this check, returning an array instead somehow: + // assert!(matches!(dfg.type_of_value(results[1]), Type::Slice(_))); + SizeChange::SetTo(results[1], FieldElement::max_num_bits() as usize) + } + // ToRadix seems to assume it is to bytes + Intrinsic::ToRadix(_) => { + assert_eq!(results.len(), 2); + assert!(matches!(dfg.type_of_value(results[1]), Type::Slice(_))); + SizeChange::SetTo(results[1], FieldElement::max_num_bytes() as usize) + } + Intrinsic::AsSlice => { + assert_eq!(arguments.len(), 1); + assert_eq!(results.len(), 2); + let length = match dfg.type_of_value(arguments[0]) { + Type::Array(_, length) => length, + other => unreachable!("slice_capacity_change expected array, found {other:?}"), + }; + assert!(matches!(dfg.type_of_value(results[1]), Type::Slice(_))); + SizeChange::SetTo(results[1], length) + } + + // These cases don't affect slice capacities + Intrinsic::AssertConstant + | Intrinsic::ApplyRangeConstraint + | Intrinsic::ArrayLen + | Intrinsic::StrAsBytes + | Intrinsic::BlackBox(_) + | Intrinsic::FromField + | Intrinsic::AsField => SizeChange::None, + } +} diff --git a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs index 6cf155f85ab..cfb5cfac326 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -12,6 +12,8 @@ //! //! Note that this pass also often creates superfluous jmp instructions in the //! program that will need to be removed by a later simplify cfg pass. +//! Note also that unrolling is skipped for Brillig runtime and as a result +//! we remove reference count instructions because they are only used by Brillig bytecode use std::collections::HashSet; use crate::{ @@ -24,7 +26,7 @@ use crate::{ dom::DominatorTree, function::{Function, RuntimeType}, function_inserter::FunctionInserter, - instruction::TerminatorInstruction, + instruction::{Instruction, TerminatorInstruction}, post_order::PostOrder, value::ValueId, }, @@ -465,9 +467,14 @@ impl<'f> LoopIteration<'f> { // instances of the induction variable or any values that were changed as a result // of the new induction variable value. for instruction in instructions { - self.inserter.push_instruction(instruction, self.insert_block); + // Skip reference count instructions since they are only used for brillig, and brillig code is not unrolled + if !matches!( + self.dfg()[instruction], + Instruction::IncrementRc { .. } | Instruction::DecrementRc { .. } + ) { + self.inserter.push_instruction(instruction, self.insert_block); + } } - let mut terminator = self.dfg()[self.source_block] .unwrap_terminator() .clone() diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index e591a3d478c..f7ecdc8870d 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -11,9 +11,8 @@ use noirc_frontend::monomorphization::ast::{FuncId, Program}; use crate::errors::RuntimeError; use crate::ssa::function_builder::FunctionBuilder; use crate::ssa::ir::basic_block::BasicBlockId; -use crate::ssa::ir::dfg::DataFlowGraph; +use crate::ssa::ir::function::FunctionId as IrFunctionId; use crate::ssa::ir::function::{Function, RuntimeType}; -use crate::ssa::ir::function::{FunctionId as IrFunctionId, InlineType}; use crate::ssa::ir::instruction::BinaryOp; use crate::ssa::ir::instruction::Instruction; use crate::ssa::ir::map::AtomicCounter; @@ -126,8 +125,7 @@ impl<'a> FunctionContext<'a> { if func.unconstrained { self.builder.new_brillig_function(func.name.clone(), id); } else { - let inline_type = if func.should_fold { InlineType::Fold } else { InlineType::Inline }; - self.builder.new_function(func.name.clone(), id, inline_type); + self.builder.new_function(func.name.clone(), id, func.inline_type); } self.add_parameters_to_scope(&func.parameters); } @@ -346,7 +344,7 @@ impl<'a> FunctionContext<'a> { self.insert_safe_cast(result, result_type, location) } BinaryOpKind::ShiftLeft | BinaryOpKind::ShiftRight => { - self.check_shift_overflow(result, rhs, bit_size, location, true) + self.check_shift_overflow(result, rhs, bit_size, location) } _ => unreachable!("operator {} should not overflow", operator), } @@ -410,7 +408,7 @@ impl<'a> FunctionContext<'a> { } } - self.check_shift_overflow(result, rhs, bit_size, location, false); + self.check_shift_overflow(result, rhs, bit_size, location); } _ => unreachable!("operator {} should not overflow", operator), @@ -432,32 +430,12 @@ impl<'a> FunctionContext<'a> { rhs: ValueId, bit_size: u32, location: Location, - is_signed: bool, ) -> ValueId { let one = self.builder.numeric_constant(FieldElement::one(), Type::bool()); - let rhs = if is_signed { - self.insert_safe_cast(rhs, Type::unsigned(bit_size), location) - } else { - rhs - }; - // Bit-shift with a negative number is an overflow - if is_signed { - // We compute the sign of rhs. - let half_width = self.builder.numeric_constant( - FieldElement::from(2_i128.pow(bit_size - 1)), - Type::unsigned(bit_size), - ); - let sign = self.builder.insert_binary(rhs, BinaryOp::Lt, half_width); - self.builder.set_location(location).insert_constrain( - sign, - one, - Some("attempt to bit-shift with overflow".to_owned().into()), - ); - } + assert!(self.builder.current_function.dfg.type_of_value(rhs) == Type::unsigned(8)); - let max = self - .builder - .numeric_constant(FieldElement::from(bit_size as i128), Type::unsigned(bit_size)); + let max = + self.builder.numeric_constant(FieldElement::from(bit_size as i128), Type::unsigned(8)); let overflow = self.builder.insert_binary(rhs, BinaryOp::Lt, max); self.builder.set_location(location).insert_constrain( overflow, @@ -566,22 +544,12 @@ impl<'a> FunctionContext<'a> { mut rhs: ValueId, location: Location, ) -> Values { - let result_type = self.builder.type_of_value(lhs); - let mut result = match operator { - BinaryOpKind::Equal | BinaryOpKind::NotEqual - if matches!(result_type, Type::Array(..)) => - { - return self.insert_array_equality(lhs, operator, rhs, location) - } - _ => { - let op = convert_operator(operator); - if operator_requires_swapped_operands(operator) { - std::mem::swap(&mut lhs, &mut rhs); - } + let op = convert_operator(operator); + if operator_requires_swapped_operands(operator) { + std::mem::swap(&mut lhs, &mut rhs); + } - self.builder.set_location(location).insert_binary(lhs, op, rhs) - } - }; + let mut result = self.builder.set_location(location).insert_binary(lhs, op, rhs); // Check for integer overflow if matches!( @@ -600,94 +568,6 @@ impl<'a> FunctionContext<'a> { result.into() } - /// The frontend claims to support equality (==) on arrays, so we must support it in SSA here. - /// The actual BinaryOp::Eq in SSA is meant only for primitive numeric types so we encode an - /// entire equality loop on each array element. The generated IR is as follows: - /// - /// ... - /// result_alloc = allocate - /// store u1 1 in result_alloc - /// jmp loop_start(0) - /// loop_start(i: Field): - /// v0 = lt i, array_len - /// jmpif v0, then: loop_body, else: loop_end - /// loop_body(): - /// v1 = array_get lhs, index i - /// v2 = array_get rhs, index i - /// v3 = eq v1, v2 - /// v4 = load result_alloc - /// v5 = and v4, v3 - /// store v5 in result_alloc - /// v6 = add i, Field 1 - /// jmp loop_start(v6) - /// loop_end(): - /// result = load result_alloc - fn insert_array_equality( - &mut self, - lhs: ValueId, - operator: BinaryOpKind, - rhs: ValueId, - location: Location, - ) -> Values { - let lhs_type = self.builder.type_of_value(lhs); - let rhs_type = self.builder.type_of_value(rhs); - - let (array_length, element_type) = match (lhs_type, rhs_type) { - ( - Type::Array(lhs_composite_type, lhs_length), - Type::Array(rhs_composite_type, rhs_length), - ) => { - assert!( - lhs_composite_type.len() == 1 && rhs_composite_type.len() == 1, - "== is unimplemented for arrays of structs" - ); - assert_eq!(lhs_composite_type[0], rhs_composite_type[0]); - assert_eq!(lhs_length, rhs_length, "Expected two arrays of equal length"); - (lhs_length, lhs_composite_type[0].clone()) - } - _ => unreachable!("Expected two array values"), - }; - - let loop_start = self.builder.insert_block(); - let loop_body = self.builder.insert_block(); - let loop_end = self.builder.insert_block(); - - // pre-loop - let result_alloc = self.builder.set_location(location).insert_allocate(Type::bool()); - let true_value = self.builder.numeric_constant(1u128, Type::bool()); - self.builder.insert_store(result_alloc, true_value); - let zero = self.builder.length_constant(0u128); - self.builder.terminate_with_jmp(loop_start, vec![zero]); - - // loop_start - self.builder.switch_to_block(loop_start); - let i = self.builder.add_block_parameter(loop_start, Type::length_type()); - let array_length = self.builder.length_constant(array_length as u128); - let v0 = self.builder.insert_binary(i, BinaryOp::Lt, array_length); - self.builder.terminate_with_jmpif(v0, loop_body, loop_end); - - // loop body - self.builder.switch_to_block(loop_body); - let v1 = self.builder.insert_array_get(lhs, i, element_type.clone()); - let v2 = self.builder.insert_array_get(rhs, i, element_type); - let v3 = self.builder.insert_binary(v1, BinaryOp::Eq, v2); - let v4 = self.builder.insert_load(result_alloc, Type::bool()); - let v5 = self.builder.insert_binary(v4, BinaryOp::And, v3); - self.builder.insert_store(result_alloc, v5); - let one = self.builder.length_constant(1u128); - let v6 = self.builder.insert_binary(i, BinaryOp::Add, one); - self.builder.terminate_with_jmp(loop_start, vec![v6]); - - // loop end - self.builder.switch_to_block(loop_end); - let mut result = self.builder.insert_load(result_alloc, Type::bool()); - - if operator_requires_not(operator) { - result = self.builder.insert_not(result); - } - result.into() - } - /// Inserts a call instruction at the end of the current block and returns the results /// of the call. /// @@ -1103,72 +983,6 @@ fn operator_requires_swapped_operands(op: BinaryOpKind) -> bool { matches!(op, Greater | LessEqual) } -/// If the operation requires its result to be truncated because it is an integer, the maximum -/// number of bits that result may occupy is returned. -fn operator_result_max_bit_size_to_truncate( - op: BinaryOpKind, - lhs: ValueId, - rhs: ValueId, - dfg: &DataFlowGraph, -) -> Option { - let lhs_type = dfg.type_of_value(lhs); - let rhs_type = dfg.type_of_value(rhs); - - let get_bit_size = |typ| match typ { - Type::Numeric(NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size }) => { - Some(bit_size) - } - _ => None, - }; - - let lhs_bit_size = get_bit_size(lhs_type)?; - let rhs_bit_size = get_bit_size(rhs_type)?; - use BinaryOpKind::*; - match op { - Add => Some(std::cmp::max(lhs_bit_size, rhs_bit_size) + 1), - Subtract => Some(std::cmp::max(lhs_bit_size, rhs_bit_size) + 1), - Multiply => { - if lhs_bit_size == 1 || rhs_bit_size == 1 { - // Truncation is unnecessary as multiplication by a boolean value cannot cause an overflow. - None - } else { - Some(lhs_bit_size + rhs_bit_size) - } - } - - ShiftLeft => { - if let Some(rhs_constant) = dfg.get_numeric_constant(rhs) { - // Happy case is that we know precisely by how many bits the the integer will - // increase: lhs_bit_size + rhs - return Some(lhs_bit_size + (rhs_constant.to_u128() as u32)); - } - // Unhappy case is that we don't yet know the rhs value, (even though it will - // eventually have to resolve to a constant). The best we can is assume the value of - // rhs to be the maximum value of it's numeric type. If that turns out to be larger - // than the native field's bit size, we full back to using that. - - // The formula for calculating the max bit size of a left shift is: - // lhs_bit_size + 2^{rhs_bit_size} - 1 - // Inferring the max bit size of left shift from its operands can result in huge - // number, that might not only be larger than the native field's max bit size, but - // furthermore might not be representable as a u32. Hence we use overflow checks and - // fallback to the native field's max bits. - let field_max_bits = FieldElement::max_num_bits(); - let (rhs_bit_size_pow_2, overflows) = 2_u32.overflowing_pow(rhs_bit_size); - if overflows { - return Some(field_max_bits); - } - let (max_bits_plus_1, overflows) = rhs_bit_size_pow_2.overflowing_add(lhs_bit_size); - if overflows { - return Some(field_max_bits); - } - let max_bit_size = std::cmp::min(max_bits_plus_1 - 1, field_max_bits); - Some(max_bit_size) - } - _ => None, - } -} - /// Converts the given operator to the appropriate BinaryOp. /// Take care when using this to insert a binary instruction: this requires /// checking operator_requires_not and operator_requires_swapped_operands diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index 79f7cda4ae2..698a2b0471a 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -8,14 +8,12 @@ use context::SharedContext; use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; use noirc_frontend::ast::{UnaryOp, Visibility}; +use noirc_frontend::hir_def::types::Type as HirType; use noirc_frontend::monomorphization::ast::{self, Expression, Program}; use crate::{ - errors::{InternalError, RuntimeError}, - ssa::{ - function_builder::data_bus::DataBusBuilder, - ir::{function::InlineType, instruction::Intrinsic}, - }, + errors::RuntimeError, + ssa::{function_builder::data_bus::DataBusBuilder, ir::instruction::Intrinsic}, }; use self::{ @@ -23,13 +21,12 @@ use self::{ value::{Tree, Values}, }; +use super::ir::instruction::error_selector_from_type; use super::{ function_builder::data_bus::DataBus, ir::{ function::RuntimeType, - instruction::{ - BinaryOp, ConstrainError, Instruction, TerminatorInstruction, UserDefinedConstrainError, - }, + instruction::{BinaryOp, ConstrainError, TerminatorInstruction}, types::Type, value::ValueId, }, @@ -61,9 +58,7 @@ pub(crate) fn generate_ssa( if force_brillig_runtime || main.unconstrained { RuntimeType::Brillig } else { - let main_inline_type = - if main.should_fold { InlineType::Fold } else { InlineType::Inline }; - RuntimeType::Acir(main_inline_type) + RuntimeType::Acir(main.inline_type) }, &context, ); @@ -151,8 +146,8 @@ impl<'a> FunctionContext<'a> { } Expression::Call(call) => self.codegen_call(call), Expression::Let(let_expr) => self.codegen_let(let_expr), - Expression::Constrain(expr, location, assert_message) => { - self.codegen_constrain(expr, *location, assert_message) + Expression::Constrain(expr, location, assert_payload) => { + self.codegen_constrain(expr, *location, assert_payload) } Expression::Assign(assign) => self.codegen_assign(assign), Expression::Semi(semi) => self.codegen_semi(semi), @@ -453,7 +448,7 @@ impl<'a> FunctionContext<'a> { self.builder.insert_constrain( is_offset_out_of_bounds, true_const, - Some(Box::new("Index out of bounds".to_owned().into())), + Some("Index out of bounds".to_owned().into()), ); } @@ -680,7 +675,7 @@ impl<'a> FunctionContext<'a> { &mut self, expr: &Expression, location: Location, - assert_message: &Option>, + assert_payload: &Option>, ) -> Result { let expr = self.codegen_non_tuple_expression(expr)?; let true_literal = self.builder.numeric_constant(true, Type::bool()); @@ -688,9 +683,9 @@ impl<'a> FunctionContext<'a> { // Set the location here for any errors that may occur when we codegen the assert message self.builder.set_location(location); - let assert_message = self.codegen_constrain_error(assert_message)?; + let assert_payload = self.codegen_constrain_error(assert_payload)?; - self.builder.insert_constrain(expr, true_literal, assert_message); + self.builder.insert_constrain(expr, true_literal, assert_payload); Ok(Self::unit_value()) } @@ -701,42 +696,22 @@ impl<'a> FunctionContext<'a> { // inserted to the SSA as we want that instruction to be atomic in SSA with a constrain instruction. fn codegen_constrain_error( &mut self, - assert_message: &Option>, - ) -> Result>, RuntimeError> { - let Some(assert_message_expr) = assert_message else { return Ok(None) }; - - if let ast::Expression::Literal(ast::Literal::Str(assert_message)) = - assert_message_expr.as_ref() - { - return Ok(Some(Box::new(ConstrainError::UserDefined( - UserDefinedConstrainError::Static(assert_message.to_string()), - )))); - } - - let ast::Expression::Call(call) = assert_message_expr.as_ref() else { - return Err(InternalError::Unexpected { - expected: "Expected a call expression".to_owned(), - found: "Instead found {expr:?}".to_owned(), - call_stack: self.builder.get_call_stack(), + assert_message: &Option>, + ) -> Result, RuntimeError> { + let Some(assert_message_payload) = assert_message else { return Ok(None) }; + let (assert_message_expression, assert_message_typ) = assert_message_payload.as_ref(); + + let values = self.codegen_expression(assert_message_expression)?.into_value_list(self); + + let error_type_id = error_selector_from_type(assert_message_typ); + // Do not record string errors in the ABI + match assert_message_typ { + HirType::String(_) => {} + _ => { + self.builder.record_error_type(error_type_id, assert_message_typ.clone()); } - .into()); }; - - let func = self.codegen_non_tuple_expression(&call.func)?; - let mut arguments = Vec::with_capacity(call.arguments.len()); - - for argument in &call.arguments { - let mut values = self.codegen_expression(argument)?.into_value_list(self); - arguments.append(&mut values); - } - - // If an array is passed as an argument we increase its reference count - for argument in &arguments { - self.builder.increment_array_reference_count(*argument); - } - - let instr = Instruction::Call { func, arguments }; - Ok(Some(Box::new(ConstrainError::UserDefined(UserDefinedConstrainError::Dynamic(instr))))) + Ok(Some(ConstrainError::UserDefined(error_type_id, values))) } fn codegen_assign(&mut self, assign: &ast::Assign) -> Result { diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs index b05a2cbc741..21178c55c73 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs @@ -1,11 +1,13 @@ use std::{collections::BTreeMap, fmt::Display}; +use acvm::acir::circuit::ErrorSelector; use iter_extended::btree_map; use crate::ssa::ir::{ function::{Function, FunctionId, RuntimeType}, map::AtomicCounter, }; +use noirc_frontend::hir_def::types::Type as HirType; /// Contains the entire SSA representation of the program. pub(crate) struct Ssa { @@ -17,12 +19,16 @@ pub(crate) struct Ssa { /// This mapping is necessary to use the correct function pointer for an ACIR call, /// as the final program artifact will be a list of only entry point functions. pub(crate) entry_point_to_generated_index: BTreeMap, + pub(crate) error_selector_to_type: BTreeMap, } impl Ssa { /// Create a new Ssa object from the given SSA functions. /// The first function in this vector is expected to be the main function. - pub(crate) fn new(functions: Vec) -> Self { + pub(crate) fn new( + functions: Vec, + error_types: BTreeMap, + ) -> Self { let main_id = functions.first().expect("Expected at least 1 SSA function").id(); let mut max_id = main_id; @@ -50,6 +56,7 @@ impl Ssa { main_id, next_id: AtomicCounter::starting_after(max_id), entry_point_to_generated_index, + error_selector_to_type: error_types, } } diff --git a/compiler/noirc_frontend/Cargo.toml b/compiler/noirc_frontend/Cargo.toml index 84c9393fa37..0430d214d53 100644 --- a/compiler/noirc_frontend/Cargo.toml +++ b/compiler/noirc_frontend/Cargo.toml @@ -10,10 +10,10 @@ license.workspace = true [dependencies] acvm.workspace = true +noirc_arena.workspace = true noirc_errors.workspace = true noirc_printable_type.workspace = true fm.workspace = true -arena.workspace = true iter-extended.workspace = true chumsky.workspace = true thiserror.workspace = true diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index 5659de46588..59c04218e2e 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::fmt::Display; use crate::ast::{ - Distinctness, Ident, ItemVisibility, Path, Pattern, Recoverable, Statement, StatementKind, + Ident, ItemVisibility, Path, Pattern, Recoverable, Statement, StatementKind, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, Visibility, }; use crate::token::{Attributes, Token}; @@ -401,7 +401,6 @@ pub struct FunctionDefinition { pub where_clause: Vec, pub return_type: FunctionReturnType, pub return_visibility: Visibility, - pub return_distinctness: Distinctness, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -698,7 +697,6 @@ impl FunctionDefinition { where_clause: where_clause.to_vec(), return_type: return_type.clone(), return_visibility: Visibility::Private, - return_distinctness: Distinctness::DuplicationAllowed, } } } diff --git a/compiler/noirc_frontend/src/ast/function.rs b/compiler/noirc_frontend/src/ast/function.rs index 9816218c5f7..dc426a4642a 100644 --- a/compiler/noirc_frontend/src/ast/function.rs +++ b/compiler/noirc_frontend/src/ast/function.rs @@ -109,6 +109,7 @@ impl From for NoirFunction { Some(FunctionAttribute::Oracle(_)) => FunctionKind::Oracle, Some(FunctionAttribute::Recursive) => FunctionKind::Recursive, Some(FunctionAttribute::Fold) => FunctionKind::Normal, + Some(FunctionAttribute::NoPredicates) => FunctionKind::Normal, None => FunctionKind::Normal, }; diff --git a/compiler/noirc_frontend/src/ast/statement.rs b/compiler/noirc_frontend/src/ast/statement.rs index 1831a046f5b..0da39edfd85 100644 --- a/compiler/noirc_frontend/src/ast/statement.rs +++ b/compiler/noirc_frontend/src/ast/statement.rs @@ -40,7 +40,7 @@ pub enum StatementKind { Break, Continue, /// This statement should be executed at compile-time - Comptime(Box), + Comptime(Box), // This is an expression with a trailing semi-colon Semi(Expression), // This statement is the result of a recovered parse error. @@ -486,7 +486,8 @@ impl Pattern { pub fn name_ident(&self) -> &Ident { match self { Pattern::Identifier(name_ident) => name_ident, - _ => panic!("only the identifier pattern can return a name"), + Pattern::Mutable(pattern, ..) => pattern.name_ident(), + _ => panic!("Only the Identifier or Mutable patterns can return a name"), } } @@ -685,7 +686,7 @@ impl Display for StatementKind { StatementKind::For(for_loop) => for_loop.fmt(f), StatementKind::Break => write!(f, "break"), StatementKind::Continue => write!(f, "continue"), - StatementKind::Comptime(statement) => write!(f, "comptime {statement}"), + StatementKind::Comptime(statement) => write!(f, "comptime {}", statement.kind), StatementKind::Semi(semi) => write!(f, "{semi};"), StatementKind::Error => write!(f, "Error"), } diff --git a/compiler/noirc_frontend/src/hir/comptime/errors.rs b/compiler/noirc_frontend/src/hir/comptime/errors.rs index 67d9a006b22..af5ba9a44cf 100644 --- a/compiler/noirc_frontend/src/hir/comptime/errors.rs +++ b/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -1,13 +1,13 @@ -use crate::Type; +use crate::{hir::def_collector::dc_crate::CompilationError, Type}; use acvm::FieldElement; -use noirc_errors::Location; +use noirc_errors::{CustomDiagnostic, Location}; use super::value::Value; /// The possible errors that can halt the interpreter. -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum InterpreterError { - ArgumentCountMismatch { expected: usize, actual: usize, call_location: Location }, + ArgumentCountMismatch { expected: usize, actual: usize, location: Location }, TypeMismatch { expected: Type, value: Value, location: Location }, NonComptimeVarReferenced { name: String, location: Location }, IntegerOutOfRangeForType { value: FieldElement, typ: Type, location: Location }, @@ -16,7 +16,7 @@ pub enum InterpreterError { NonBoolUsedInIf { value: Value, location: Location }, NonBoolUsedInConstrain { value: Value, location: Location }, FailingConstraint { message: Option, location: Location }, - NoMethodFound { object: Value, typ: Type, location: Location }, + NoMethodFound { name: String, typ: Type, location: Location }, NonIntegerUsedInLoop { value: Value, location: Location }, NonPointerDereferenced { value: Value, location: Location }, NonTupleOrStructInMemberAccess { value: Value, location: Location }, @@ -51,3 +51,221 @@ pub enum InterpreterError { #[allow(unused)] pub(super) type IResult = std::result::Result; + +impl InterpreterError { + pub fn into_compilation_error_pair(self) -> (CompilationError, fm::FileId) { + let location = self.get_location(); + (CompilationError::InterpreterError(self), location.file) + } + + pub fn get_location(&self) -> Location { + match self { + InterpreterError::ArgumentCountMismatch { location, .. } + | InterpreterError::TypeMismatch { location, .. } + | InterpreterError::NonComptimeVarReferenced { location, .. } + | InterpreterError::IntegerOutOfRangeForType { location, .. } + | InterpreterError::ErrorNodeEncountered { location, .. } + | InterpreterError::NonFunctionCalled { location, .. } + | InterpreterError::NonBoolUsedInIf { location, .. } + | InterpreterError::NonBoolUsedInConstrain { location, .. } + | InterpreterError::FailingConstraint { location, .. } + | InterpreterError::NoMethodFound { location, .. } + | InterpreterError::NonIntegerUsedInLoop { location, .. } + | InterpreterError::NonPointerDereferenced { location, .. } + | InterpreterError::NonTupleOrStructInMemberAccess { location, .. } + | InterpreterError::NonArrayIndexed { location, .. } + | InterpreterError::NonIntegerUsedAsIndex { location, .. } + | InterpreterError::NonIntegerIntegerLiteral { location, .. } + | InterpreterError::NonIntegerArrayLength { location, .. } + | InterpreterError::NonNumericCasted { location, .. } + | InterpreterError::IndexOutOfBounds { location, .. } + | InterpreterError::ExpectedStructToHaveField { location, .. } + | InterpreterError::TypeUnsupported { location, .. } + | InterpreterError::InvalidValueForUnary { location, .. } + | InterpreterError::InvalidValuesForBinary { location, .. } + | InterpreterError::CastToNonNumericType { location, .. } + | InterpreterError::QuoteInRuntimeCode { location, .. } + | InterpreterError::NonStructInConstructor { location, .. } + | InterpreterError::CannotInlineMacro { location, .. } + | InterpreterError::UnquoteFoundDuringEvaluation { location, .. } + | InterpreterError::Unimplemented { location, .. } + | InterpreterError::BreakNotInLoop { location, .. } + | InterpreterError::ContinueNotInLoop { location, .. } => *location, + InterpreterError::Break | InterpreterError::Continue => { + panic!("Tried to get the location of Break/Continue error!") + } + } + } +} + +impl<'a> From<&'a InterpreterError> for CustomDiagnostic { + fn from(error: &'a InterpreterError) -> Self { + match error { + InterpreterError::ArgumentCountMismatch { expected, actual, location } => { + let only = if expected > actual { "only " } else { "" }; + let plural = if *expected == 1 { "" } else { "s" }; + let was_were = if *actual == 1 { "was" } else { "were" }; + let msg = format!( + "Expected {expected} argument{plural}, but {only}{actual} {was_were} provided" + ); + + let few_many = if actual < expected { "few" } else { "many" }; + let secondary = format!("Too {few_many} arguments"); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::TypeMismatch { expected, value, location } => { + let typ = value.get_type(); + let msg = format!("Expected `{expected}` but a value of type `{typ}` was given"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonComptimeVarReferenced { name, location } => { + let msg = format!("Non-comptime variable `{name}` referenced in comptime code"); + let secondary = "Non-comptime variables can't be used in comptime code".to_string(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::IntegerOutOfRangeForType { value, typ, location } => { + let int = match value.try_into_u128() { + Some(int) => int.to_string(), + None => value.to_string(), + }; + let msg = format!("{int} is outside the range of the {typ} type"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::ErrorNodeEncountered { location } => { + let msg = "Internal Compiler Error: Error node encountered".to_string(); + let secondary = "This is a bug, please report this if found!".to_string(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonFunctionCalled { value, location } => { + let msg = "Only functions may be called".to_string(); + let secondary = format!("Expression has type {}", value.get_type()); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonBoolUsedInIf { value, location } => { + let msg = format!("Expected a `bool` but found `{}`", value.get_type()); + let secondary = "If conditions must be a boolean value".to_string(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonBoolUsedInConstrain { value, location } => { + let msg = format!("Expected a `bool` but found `{}`", value.get_type()); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::FailingConstraint { message, location } => { + let (primary, secondary) = match message { + Some(msg) => (format!("{msg:?}"), "Assertion failed".into()), + None => ("Assertion failed".into(), String::new()), + }; + CustomDiagnostic::simple_error(primary, secondary, location.span) + } + InterpreterError::NoMethodFound { name, typ, location } => { + let msg = format!("No method named `{name}` found for type `{typ}`"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonIntegerUsedInLoop { value, location } => { + let typ = value.get_type(); + let msg = format!("Non-integer type `{typ}` used in for loop"); + let secondary = if matches!(typ.as_ref(), &Type::FieldElement) { + "`field` is not an integer type, try `u64` instead".to_string() + } else { + String::new() + }; + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonPointerDereferenced { value, location } => { + let typ = value.get_type(); + let msg = format!("Only references may be dereferenced, but found `{typ}`"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonTupleOrStructInMemberAccess { value, location } => { + let msg = format!("The type `{}` has no fields to access", value.get_type()); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonArrayIndexed { value, location } => { + let msg = format!("Expected an array or slice but found a(n) {}", value.get_type()); + let secondary = "Only arrays or slices may be indexed".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonIntegerUsedAsIndex { value, location } => { + let msg = format!("Expected an integer but found a(n) {}", value.get_type()); + let secondary = + "Only integers may be indexed. Note that this excludes `field`s".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonIntegerIntegerLiteral { typ, location } => { + let msg = format!("This integer literal somehow has the type `{typ}`"); + let secondary = "This is likely a bug".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonIntegerArrayLength { typ, location } => { + let msg = format!("Non-integer array length: `{typ}`"); + let secondary = "Array lengths must be integers".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::NonNumericCasted { value, location } => { + let msg = "Only numeric types may be casted".into(); + let secondary = format!("`{}` is non-numeric", value.get_type()); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::IndexOutOfBounds { index, length, location } => { + let msg = format!("{index} is out of bounds for the array of length {length}"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::ExpectedStructToHaveField { value, field_name, location } => { + let typ = value.get_type(); + let msg = format!("The type `{typ}` has no field named `{field_name}`"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::TypeUnsupported { typ, location } => { + let msg = + format!("The type `{typ}` is currently unsupported in comptime expressions"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::InvalidValueForUnary { value, operator, location } => { + let msg = format!("`{}` cannot be used with unary {operator}", value.get_type()); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::InvalidValuesForBinary { lhs, rhs, operator, location } => { + let lhs = lhs.get_type(); + let rhs = rhs.get_type(); + let msg = format!("No implementation for `{lhs}` {operator} `{rhs}`",); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::CastToNonNumericType { typ, location } => { + let msg = format!("Cannot cast to non-numeric type `{typ}`"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::QuoteInRuntimeCode { location } => { + let msg = "`quote` may only be used in comptime code".into(); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::NonStructInConstructor { typ, location } => { + let msg = format!("`{typ}` is not a struct type"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::CannotInlineMacro { value, location } => { + let msg = "Cannot inline value into runtime code if it contains references".into(); + let secondary = format!("Cannot inline value {value:?}"); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::UnquoteFoundDuringEvaluation { location } => { + let msg = "Unquote found during comptime evaluation".into(); + let secondary = "This is a bug".into(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } + InterpreterError::Unimplemented { item, location } => { + let msg = format!("{item} is currently unimplemented"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::BreakNotInLoop { location } => { + let msg = "There is no loop to break out of!".into(); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::ContinueNotInLoop { location } => { + let msg = "There is no loop to continue!".into(); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } + InterpreterError::Break => unreachable!("Uncaught InterpreterError::Break"), + InterpreterError::Continue => unreachable!("Uncaught InterpreterError::Continue"), + } + } +} diff --git a/compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs b/compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs index 42ee76d29fa..1ab9c13ea25 100644 --- a/compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs +++ b/compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs @@ -67,7 +67,7 @@ impl StmtId { HirStatement::Semi(expr) => StatementKind::Semi(expr.to_ast(interner)), HirStatement::Error => StatementKind::Error, HirStatement::Comptime(statement) => { - StatementKind::Comptime(Box::new(statement.to_ast(interner).kind)) + StatementKind::Comptime(Box::new(statement.to_ast(interner))) } }; diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index c01c985a40c..26b7c212a30 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -70,20 +70,21 @@ impl<'a> Interpreter<'a> { &mut self, function: FuncId, arguments: Vec<(Value, Location)>, - call_location: Location, + location: Location, ) -> IResult { let previous_state = self.enter_function(); let meta = self.interner.function_meta(&function); if meta.kind != FunctionKind::Normal { - todo!("Evaluation for {:?} is unimplemented", meta.kind); + let item = "Evaluation for builtin functions"; + return Err(InterpreterError::Unimplemented { item, location }); } if meta.parameters.len() != arguments.len() { return Err(InterpreterError::ArgumentCountMismatch { expected: meta.parameters.len(), actual: arguments.len(), - call_location, + location, }); } @@ -113,7 +114,7 @@ impl<'a> Interpreter<'a> { return Err(InterpreterError::ArgumentCountMismatch { expected: closure.parameters.len(), actual: arguments.len(), - call_location, + location: call_location, }); } @@ -133,8 +134,11 @@ impl<'a> Interpreter<'a> { /// `exit_function` is called. pub(super) fn enter_function(&mut self) -> (bool, Vec>) { // Drain every scope except the global scope - let scope = self.scopes.drain(1..).collect(); - self.push_scope(); + let mut scope = Vec::new(); + if self.scopes.len() > 1 { + scope = self.scopes.drain(1..).collect(); + self.push_scope(); + } (std::mem::take(&mut self.in_loop), scope) } @@ -159,7 +163,7 @@ impl<'a> Interpreter<'a> { self.scopes.last_mut().unwrap() } - fn define_pattern( + pub(super) fn define_pattern( &mut self, pattern: &HirPattern, typ: &Type, @@ -261,7 +265,7 @@ impl<'a> Interpreter<'a> { Err(InterpreterError::NonComptimeVarReferenced { name, location }) } - fn lookup(&self, ident: &HirIdent) -> IResult { + pub(super) fn lookup(&self, ident: &HirIdent) -> IResult { self.lookup_id(ident.id, ident.location) } @@ -290,7 +294,7 @@ impl<'a> Interpreter<'a> { } /// Evaluate an expression and return the result - fn evaluate(&mut self, id: ExprId) -> IResult { + pub(super) fn evaluate(&mut self, id: ExprId) -> IResult { match self.interner.expression(&id) { HirExpression::Ident(ident) => self.evaluate_ident(ident, id), HirExpression::Literal(literal) => self.evaluate_literal(literal, id), @@ -321,7 +325,7 @@ impl<'a> Interpreter<'a> { } } - fn evaluate_ident(&mut self, ident: HirIdent, id: ExprId) -> IResult { + pub(super) fn evaluate_ident(&mut self, ident: HirIdent, id: ExprId) -> IResult { let definition = self.interner.definition(ident.id); match &definition.kind { @@ -331,9 +335,15 @@ impl<'a> Interpreter<'a> { } DefinitionKind::Local(_) => self.lookup(&ident), DefinitionKind::Global(global_id) => { - let let_ = self.interner.get_global_let_statement(*global_id).unwrap(); - self.evaluate_let(let_)?; - self.lookup(&ident) + // Don't need to check let_.comptime, we can evaluate non-comptime globals too. + // Avoid resetting the value if it is already known + if let Ok(value) = self.lookup(&ident) { + Ok(value) + } else { + let let_ = self.interner.get_global_let_statement(*global_id).unwrap(); + self.evaluate_let(let_)?; + self.lookup(&ident) + } } DefinitionKind::GenericType(type_variable) => { let value = match &*type_variable.borrow() { @@ -506,11 +516,8 @@ impl<'a> Interpreter<'a> { Value::U64(value) => Ok(Value::U64(0 - value)), value => { let location = self.interner.expr_location(&id); - Err(InterpreterError::InvalidValueForUnary { - value, - location, - operator: "minus", - }) + let operator = "minus"; + Err(InterpreterError::InvalidValueForUnary { value, location, operator }) } }, crate::ast::UnaryOp::Not => match rhs { @@ -880,7 +887,7 @@ impl<'a> Interpreter<'a> { if let Some(method) = method { self.call_function(method, arguments, location) } else { - Err(InterpreterError::NoMethodFound { object, typ, location }) + Err(InterpreterError::NoMethodFound { name: method_name.clone(), typ, location }) } } @@ -1029,7 +1036,7 @@ impl<'a> Interpreter<'a> { } } - fn evaluate_let(&mut self, let_: HirLetStatement) -> IResult { + pub(super) fn evaluate_let(&mut self, let_: HirLetStatement) -> IResult { let rhs = self.evaluate(let_.expression)?; let location = self.interner.expr_location(&let_.expression); self.define_pattern(&let_.pattern, &let_.r#type, rhs, location)?; diff --git a/compiler/noirc_frontend/src/hir/comptime/mod.rs b/compiler/noirc_frontend/src/hir/comptime/mod.rs index 26e05d675b3..0c8efae63ee 100644 --- a/compiler/noirc_frontend/src/hir/comptime/mod.rs +++ b/compiler/noirc_frontend/src/hir/comptime/mod.rs @@ -5,4 +5,6 @@ mod scan; mod tests; mod value; +pub use errors::InterpreterError; pub use interpreter::Interpreter; +pub use value::Value; diff --git a/compiler/noirc_frontend/src/hir/comptime/scan.rs b/compiler/noirc_frontend/src/hir/comptime/scan.rs index 50c8ccb4557..7101a158ddb 100644 --- a/compiler/noirc_frontend/src/hir/comptime/scan.rs +++ b/compiler/noirc_frontend/src/hir/comptime/scan.rs @@ -14,18 +14,19 @@ use crate::{ hir_def::{ expr::{ HirArrayLiteral, HirBlockExpression, HirCallExpression, HirConstructorExpression, - HirIfExpression, HirIndexExpression, HirInfixExpression, HirLambda, + HirIdent, HirIfExpression, HirIndexExpression, HirInfixExpression, HirLambda, HirMethodCallExpression, }, stmt::HirForStatement, }, macros_api::{HirExpression, HirLiteral, HirStatement}, - node_interner::{ExprId, FuncId, StmtId}, + node_interner::{DefinitionKind, ExprId, FuncId, GlobalId, StmtId}, }; use super::{ errors::{IResult, InterpreterError}, interpreter::Interpreter, + Value, }; #[allow(dead_code)] @@ -48,9 +49,23 @@ impl<'interner> Interpreter<'interner> { Ok(()) } + /// Evaluate this global if it is a comptime global. + /// Otherwise, scan through its expression for any comptime blocks to evaluate. + pub fn scan_global(&mut self, global: GlobalId) -> IResult<()> { + if let Some(let_) = self.interner.get_global_let_statement(global) { + if let_.comptime { + self.evaluate_let(let_)?; + } else { + self.scan_expression(let_.expression)?; + } + } + + Ok(()) + } + fn scan_expression(&mut self, expr: ExprId) -> IResult<()> { match self.interner.expression(&expr) { - HirExpression::Ident(_) => Ok(()), + HirExpression::Ident(ident) => self.scan_ident(ident, expr), HirExpression::Literal(literal) => self.scan_literal(literal), HirExpression::Block(block) => self.scan_block(block), HirExpression::Prefix(prefix) => self.scan_expression(prefix.rhs), @@ -91,6 +106,27 @@ impl<'interner> Interpreter<'interner> { } } + // Identifiers have no code to execute but we may need to inline any values + // of comptime variables into runtime code. + fn scan_ident(&mut self, ident: HirIdent, id: ExprId) -> IResult<()> { + let definition = self.interner.definition(ident.id); + + match &definition.kind { + DefinitionKind::Function(_) => Ok(()), + _ => { + // Opportunistically evaluate this identifier to see if it is compile-time known. + // If so, inline its value. + if let Ok(value) = self.evaluate_ident(ident, id) { + // TODO(#4922): Inlining closures is currently unimplemented + if !matches!(value, Value::Closure(..)) { + self.inline_expression(value, id)?; + } + } + Ok(()) + } + } + } + fn scan_literal(&mut self, literal: HirLiteral) -> IResult<()> { match literal { HirLiteral::Array(elements) | HirLiteral::Slice(elements) => match elements { @@ -210,4 +246,12 @@ impl<'interner> Interpreter<'interner> { self.pop_scope(); Ok(()) } + + fn inline_expression(&mut self, value: Value, expr: ExprId) -> IResult<()> { + let location = self.interner.expr_location(&expr); + let new_expr = value.into_expression(self.interner, location)?; + let new_expr = self.interner.expression(&new_expr); + self.interner.replace_expr(&expr, new_expr); + Ok(()) + } } diff --git a/compiler/noirc_frontend/src/hir/comptime/tests.rs b/compiler/noirc_frontend/src/hir/comptime/tests.rs index 1a84dae4a87..5a12eb7292c 100644 --- a/compiler/noirc_frontend/src/hir/comptime/tests.rs +++ b/compiler/noirc_frontend/src/hir/comptime/tests.rs @@ -76,6 +76,20 @@ fn mutating_arrays() { assert_eq!(result, Value::U8(22)); } +#[test] +fn mutate_in_new_scope() { + let program = "fn main() -> pub u8 { + let mut x = 0; + x += 1; + { + x += 1; + } + x + }"; + let result = interpret(program, vec!["main".into()]); + assert_eq!(result, Value::U8(2)); +} + #[test] fn for_loop() { let program = "fn main() -> pub u8 { diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index d7af4643192..6845c6ac5a9 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -116,7 +116,7 @@ impl Value { } Value::Closure(_lambda, _env, _typ) => { // TODO: How should a closure's environment be inlined? - let item = "returning closures from a comptime fn"; + let item = "Returning closures from a comptime fn"; return Err(InterpreterError::Unimplemented { item, location }); } Value::Tuple(fields) => { diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 7805f36cdb2..2f6b101e62f 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -1,7 +1,7 @@ use super::dc_mod::collect_defs; use super::errors::{DefCollectorErrorKind, DuplicateType}; use crate::graph::CrateId; -use crate::hir::comptime::Interpreter; +use crate::hir::comptime::{Interpreter, InterpreterError}; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; use crate::hir::resolution::errors::ResolverError; @@ -155,15 +155,24 @@ pub enum CompilationError { DefinitionError(DefCollectorErrorKind), ResolverError(ResolverError), TypeError(TypeCheckError), + InterpreterError(InterpreterError), } -impl From for CustomDiagnostic { - fn from(value: CompilationError) -> Self { +impl CompilationError { + fn is_error(&self) -> bool { + let diagnostic = CustomDiagnostic::from(self); + diagnostic.is_error() + } +} + +impl<'a> From<&'a CompilationError> for CustomDiagnostic { + fn from(value: &'a CompilationError) -> Self { match value { CompilationError::ParseError(error) => error.into(), CompilationError::DefinitionError(error) => error.into(), CompilationError::ResolverError(error) => error.into(), CompilationError::TypeError(error) => error.into(), + CompilationError::InterpreterError(error) => error.into(), } } } @@ -402,10 +411,15 @@ impl DefCollector { ); } - resolved_module.errors.extend(context.def_interner.check_for_dependency_cycles()); + let cycle_errors = context.def_interner.check_for_dependency_cycles(); + let cycles_present = !cycle_errors.is_empty(); + resolved_module.errors.extend(cycle_errors); resolved_module.type_check(context); - resolved_module.evaluate_comptime(&mut context.def_interner); + + if !cycles_present { + resolved_module.evaluate_comptime(&mut context.def_interner); + } resolved_module.errors } @@ -500,13 +514,23 @@ impl ResolvedModule { } /// Evaluate all `comptime` expressions in this module - fn evaluate_comptime(&self, interner: &mut NodeInterner) { - let mut interpreter = Interpreter::new(interner); + fn evaluate_comptime(&mut self, interner: &mut NodeInterner) { + if self.count_errors() == 0 { + let mut interpreter = Interpreter::new(interner); + + for (_file, global) in &self.globals { + if let Err(error) = interpreter.scan_global(*global) { + self.errors.push(error.into_compilation_error_pair()); + } + } - for (_file, function) in &self.functions { - // .unwrap() is temporary here until we can convert - // from InterpreterError to (CompilationError, FileId) - interpreter.scan_function(*function).unwrap(); + for (_file, function) in &self.functions { + // The file returned by the error may be different than the file the + // function is in so only use the error's file id. + if let Err(error) = interpreter.scan_function(*function) { + self.errors.push(error.into_compilation_error_pair()); + } + } } } @@ -520,4 +544,9 @@ impl ResolvedModule { self.globals.extend(globals.globals); self.errors.extend(globals.errors); } + + /// Counts the number of errors (minus warnings) this program currently has + fn count_errors(&self) -> usize { + self.errors.iter().filter(|(error, _)| error.is_error()).count() + } } diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index baedb109967..b2ec7dbc813 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -6,7 +6,8 @@ use noirc_errors::Location; use crate::ast::{ FunctionDefinition, Ident, ItemVisibility, LetStatement, ModuleDeclaration, NoirFunction, - NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, TraitImplItem, TraitItem, TypeImpl, + NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, Pattern, TraitImplItem, TraitItem, + TypeImpl, }; use crate::{ graph::CrateId, @@ -109,6 +110,7 @@ impl<'a> ModCollector<'a> { self.module_id, self.file_id, global.attributes.clone(), + matches!(global.pattern, Pattern::Mutable { .. }), ); // Add the statement to the scope so its path can be looked up later @@ -463,6 +465,7 @@ impl<'a> ModCollector<'a> { trait_id.0.local_id, self.file_id, vec![], + false, ); if let Err((first_def, second_def)) = self.def_collector.def_map.modules diff --git a/compiler/noirc_frontend/src/hir/def_collector/errors.rs b/compiler/noirc_frontend/src/hir/def_collector/errors.rs index 59a3051ac70..edeb463e10d 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/errors.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/errors.rs @@ -77,7 +77,7 @@ pub struct MacroError { } impl DefCollectorErrorKind { - pub fn into_file_diagnostic(self, file: fm::FileId) -> FileDiagnostic { + pub fn into_file_diagnostic(&self, file: fm::FileId) -> FileDiagnostic { Diagnostic::from(self).in_file(file) } } @@ -99,8 +99,8 @@ impl fmt::Display for DuplicateType { } } -impl From for Diagnostic { - fn from(error: DefCollectorErrorKind) -> Diagnostic { +impl<'a> From<&'a DefCollectorErrorKind> for Diagnostic { + fn from(error: &'a DefCollectorErrorKind) -> Diagnostic { match error { DefCollectorErrorKind::Duplicate { typ, first_def, second_def } => { let primary_message = format!( @@ -133,18 +133,18 @@ impl From for Diagnostic { DefCollectorErrorKind::NonStructTypeInImpl { span } => Diagnostic::simple_error( "Non-struct type used in impl".into(), "Only struct types may have implementation methods".into(), - span, + *span, ), DefCollectorErrorKind::MutableReferenceInTraitImpl { span } => Diagnostic::simple_error( "Trait impls are not allowed on mutable reference types".into(), "Try using a struct type here instead".into(), - span, + *span, ), DefCollectorErrorKind::OverlappingImpl { span, typ } => { Diagnostic::simple_error( format!("Impl for type `{typ}` overlaps with existing impl"), "Overlapping impl".into(), - span, + *span, ) } DefCollectorErrorKind::OverlappingImplNote { span } => { @@ -154,13 +154,13 @@ impl From for Diagnostic { Diagnostic::simple_error( "Previous impl defined here".into(), "Previous impl defined here".into(), - span, + *span, ) } DefCollectorErrorKind::ForeignImpl { span, type_name } => Diagnostic::simple_error( "Cannot `impl` a type that was defined outside the current crate".into(), format!("{type_name} was defined outside the current crate"), - span, + *span, ), DefCollectorErrorKind::TraitNotFound { trait_path } => Diagnostic::simple_error( format!("Trait {trait_path} not found"), @@ -174,15 +174,15 @@ impl From for Diagnostic { origin, span, } => { - let plural = if expected_generic_count == 1 { "" } else { "s" }; + let plural = if *expected_generic_count == 1 { "" } else { "s" }; let primary_message = format!( "`{origin}` expects {expected_generic_count} generic{plural}, but {location} has {actual_generic_count}"); - Diagnostic::simple_error(primary_message, "".to_string(), span) + Diagnostic::simple_error(primary_message, "".to_string(), *span) } DefCollectorErrorKind::MethodNotInTrait { trait_name, impl_method } => { - let trait_name = trait_name.0.contents; + let trait_name = &trait_name.0.contents; let impl_method_span = impl_method.span(); - let impl_method_name = impl_method.0.contents; + let impl_method_name = &impl_method.0.contents; let primary_message = format!("Method with name `{impl_method_name}` is not part of trait `{trait_name}`, therefore it can't be implemented"); Diagnostic::simple_error(primary_message, "".to_owned(), impl_method_span) } @@ -191,15 +191,15 @@ impl From for Diagnostic { method_name, trait_impl_span, } => { - let trait_name = trait_name.0.contents; - let impl_method_name = method_name.0.contents; + let trait_name = &trait_name.0.contents; + let impl_method_name = &method_name.0.contents; let primary_message = format!( "Method `{impl_method_name}` from trait `{trait_name}` is not implemented" ); Diagnostic::simple_error( primary_message, format!("Please implement {impl_method_name} here"), - trait_impl_span, + *trait_impl_span, ) } DefCollectorErrorKind::NotATrait { not_a_trait_name } => { @@ -213,20 +213,20 @@ impl From for Diagnostic { DefCollectorErrorKind::ModuleAlreadyPartOfCrate { mod_name, span } => { let message = format!("Module '{mod_name}' is already part of the crate"); let secondary = String::new(); - Diagnostic::simple_error(message, secondary, span) + Diagnostic::simple_error(message, secondary, *span) } DefCollectorErrorKind::ModuleOriginallyDefined { mod_name, span } => { let message = format!("Note: {mod_name} was originally declared here"); let secondary = String::new(); - Diagnostic::simple_error(message, secondary, span) + Diagnostic::simple_error(message, secondary, *span) } DefCollectorErrorKind::TraitImplOrphaned { span } => Diagnostic::simple_error( "Orphaned trait implementation".into(), "Either the type or the trait must be from the same crate as the trait implementation".into(), - span, + *span, ), DefCollectorErrorKind::MacroError(macro_error) => { - Diagnostic::simple_error(macro_error.primary_message, macro_error.secondary_message.unwrap_or_default(), macro_error.span.unwrap_or_default()) + Diagnostic::simple_error(macro_error.primary_message.clone(), macro_error.secondary_message.clone().unwrap_or_default(), macro_error.span.unwrap_or_default()) }, } } diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 7c0090ff95b..590c2e3d6b6 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -5,8 +5,8 @@ use crate::macros_api::MacroProcessor; use crate::node_interner::{FuncId, GlobalId, NodeInterner, StructId}; use crate::parser::{parse_program, ParsedModule, ParserError}; use crate::token::{FunctionAttribute, SecondaryAttribute, TestScope}; -use arena::{Arena, Index}; use fm::{FileId, FileManager}; +use noirc_arena::{Arena, Index}; use noirc_errors::Location; use std::collections::{BTreeMap, HashMap}; mod module_def; diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index 0fac6f96086..fa4ea96316a 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -77,7 +77,7 @@ pub enum ResolverError { #[error("#[recursive] attribute is only allowed on entry points to a program")] MisplacedRecursiveAttribute { ident: Ident }, #[error("#[abi(tag)] attribute is only allowed in contracts")] - AbiAttributeOusideContract { span: Span }, + AbiAttributeOutsideContract { span: Span }, #[error("Usage of the `#[foreign]` or `#[builtin]` function attributes are not allowed outside of the Noir standard library")] LowLevelFunctionOutsideOfStdlib { ident: Ident }, #[error("Dependency cycle found, '{item}' recursively depends on itself: {cycle} ")] @@ -86,27 +86,35 @@ pub enum ResolverError { JumpInConstrainedFn { is_break: bool, span: Span }, #[error("break/continue are only allowed within loops")] JumpOutsideLoop { is_break: bool, span: Span }, + #[error("Only `comptime` globals can be mutable")] + MutableGlobal { span: Span }, + #[error("Self-referential structs are not supported")] + SelfReferentialStruct { span: Span }, + #[error("#[no_predicates] attribute is only allowed on constrained functions")] + NoPredicatesAttributeOnUnconstrained { ident: Ident }, + #[error("#[fold] attribute is only allowed on constrained functions")] + FoldAttributeOnUnconstrained { ident: Ident }, } impl ResolverError { - pub fn into_file_diagnostic(self, file: fm::FileId) -> FileDiagnostic { + pub fn into_file_diagnostic(&self, file: fm::FileId) -> FileDiagnostic { Diagnostic::from(self).in_file(file) } } -impl From for Diagnostic { +impl<'a> From<&'a ResolverError> for Diagnostic { /// Only user errors can be transformed into a Diagnostic /// ICEs will make the compiler panic, as they could affect the /// soundness of the generated program - fn from(error: ResolverError) -> Diagnostic { + fn from(error: &'a ResolverError) -> Diagnostic { match error { ResolverError::DuplicateDefinition { name, first_span, second_span } => { let mut diag = Diagnostic::simple_error( format!("duplicate definitions of {name} found"), "first definition found here".to_string(), - first_span, + *first_span, ); - diag.add_secondary("second definition found here".to_string(), second_span); + diag.add_secondary("second definition found here".to_string(), *second_span); diag } ResolverError::UnusedVariable { ident } => { @@ -121,18 +129,18 @@ impl From for Diagnostic { ResolverError::VariableNotDeclared { name, span } => Diagnostic::simple_error( format!("cannot find `{name}` in this scope "), "not found in this scope".to_string(), - span, + *span, ), ResolverError::PathIsNotIdent { span } => Diagnostic::simple_error( "cannot use path as an identifier".to_string(), String::new(), - span, + *span, ), ResolverError::PathResolutionError(error) => error.into(), ResolverError::Expected { span, expected, got } => Diagnostic::simple_error( format!("expected {expected} got {got}"), String::new(), - span, + *span, ), ResolverError::DuplicateField { field } => Diagnostic::simple_error( format!("duplicate field {field}"), @@ -146,7 +154,7 @@ impl From for Diagnostic { field.span(), ) } - ResolverError::MissingFields { span, mut missing_fields, struct_definition } => { + ResolverError::MissingFields { span, missing_fields, struct_definition } => { let plural = if missing_fields.len() != 1 { "s" } else { "" }; let remaining_fields_names = match &missing_fields[..] { [field1] => field1.clone(), @@ -157,7 +165,7 @@ impl From for Diagnostic { let len_plural = if len != 1 {"s"} else {""}; let truncated_fields = format!(" and {len} other field{len_plural}"); - missing_fields.truncate(3); + let missing_fields = &missing_fields[0..3]; format!("{}{truncated_fields}", missing_fields.join(", ")) } }; @@ -165,18 +173,18 @@ impl From for Diagnostic { Diagnostic::simple_error( format!("missing field{plural} {remaining_fields_names} in struct {struct_definition}"), String::new(), - span, + *span, ) } ResolverError::UnnecessaryMut { first_mut, second_mut } => { let mut error = Diagnostic::simple_error( "'mut' here is not necessary".to_owned(), "".to_owned(), - second_mut, + *second_mut, ); error.add_secondary( "Pattern was already made mutable from this 'mut'".to_owned(), - first_mut, + *first_mut, ); error } @@ -221,17 +229,17 @@ impl From for Diagnostic { "no expression specifying the value stored by the constant variable {name}" ), "expected expression to be stored for let statement".to_string(), - span, + *span, ), ResolverError::InvalidArrayLengthExpr { span } => Diagnostic::simple_error( "Expression invalid in an array-length context".into(), "Array-length expressions can only have simple integer operations and any variables used must be global constants".into(), - span, + *span, ), ResolverError::IntegerTooLarge { span } => Diagnostic::simple_error( "Integer too large to be evaluated to an array-length".into(), "Array-lengths may be a maximum size of usize::MAX, including intermediate calculations".into(), - span, + *span, ), ResolverError::NoSuchNumericTypeVariable { path } => Diagnostic::simple_error( format!("Cannot find a global or generic type parameter named `{path}`"), @@ -241,57 +249,57 @@ impl From for Diagnostic { ResolverError::CapturedMutableVariable { span } => Diagnostic::simple_error( "Closures cannot capture mutable variables".into(), "Mutable variable".into(), - span, + *span, ), ResolverError::TestFunctionHasParameters { span } => Diagnostic::simple_error( "Test functions cannot have any parameters".into(), "Try removing the parameters or moving the test into a wrapper function".into(), - span, + *span, ), ResolverError::NonStructUsedInConstructor { typ, span } => Diagnostic::simple_error( "Only struct types can be used in constructor expressions".into(), format!("{typ} has no fields to construct it with"), - span, + *span, ), ResolverError::NonStructWithGenerics { span } => Diagnostic::simple_error( "Only struct types can have generic arguments".into(), "Try removing the generic arguments".into(), - span, + *span, ), ResolverError::GenericsOnSelfType { span } => Diagnostic::simple_error( "Cannot apply generics to Self type".into(), "Use an explicit type name or apply the generics at the start of the impl instead".into(), - span, + *span, ), ResolverError::IncorrectGenericCount { span, item_name, actual, expected } => { - let expected_plural = if expected == 1 { "" } else { "s" }; - let actual_plural = if actual == 1 { "is" } else { "are" }; + let expected_plural = if *expected == 1 { "" } else { "s" }; + let actual_plural = if *actual == 1 { "is" } else { "are" }; Diagnostic::simple_error( format!("`{item_name}` has {expected} generic argument{expected_plural} but {actual} {actual_plural} given here"), "Incorrect number of generic arguments".into(), - span, + *span, ) } - ResolverError::ParserError(error) => (*error).into(), + ResolverError::ParserError(error) => error.as_ref().into(), ResolverError::MutableReferenceToImmutableVariable { variable, span } => { - Diagnostic::simple_error(format!("Cannot mutably reference the immutable variable {variable}"), format!("{variable} is immutable"), span) + Diagnostic::simple_error(format!("Cannot mutably reference the immutable variable {variable}"), format!("{variable} is immutable"), *span) }, ResolverError::MutableReferenceToArrayElement { span } => { - Diagnostic::simple_error("Mutable references to array elements are currently unsupported".into(), "Try storing the element in a fresh variable first".into(), span) + Diagnostic::simple_error("Mutable references to array elements are currently unsupported".into(), "Try storing the element in a fresh variable first".into(), *span) }, ResolverError::NumericConstantInFormatString { name, span } => Diagnostic::simple_error( format!("cannot find `{name}` in this scope "), "Numeric constants should be printed without formatting braces".to_string(), - span, + *span, ), ResolverError::InvalidClosureEnvironment { span, typ } => Diagnostic::simple_error( format!("{typ} is not a valid closure environment type"), - "Closure environment must be a tuple or unit type".to_string(), span), + "Closure environment must be a tuple or unit type".to_string(), *span), ResolverError::NestedSlices { span } => Diagnostic::simple_error( "Nested slices are not supported".into(), "Try to use a constant sized array instead".into(), - span, + *span, ), ResolverError::MisplacedRecursiveAttribute { ident } => { let name = &ident.0.contents; @@ -305,11 +313,11 @@ impl From for Diagnostic { diag.add_note("The `#[recursive]` attribute specifies to the backend whether it should use a prover which generates proofs that are friendly for recursive verification in another circuit".to_owned()); diag } - ResolverError::AbiAttributeOusideContract { span } => { + ResolverError::AbiAttributeOutsideContract { span } => { Diagnostic::simple_error( "#[abi(tag)] attributes can only be used in contracts".to_string(), "misplaced #[abi(tag)] attribute".to_string(), - span, + *span, ) }, ResolverError::LowLevelFunctionOutsideOfStdlib { ident } => Diagnostic::simple_error( @@ -321,25 +329,63 @@ impl From for Diagnostic { Diagnostic::simple_error( "Dependency cycle found".into(), format!("'{item}' recursively depends on itself: {cycle}"), - span, + *span, ) }, ResolverError::JumpInConstrainedFn { is_break, span } => { - let item = if is_break { "break" } else { "continue" }; + let item = if *is_break { "break" } else { "continue" }; Diagnostic::simple_error( format!("{item} is only allowed in unconstrained functions"), "Constrained code must always have a known number of loop iterations".into(), - span, + *span, ) }, ResolverError::JumpOutsideLoop { is_break, span } => { - let item = if is_break { "break" } else { "continue" }; + let item = if *is_break { "break" } else { "continue" }; Diagnostic::simple_error( format!("{item} is only allowed within loops"), "".into(), - span, + *span, ) }, + ResolverError::MutableGlobal { span } => { + Diagnostic::simple_error( + "Only `comptime` globals may be mutable".into(), + String::new(), + *span, + ) + }, + ResolverError::SelfReferentialStruct { span } => { + Diagnostic::simple_error( + "Self-referential structs are not supported".into(), + "".into(), + *span, + ) + }, + ResolverError::NoPredicatesAttributeOnUnconstrained { ident } => { + let name = &ident.0.contents; + + let mut diag = Diagnostic::simple_error( + format!("misplaced #[no_predicates] attribute on unconstrained function {name}. Only allowed on constrained functions"), + "misplaced #[no_predicates] attribute".to_string(), + ident.0.span(), + ); + + diag.add_note("The `#[no_predicates]` attribute specifies to the compiler whether it should diverge from auto-inlining constrained functions".to_owned()); + diag + } + ResolverError::FoldAttributeOnUnconstrained { ident } => { + let name = &ident.0.contents; + + let mut diag = Diagnostic::simple_error( + format!("misplaced #[fold] attribute on unconstrained function {name}. Only allowed on constrained functions"), + "misplaced #[fold] attribute".to_string(), + ident.0.span(), + ); + + diag.add_note("The `#[fold]` attribute specifies whether a constrained function should be treated as a separate circuit rather than inlined into the program entry point".to_owned()); + diag + } } } } diff --git a/compiler/noirc_frontend/src/hir/resolution/import.rs b/compiler/noirc_frontend/src/hir/resolution/import.rs index 77e67567f8c..8850331f683 100644 --- a/compiler/noirc_frontend/src/hir/resolution/import.rs +++ b/compiler/noirc_frontend/src/hir/resolution/import.rs @@ -53,8 +53,8 @@ pub struct ResolvedImport { pub error: Option, } -impl From for CustomDiagnostic { - fn from(error: PathResolutionError) -> Self { +impl<'a> From<&'a PathResolutionError> for CustomDiagnostic { + fn from(error: &'a PathResolutionError) -> Self { match &error { PathResolutionError::Unresolved(ident) => { CustomDiagnostic::simple_error(error.to_string(), String::new(), ident.span()) diff --git a/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 8e29f8f9fce..60baaecab59 100644 --- a/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -22,14 +22,14 @@ use crate::hir_def::traits::{Trait, TraitConstraint}; use crate::macros_api::SecondaryAttribute; use crate::token::{Attributes, FunctionAttribute}; use regex::Regex; -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::rc::Rc; use crate::ast::{ - ArrayLiteral, BinaryOpKind, BlockExpression, Distinctness, Expression, ExpressionKind, - ForRange, FunctionDefinition, FunctionKind, FunctionReturnType, Ident, ItemVisibility, LValue, + ArrayLiteral, BinaryOpKind, BlockExpression, Expression, ExpressionKind, ForRange, + FunctionDefinition, FunctionKind, FunctionReturnType, Ident, ItemVisibility, LValue, LetStatement, Literal, NoirFunction, NoirStruct, NoirTypeAlias, Param, Path, PathKind, Pattern, - Statement, StatementKind, UnaryOp, UnresolvedGenerics, UnresolvedTraitConstraint, + Statement, StatementKind, TraitBound, UnaryOp, UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression, Visibility, ERROR_IDENT, }; use crate::graph::CrateId; @@ -96,6 +96,21 @@ pub struct Resolver<'a> { /// Used to link items to their dependencies in the dependency graph current_item: Option, + /// In-resolution names + /// + /// This needs to be a set because we can have multiple in-resolution + /// names when resolving structs that are declared in reverse order of their + /// dependencies, such as in the following case: + /// + /// ``` + /// struct Wrapper { + /// value: Wrapped + /// } + /// struct Wrapped { + /// } + /// ``` + resolving_ids: BTreeSet, + /// True if the current module is a contract. /// This is usually determined by self.path_resolver.module_id(), but it can /// be overridden for impls. Impls are an odd case since the methods within resolve @@ -159,6 +174,7 @@ impl<'a> Resolver<'a> { lambda_stack: Vec::new(), current_trait_impl: None, current_item: None, + resolving_ids: BTreeSet::new(), file, in_contract, in_unconstrained_fn: false, @@ -186,6 +202,52 @@ impl<'a> Resolver<'a> { self.errors.push(err); } + /// This turns function parameters of the form: + /// fn foo(x: impl Bar) + /// + /// into + /// fn foo(x: T0_impl_Bar) where T0_impl_Bar: Bar + fn desugar_impl_trait_args(&mut self, func: &mut NoirFunction, func_id: FuncId) { + let mut impl_trait_generics = HashSet::new(); + let mut counter: usize = 0; + for parameter in func.def.parameters.iter_mut() { + if let UnresolvedTypeData::TraitAsType(path, args) = ¶meter.typ.typ { + let mut new_generic_ident: Ident = + format!("T{}_impl_{}", func_id, path.as_string()).into(); + let mut new_generic_path = Path::from_ident(new_generic_ident.clone()); + while impl_trait_generics.contains(&new_generic_ident) + || self.lookup_generic_or_global_type(&new_generic_path).is_some() + { + new_generic_ident = + format!("T{}_impl_{}_{}", func_id, path.as_string(), counter).into(); + new_generic_path = Path::from_ident(new_generic_ident.clone()); + counter += 1; + } + impl_trait_generics.insert(new_generic_ident.clone()); + + let is_synthesized = true; + let new_generic_type_data = + UnresolvedTypeData::Named(new_generic_path, vec![], is_synthesized); + let new_generic_type = + UnresolvedType { typ: new_generic_type_data.clone(), span: None }; + let new_trait_bound = TraitBound { + trait_path: path.clone(), + trait_id: None, + trait_generics: args.to_vec(), + }; + let new_trait_constraint = UnresolvedTraitConstraint { + typ: new_generic_type, + trait_bound: new_trait_bound, + }; + + parameter.typ.typ = new_generic_type_data; + func.def.generics.push(new_generic_ident); + func.def.where_clause.push(new_trait_constraint); + } + } + self.add_generics(&impl_trait_generics.into_iter().collect()); + } + /// Resolving a function involves interning the metadata /// interning any statements inside of the function /// and interning the function itself @@ -193,7 +255,7 @@ impl<'a> Resolver<'a> { /// Since lowering would require scope data, unless we add an extra resolution field to the AST pub fn resolve_function( mut self, - func: NoirFunction, + mut func: NoirFunction, func_id: FuncId, ) -> (HirFunction, FuncMeta, Vec) { self.scopes.start_function(); @@ -201,8 +263,9 @@ impl<'a> Resolver<'a> { // Check whether the function has globals in the local module and add them to the scope self.resolve_local_globals(); - self.add_generics(&func.def.generics); + + self.desugar_impl_trait_args(&mut func, func_id); self.trait_bounds = func.def.where_clause.clone(); let is_low_level_or_oracle = func @@ -257,7 +320,6 @@ impl<'a> Resolver<'a> { where_clause: where_clause.to_vec(), return_type: return_type.clone(), return_visibility: Visibility::Private, - return_distinctness: Distinctness::DuplicationAllowed, }; let (hir_func, func_meta) = self.intern_function(NoirFunction { kind, def }, func_id); @@ -616,6 +678,14 @@ impl<'a> Resolver<'a> { match self.lookup_struct_or_error(path) { Some(struct_type) => { + if self.resolving_ids.contains(&struct_type.borrow().id) { + self.push_err(ResolverError::SelfReferentialStruct { + span: struct_type.borrow().name.span(), + }); + + return Type::Error; + } + let expected_generic_count = struct_type.borrow().generics.len(); if !self.in_contract && self @@ -624,7 +694,7 @@ impl<'a> Resolver<'a> { .iter() .any(|attr| matches!(attr, SecondaryAttribute::Abi(_))) { - self.push_err(ResolverError::AbiAttributeOusideContract { + self.push_err(ResolverError::AbiAttributeOutsideContract { span: struct_type.borrow().name.span(), }); } @@ -886,7 +956,10 @@ impl<'a> Resolver<'a> { self.resolve_local_globals(); self.current_item = Some(DependencyId::Struct(struct_id)); + + self.resolving_ids.insert(struct_id); let fields = vecmap(unresolved.fields, |(ident, typ)| (ident, self.resolve_type(typ))); + self.resolving_ids.remove(&struct_id); (generics, fields, self.errors) } @@ -926,7 +999,23 @@ impl<'a> Resolver<'a> { let name_ident = HirIdent::non_trait_method(id, location); let attributes = func.attributes().clone(); + let has_no_predicates_attribute = attributes.is_no_predicates(); let should_fold = attributes.is_foldable(); + if !self.inline_attribute_allowed(func) { + if has_no_predicates_attribute { + self.push_err(ResolverError::NoPredicatesAttributeOnUnconstrained { + ident: func.name_ident().clone(), + }); + } else if should_fold { + self.push_err(ResolverError::FoldAttributeOnUnconstrained { + ident: func.name_ident().clone(), + }); + } + } + // Both the #[fold] and #[no_predicates] alter a function's inline type and code generation in similar ways. + // In certain cases such as type checking (for which the following flag will be used) both attributes + // indicate we should code generate in the same way. Thus, we unify the attributes into one flag here. + let has_inline_attribute = has_no_predicates_attribute || should_fold; let mut generics = vecmap(&self.generics, |(_, typevar, _)| typevar.clone()); let mut parameters = vec![]; @@ -979,12 +1068,6 @@ impl<'a> Resolver<'a> { }); } - if !self.distinct_allowed(func) - && func.def.return_distinctness != Distinctness::DuplicationAllowed - { - self.push_err(ResolverError::DistinctNotAllowed { ident: func.name_ident().clone() }); - } - if matches!(attributes.function, Some(FunctionAttribute::Test { .. })) && !parameters.is_empty() { @@ -1017,11 +1100,10 @@ impl<'a> Resolver<'a> { parameters: parameters.into(), return_type: func.def.return_type.clone(), return_visibility: func.def.return_visibility, - return_distinctness: func.def.return_distinctness, has_body: !func.def.body.is_empty(), trait_constraints: self.resolve_trait_constraints(&func.def.where_clause), is_entry_point: self.is_entry_point_function(func), - should_fold, + has_inline_attribute, } } @@ -1046,15 +1128,10 @@ impl<'a> Resolver<'a> { } } - /// True if the `distinct` keyword is allowed on a function's return type - fn distinct_allowed(&self, func: &NoirFunction) -> bool { - if self.in_contract { - // "unconstrained" functions are compiled to brillig and thus duplication of - // witness indices in their abis is not a concern. - !func.def.is_unconstrained - } else { - func.name() == MAIN_FUNCTION - } + fn inline_attribute_allowed(&self, func: &NoirFunction) -> bool { + // Inline attributes are only relevant for constrained functions + // as all unconstrained functions are not inlined + !func.def.is_unconstrained } fn declare_numeric_generics(&mut self, params: &[Type], return_type: &Type) { @@ -1101,10 +1178,15 @@ impl<'a> Resolver<'a> { | Type::TypeVariable(_, _) | Type::Constant(_) | Type::NamedGeneric(_, _) - | Type::TraitAsType(..) | Type::Code | Type::Forall(_, _) => (), + Type::TraitAsType(_, _, args) => { + for arg in args { + Self::find_numeric_generics_in_type(arg, found); + } + } + Type::Array(length, element_type) => { if let Type::NamedGeneric(type_variable, name) = length.as_ref() { found.insert(name.to_string(), type_variable.clone()); @@ -1173,15 +1255,18 @@ impl<'a> Resolver<'a> { ) -> HirStatement { self.current_item = Some(DependencyId::Global(global_id)); let expression = self.resolve_expression(let_stmt.expression); - let global_id = self.interner.next_global_id(); let definition = DefinitionKind::Global(global_id); if !self.in_contract && let_stmt.attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Abi(_))) { - self.push_err(ResolverError::AbiAttributeOusideContract { - span: let_stmt.pattern.span(), - }); + let span = let_stmt.pattern.span(); + self.push_err(ResolverError::AbiAttributeOutsideContract { span }); + } + + if !let_stmt.comptime && matches!(let_stmt.pattern, Pattern::Mutable(..)) { + let span = let_stmt.pattern.span(); + self.push_err(ResolverError::MutableGlobal { span }); } HirStatement::Let(HirLetStatement { @@ -1189,6 +1274,7 @@ impl<'a> Resolver<'a> { r#type: self.resolve_type(let_stmt.r#type), expression, attributes: let_stmt.attributes, + comptime: let_stmt.comptime, }) } @@ -1202,18 +1288,18 @@ impl<'a> Resolver<'a> { r#type: self.resolve_type(let_stmt.r#type), expression, attributes: let_stmt.attributes, + comptime: let_stmt.comptime, }) } StatementKind::Constrain(constrain_stmt) => { - let span = constrain_stmt.0.span; - let assert_msg_call_expr_id = - self.resolve_assert_message(constrain_stmt.1, span, constrain_stmt.0.clone()); let expr_id = self.resolve_expression(constrain_stmt.0); + let assert_message_expr_id = + constrain_stmt.1.map(|assert_expr_id| self.resolve_expression(assert_expr_id)); HirStatement::Constrain(HirConstrainStatement( expr_id, self.file, - assert_msg_call_expr_id, + assert_message_expr_id, )) } StatementKind::Expression(expr) => { @@ -1273,54 +1359,14 @@ impl<'a> Resolver<'a> { } StatementKind::Error => HirStatement::Error, StatementKind::Comptime(statement) => { - let statement = self.resolve_stmt(*statement, span); - HirStatement::Comptime(self.interner.push_stmt(statement)) + let hir_statement = self.resolve_stmt(statement.kind, statement.span); + let statement_id = self.interner.push_stmt(hir_statement); + self.interner.push_statement_location(statement_id, statement.span, self.file); + HirStatement::Comptime(statement_id) } } } - fn resolve_assert_message( - &mut self, - assert_message_expr: Option, - span: Span, - condition: Expression, - ) -> Option { - let assert_message_expr = assert_message_expr?; - - if matches!( - assert_message_expr, - Expression { kind: ExpressionKind::Literal(Literal::Str(..)), .. } - ) { - return Some(self.resolve_expression(assert_message_expr)); - } - - let is_in_stdlib = self.path_resolver.module_id().krate.is_stdlib(); - let assert_msg_call_path = if is_in_stdlib { - ExpressionKind::Variable(Path { - segments: vec![Ident::from("internal"), Ident::from("resolve_assert_message")], - kind: PathKind::Crate, - span, - }) - } else { - ExpressionKind::Variable(Path { - segments: vec![ - Ident::from("std"), - Ident::from("internal"), - Ident::from("resolve_assert_message"), - ], - kind: PathKind::Dep, - span, - }) - }; - let assert_msg_call_args = vec![assert_message_expr.clone(), condition]; - let assert_msg_call_expr = Expression::call( - Expression { kind: assert_msg_call_path, span }, - assert_msg_call_args, - span, - ); - Some(self.resolve_expression(assert_msg_call_expr)) - } - pub fn intern_stmt(&mut self, stmt: Statement) -> StmtId { let hir_stmt = self.resolve_stmt(stmt.kind, stmt.span); let id = self.interner.push_stmt(hir_stmt); diff --git a/compiler/noirc_frontend/src/hir/resolution/traits.rs b/compiler/noirc_frontend/src/hir/resolution/traits.rs index ccae8c6dd03..3d355fd4447 100644 --- a/compiler/noirc_frontend/src/hir/resolution/traits.rs +++ b/compiler/noirc_frontend/src/hir/resolution/traits.rs @@ -124,6 +124,7 @@ fn resolve_trait_methods( let mut resolver = Resolver::new(interner, &path_resolver, def_maps, file); resolver.add_generics(generics); + resolver.add_existing_generics(&unresolved_trait.trait_def.generics, trait_generics); resolver.add_existing_generic("Self", name_span, self_typevar); resolver.set_self_type(Some(self_type.clone())); @@ -207,16 +208,16 @@ fn collect_trait_impl_methods( if overrides.is_empty() { if let Some(default_impl) = &method.default_impl { + // copy 'where' clause from unresolved trait impl + let mut default_impl_clone = default_impl.clone(); + default_impl_clone.def.where_clause.extend(trait_impl.where_clause.clone()); + let func_id = interner.push_empty_fn(); let module = ModuleId { local_id: trait_impl.module_id, krate: crate_id }; let location = Location::new(default_impl.def.span, trait_impl.file_id); interner.push_function(func_id, &default_impl.def, module, location); func_ids_in_trait.insert(func_id); - ordered_methods.push(( - method.default_impl_module_id, - func_id, - *default_impl.clone(), - )); + ordered_methods.push((method.default_impl_module_id, func_id, *default_impl_clone)); } else { let error = DefCollectorErrorKind::TraitMissingMethod { trait_name: interner.get_trait(trait_id).name.clone(), diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index 6c2a1945283..b81727a27f5 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -80,6 +80,8 @@ pub enum TypeCheckError { FieldModulo { span: Span }, #[error("Fields cannot be compared, try casting to an integer first")] FieldComparison { span: Span }, + #[error("The bit count in a bit-shift operation must fit in a u8, try casting the right hand side into a u8 first")] + InvalidShiftSize { span: Span }, #[error("The number of bits to use for this bitwise operation is ambiguous. Either the operand's type or return type should be specified")] AmbiguousBitWidth { span: Span }, #[error("Error with additional context")] @@ -145,36 +147,36 @@ impl TypeCheckError { } } -impl From for Diagnostic { - fn from(error: TypeCheckError) -> Diagnostic { +impl<'a> From<&'a TypeCheckError> for Diagnostic { + fn from(error: &'a TypeCheckError) -> Diagnostic { match error { TypeCheckError::TypeCannotBeUsed { typ, place, span } => Diagnostic::simple_error( format!("The type {} cannot be used in a {}", &typ, place), String::new(), - span, + *span, ), TypeCheckError::Context { err, ctx } => { - let mut diag = Diagnostic::from(*err); - diag.add_note(ctx.to_owned()); + let mut diag = Diagnostic::from(err.as_ref()); + diag.add_note(ctx.to_string()); diag } TypeCheckError::OpCannotBeUsed { op, place, span } => Diagnostic::simple_error( format!("The operator {op:?} cannot be used in a {place}"), String::new(), - span, + *span, ), TypeCheckError::TypeMismatch { expected_typ, expr_typ, expr_span } => { Diagnostic::simple_error( format!("Expected type {expected_typ}, found type {expr_typ}"), String::new(), - expr_span, + *expr_span, ) } TypeCheckError::TraitMethodParameterTypeMismatch { method_name, expected_typ, actual_typ, parameter_index, parameter_span } => { Diagnostic::simple_error( format!("Parameter #{parameter_index} of method `{method_name}` must be of type {expected_typ}, not {actual_typ}"), String::new(), - parameter_span, + *parameter_span, ) } TypeCheckError::NonHomogeneousArray { @@ -190,27 +192,27 @@ impl From for Diagnostic { "Non homogeneous array, different element types found at indices ({first_index},{second_index})" ), format!("Found type {first_type}"), - first_span, + *first_span, ); - diag.add_secondary(format!("but then found type {second_type}"), second_span); + diag.add_secondary(format!("but then found type {second_type}"), *second_span); diag } TypeCheckError::ArityMisMatch { expected, found, span } => { - let plural = if expected == 1 { "" } else { "s" }; + let plural = if *expected == 1 { "" } else { "s" }; let msg = format!("Expected {expected} argument{plural}, but found {found}"); - Diagnostic::simple_error(msg, String::new(), span) + Diagnostic::simple_error(msg, String::new(), *span) } TypeCheckError::ParameterCountMismatch { expected, found, span } => { - let empty_or_s = if expected == 1 { "" } else { "s" }; - let was_or_were = if found == 1 { "was" } else { "were" }; + let empty_or_s = if *expected == 1 { "" } else { "s" }; + let was_or_were = if *found == 1 { "was" } else { "were" }; let msg = format!("Function expects {expected} parameter{empty_or_s} but {found} {was_or_were} given"); - Diagnostic::simple_error(msg, String::new(), span) + Diagnostic::simple_error(msg, String::new(), *span) } TypeCheckError::GenericCountMismatch { item, expected, found, span } => { - let empty_or_s = if expected == 1 { "" } else { "s" }; - let was_or_were = if found == 1 { "was" } else { "were" }; + let empty_or_s = if *expected == 1 { "" } else { "s" }; + let was_or_were = if *found == 1 { "was" } else { "were" }; let msg = format!("{item} expects {expected} generic{empty_or_s} but {found} {was_or_were} given"); - Diagnostic::simple_error(msg, String::new(), span) + Diagnostic::simple_error(msg, String::new(), *span) } TypeCheckError::InvalidCast { span, .. } | TypeCheckError::ExpectedFunction { span, .. } @@ -234,18 +236,19 @@ impl From for Diagnostic { | TypeCheckError::UnconstrainedReferenceToConstrained { span } | TypeCheckError::UnconstrainedSliceReturnToConstrained { span } | TypeCheckError::NonConstantSliceLength { span } - | TypeCheckError::StringIndexAssign { span } => { - Diagnostic::simple_error(error.to_string(), String::new(), span) + | TypeCheckError::StringIndexAssign { span } + | TypeCheckError::InvalidShiftSize { span } => { + Diagnostic::simple_error(error.to_string(), String::new(), *span) } TypeCheckError::PublicReturnType { typ, span } => Diagnostic::simple_error( "Functions cannot declare a public return type".to_string(), format!("return type is {typ}"), - span, + *span, ), TypeCheckError::TypeAnnotationsNeeded { span } => Diagnostic::simple_error( "Expression type is ambiguous".to_string(), "Type must be known at this point".to_string(), - span, + *span, ), TypeCheckError::ResolverError(error) => error.into(), TypeCheckError::TypeMismatchWithSource { expected, actual, span, source } => { @@ -271,30 +274,30 @@ impl From for Diagnostic { diagnostic.add_note(format!("help: try adding a return type: `-> {actual}`")); } - diagnostic.add_secondary(format!("{actual} returned here"), expr_span); + diagnostic.add_secondary(format!("{actual} returned here"), *expr_span); return diagnostic }, }; - Diagnostic::simple_error(message, String::new(), span) + Diagnostic::simple_error(message, String::new(), *span) } TypeCheckError::CallDeprecated { span, ref note, .. } => { let primary_message = error.to_string(); let secondary_message = note.clone().unwrap_or_default(); - Diagnostic::simple_warning(primary_message, secondary_message, span) + Diagnostic::simple_warning(primary_message, secondary_message, *span) } TypeCheckError::UnusedResultError { expr_type, expr_span } => { let msg = format!("Unused expression result of type {expr_type}"); - Diagnostic::simple_warning(msg, String::new(), expr_span) + Diagnostic::simple_warning(msg, String::new(), *expr_span) } TypeCheckError::NoMatchingImplFound { constraints, span } => { assert!(!constraints.is_empty()); let msg = format!("No matching impl found for `{}: {}`", constraints[0].0, constraints[0].1); let mut diagnostic = Diagnostic::from_message(&msg); - diagnostic.add_secondary(format!("No impl for `{}: {}`", constraints[0].0, constraints[0].1), span); + diagnostic.add_secondary(format!("No impl for `{}: {}`", constraints[0].0, constraints[0].1), *span); // These must be notes since secondaries are unordered for (typ, trait_name) in &constraints[1..] { @@ -305,11 +308,11 @@ impl From for Diagnostic { } TypeCheckError::UnneededTraitConstraint { trait_name, typ, span } => { let msg = format!("Constraint for `{typ}: {trait_name}` is not needed, another matching impl is already in scope"); - Diagnostic::simple_warning(msg, "Unnecessary trait constraint in where clause".into(), span) + Diagnostic::simple_warning(msg, "Unnecessary trait constraint in where clause".into(), *span) } TypeCheckError::InvalidTypeForEntryPoint { span } => Diagnostic::simple_error( "Only sized types may be used in the entry point to a program".to_string(), - "Slices, references, or any type containing them may not be used in main, contract functions, or foldable functions".to_string(), span), + "Slices, references, or any type containing them may not be used in main, contract functions, or foldable functions".to_string(), *span), TypeCheckError::MismatchTraitImplNumParameters { expected_num_parameters, actual_num_parameters, @@ -317,10 +320,10 @@ impl From for Diagnostic { method_name, span, } => { - let plural = if expected_num_parameters == 1 { "" } else { "s" }; + let plural = if *expected_num_parameters == 1 { "" } else { "s" }; let primary_message = format!( "`{trait_name}::{method_name}` expects {expected_num_parameters} parameter{plural}, but this method has {actual_num_parameters}"); - Diagnostic::simple_error(primary_message, "".to_string(), span) + Diagnostic::simple_error(primary_message, "".to_string(), *span) } } } diff --git a/compiler/noirc_frontend/src/hir/type_check/expr.rs b/compiler/noirc_frontend/src/hir/type_check/expr.rs index 0bc7673e105..9b40c959981 100644 --- a/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -1,7 +1,8 @@ use iter_extended::vecmap; use noirc_errors::Span; -use crate::ast::{BinaryOpKind, UnaryOp}; +use crate::ast::{BinaryOpKind, IntegerBitSize, UnaryOp}; +use crate::macros_api::Signedness; use crate::{ hir::{resolution::resolver::verify_mutable_reference, type_check::errors::Source}, hir_def::{ @@ -890,36 +891,6 @@ impl<'interner> TypeChecker<'interner> { // <= and friends are technically valid for booleans, just not very useful (Bool, Bool) => Ok((Bool, false)), - // Special-case == and != for arrays - (Array(x_size, x_type), Array(y_size, y_type)) - if matches!(op.kind, BinaryOpKind::Equal | BinaryOpKind::NotEqual) => - { - self.unify(x_size, y_size, || TypeCheckError::TypeMismatchWithSource { - expected: lhs_type.clone(), - actual: rhs_type.clone(), - source: Source::ArrayLen, - span: op.location.span, - }); - - let (_, use_impl) = self.comparator_operand_type_rules(x_type, y_type, op, span)?; - - // If the size is not constant, we must fall back to a user-provided impl for - // equality on slices. - let size = x_size.follow_bindings(); - let use_impl = use_impl || size.evaluate_to_u64().is_none(); - Ok((Bool, use_impl)) - } - - (String(x_size), String(y_size)) => { - self.unify(x_size, y_size, || TypeCheckError::TypeMismatchWithSource { - expected: *x_size.clone(), - actual: *y_size.clone(), - span: op.location.span, - source: Source::StringLen, - }); - - Ok((Bool, false)) - } (lhs, rhs) => { self.unify(lhs, rhs, || TypeCheckError::TypeMismatchWithSource { expected: lhs.clone(), @@ -1159,11 +1130,30 @@ impl<'interner> TypeChecker<'interner> { if let TypeBinding::Bound(binding) = &*int.borrow() { return self.infix_operand_type_rules(binding, op, other, span); } - + if op.kind == BinaryOpKind::ShiftLeft || op.kind == BinaryOpKind::ShiftRight { + self.unify( + rhs_type, + &Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight), + || TypeCheckError::InvalidShiftSize { span }, + ); + let use_impl = if lhs_type.is_numeric() { + let integer_type = Type::polymorphic_integer(self.interner); + self.bind_type_variables_for_infix(lhs_type, op, &integer_type, span) + } else { + true + }; + return Ok((lhs_type.clone(), use_impl)); + } let use_impl = self.bind_type_variables_for_infix(lhs_type, op, rhs_type, span); Ok((other.clone(), use_impl)) } (Integer(sign_x, bit_width_x), Integer(sign_y, bit_width_y)) => { + if op.kind == BinaryOpKind::ShiftLeft || op.kind == BinaryOpKind::ShiftRight { + if *sign_y != Signedness::Unsigned || *bit_width_y != IntegerBitSize::Eight { + return Err(TypeCheckError::InvalidShiftSize { span }); + } + return Ok((Integer(*sign_x, *bit_width_x), false)); + } if sign_x != sign_y { return Err(TypeCheckError::IntegerSignedness { sign_x: *sign_x, @@ -1195,6 +1185,12 @@ impl<'interner> TypeChecker<'interner> { (Bool, Bool) => Ok((Bool, false)), (lhs, rhs) => { + if op.kind == BinaryOpKind::ShiftLeft || op.kind == BinaryOpKind::ShiftRight { + if rhs == &Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight) { + return Ok((lhs.clone(), true)); + } + return Err(TypeCheckError::InvalidShiftSize { span }); + } self.unify(lhs, rhs, || TypeCheckError::TypeMismatchWithSource { expected: lhs.clone(), actual: rhs.clone(), diff --git a/compiler/noirc_frontend/src/hir/type_check/mod.rs b/compiler/noirc_frontend/src/hir/type_check/mod.rs index 44dab6dee3d..0f8131d6ebb 100644 --- a/compiler/noirc_frontend/src/hir/type_check/mod.rs +++ b/compiler/noirc_frontend/src/hir/type_check/mod.rs @@ -173,7 +173,7 @@ fn check_if_type_is_valid_for_program_input( ) { let meta = type_checker.interner.function_meta(&func_id); if (meta.is_entry_point && !param.1.is_valid_for_program_input()) - || (meta.should_fold && !param.1.is_valid_non_inlined_function_input()) + || (meta.has_inline_attribute && !param.1.is_valid_non_inlined_function_input()) { let span = param.0.span(); errors.push(TypeCheckError::InvalidTypeForEntryPoint { span }); @@ -433,9 +433,7 @@ pub mod test { use iter_extended::btree_map; use noirc_errors::{Location, Span}; - use crate::ast::{ - BinaryOpKind, Distinctness, FunctionKind, FunctionReturnType, Path, Visibility, - }; + use crate::ast::{BinaryOpKind, FunctionKind, FunctionReturnType, Path, Visibility}; use crate::graph::CrateId; use crate::hir::def_map::{ModuleData, ModuleId}; use crate::hir::resolution::import::{ @@ -508,6 +506,7 @@ pub mod test { r#type: Type::FieldElement, expression: expr_id, attributes: vec![], + comptime: false, }; let stmt_id = interner.push_stmt(HirStatement::Let(let_stmt)); let expr_id = interner @@ -538,14 +537,13 @@ pub mod test { ] .into(), return_visibility: Visibility::Private, - return_distinctness: Distinctness::DuplicationAllowed, has_body: true, trait_impl: None, return_type: FunctionReturnType::Default(Span::default()), trait_constraints: Vec::new(), direct_generics: Vec::new(), is_entry_point: true, - should_fold: false, + has_inline_attribute: false, }; interner.push_fn_meta(func_meta, func_id); @@ -672,7 +670,7 @@ pub mod test { } fn local_module_id(&self) -> LocalModuleId { - LocalModuleId(arena::Index::unsafe_zeroed()) + LocalModuleId(noirc_arena::Index::unsafe_zeroed()) } fn module_id(&self) -> ModuleId { @@ -724,7 +722,7 @@ pub mod test { let mut def_maps = BTreeMap::new(); let file = FileId::default(); - let mut modules = arena::Arena::default(); + let mut modules = noirc_arena::Arena::default(); let location = Location::new(Default::default(), file); modules.insert(ModuleData::new(None, location, false)); diff --git a/compiler/noirc_frontend/src/hir/type_check/stmt.rs b/compiler/noirc_frontend/src/hir/type_check/stmt.rs index f5f6e1e8180..0760749c9e0 100644 --- a/compiler/noirc_frontend/src/hir/type_check/stmt.rs +++ b/compiler/noirc_frontend/src/hir/type_check/stmt.rs @@ -348,8 +348,10 @@ impl<'interner> TypeChecker<'interner> { if annotated_type.is_unsigned() { self.lint_overflowing_uint(&rhs_expr, &annotated_type); } + annotated_type + } else { + expr_type } - expr_type } /// Check if an assignment is overflowing with respect to `annotated_type` diff --git a/compiler/noirc_frontend/src/hir_def/function.rs b/compiler/noirc_frontend/src/hir_def/function.rs index 67b6412a21c..c38dd41fd3d 100644 --- a/compiler/noirc_frontend/src/hir_def/function.rs +++ b/compiler/noirc_frontend/src/hir_def/function.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use super::expr::{HirBlockExpression, HirExpression, HirIdent}; use super::stmt::HirPattern; use super::traits::TraitConstraint; -use crate::ast::{Distinctness, FunctionKind, FunctionReturnType, Visibility}; +use crate::ast::{FunctionKind, FunctionReturnType, Visibility}; use crate::node_interner::{ExprId, NodeInterner, TraitImplId}; use crate::{Type, TypeVariable}; @@ -99,8 +99,6 @@ pub struct FuncMeta { pub return_visibility: Visibility, - pub return_distinctness: Distinctness, - /// The type of this function. Either a Type::Function /// or a Type::Forall for generic functions. pub typ: Type, @@ -126,8 +124,9 @@ pub struct FuncMeta { pub is_entry_point: bool, /// True if this function is marked with an attribute - /// that indicates it should not be inlined, such as for folding. - pub should_fold: bool, + /// that indicates it should be inlined differently than the default (inline everything). + /// For example, such as `fold` (never inlined) or `no_predicates` (inlined after flattening) + pub has_inline_attribute: bool, } impl FuncMeta { diff --git a/compiler/noirc_frontend/src/hir_def/stmt.rs b/compiler/noirc_frontend/src/hir_def/stmt.rs index 7e22e5ee9c0..0b4dbeb3006 100644 --- a/compiler/noirc_frontend/src/hir_def/stmt.rs +++ b/compiler/noirc_frontend/src/hir_def/stmt.rs @@ -30,6 +30,7 @@ pub struct HirLetStatement { pub r#type: Type, pub expression: ExprId, pub attributes: Vec, + pub comptime: bool, } impl HirLetStatement { diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 8c6e3d48fca..f3b2a24c1f0 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -643,9 +643,11 @@ impl Type { | Type::Constant(_) | Type::NamedGeneric(_, _) | Type::Forall(_, _) - | Type::Code - | Type::TraitAsType(..) => false, + | Type::Code => false, + Type::TraitAsType(_, _, args) => { + args.iter().any(|generic| generic.contains_numeric_typevar(target_id)) + } Type::Array(length, elem) => { elem.contains_numeric_typevar(target_id) || named_generic_id_matches_target(length) } @@ -1591,11 +1593,17 @@ impl Type { element.substitute_helper(type_bindings, substitute_bound_typevars), )), + Type::TraitAsType(s, name, args) => { + let args = vecmap(args, |arg| { + arg.substitute_helper(type_bindings, substitute_bound_typevars) + }); + Type::TraitAsType(*s, name.clone(), args) + } + Type::FieldElement | Type::Integer(_, _) | Type::Bool | Type::Constant(_) - | Type::TraitAsType(..) | Type::Error | Type::Code | Type::Unit => self.clone(), @@ -1613,7 +1621,9 @@ impl Type { let field_occurs = fields.occurs(target_id); len_occurs || field_occurs } - Type::Struct(_, generic_args) | Type::Alias(_, generic_args) => { + Type::Struct(_, generic_args) + | Type::Alias(_, generic_args) + | Type::TraitAsType(_, _, generic_args) => { generic_args.iter().any(|arg| arg.occurs(target_id)) } Type::Tuple(fields) => fields.iter().any(|field| field.occurs(target_id)), @@ -1637,7 +1647,6 @@ impl Type { | Type::Integer(_, _) | Type::Bool | Type::Constant(_) - | Type::TraitAsType(..) | Type::Error | Type::Code | Type::Unit => false, @@ -1689,16 +1698,14 @@ impl Type { MutableReference(element) => MutableReference(Box::new(element.follow_bindings())), + TraitAsType(s, name, args) => { + let args = vecmap(args, |arg| arg.follow_bindings()); + TraitAsType(*s, name.clone(), args) + } + // Expect that this function should only be called on instantiated types Forall(..) => unreachable!(), - TraitAsType(..) - | FieldElement - | Integer(_, _) - | Bool - | Constant(_) - | Unit - | Code - | Error => self.clone(), + FieldElement | Integer(_, _) | Bool | Constant(_) | Unit | Code | Error => self.clone(), } } @@ -1780,7 +1787,7 @@ impl From<&Type> for PrintableType { match value { Type::FieldElement => PrintableType::Field, Type::Array(size, typ) => { - let length = size.evaluate_to_u64(); + let length = size.evaluate_to_u64().expect("Cannot print variable sized arrays"); let typ = typ.as_ref(); PrintableType::Array { length, typ: Box::new(typ.into()) } } diff --git a/compiler/noirc_frontend/src/lexer/errors.rs b/compiler/noirc_frontend/src/lexer/errors.rs index 35a07c11e0a..73c75af4cd7 100644 --- a/compiler/noirc_frontend/src/lexer/errors.rs +++ b/compiler/noirc_frontend/src/lexer/errors.rs @@ -96,8 +96,8 @@ impl LexerErrorKind { } } -impl From for Diagnostic { - fn from(error: LexerErrorKind) -> Diagnostic { +impl<'a> From<&'a LexerErrorKind> for Diagnostic { + fn from(error: &'a LexerErrorKind) -> Diagnostic { let (primary, secondary, span) = error.parts(); Diagnostic::simple_error(primary, secondary, span) } diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index 0242fc7e7ff..ebbc7fc9813 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -581,6 +581,10 @@ impl Attributes { pub fn is_foldable(&self) -> bool { self.function.as_ref().map_or(false, |func_attribute| func_attribute.is_foldable()) } + + pub fn is_no_predicates(&self) -> bool { + self.function.as_ref().map_or(false, |func_attribute| func_attribute.is_no_predicates()) + } } /// An Attribute can be either a Primary Attribute or a Secondary Attribute @@ -641,6 +645,7 @@ impl Attribute { ["test"] => Attribute::Function(FunctionAttribute::Test(TestScope::None)), ["recursive"] => Attribute::Function(FunctionAttribute::Recursive), ["fold"] => Attribute::Function(FunctionAttribute::Fold), + ["no_predicates"] => Attribute::Function(FunctionAttribute::NoPredicates), ["test", name] => { validate(name)?; let malformed_scope = @@ -693,6 +698,7 @@ pub enum FunctionAttribute { Test(TestScope), Recursive, Fold, + NoPredicates, } impl FunctionAttribute { @@ -725,6 +731,13 @@ impl FunctionAttribute { pub fn is_foldable(&self) -> bool { matches!(self, FunctionAttribute::Fold) } + + /// Check whether we have an `inline` attribute + /// Although we also do not want to inline foldable functions, + /// we keep the two attributes distinct for clarity. + pub fn is_no_predicates(&self) -> bool { + matches!(self, FunctionAttribute::NoPredicates) + } } impl fmt::Display for FunctionAttribute { @@ -736,6 +749,7 @@ impl fmt::Display for FunctionAttribute { FunctionAttribute::Oracle(ref k) => write!(f, "#[oracle({k})]"), FunctionAttribute::Recursive => write!(f, "#[recursive]"), FunctionAttribute::Fold => write!(f, "#[fold]"), + FunctionAttribute::NoPredicates => write!(f, "#[no_predicates]"), } } } @@ -781,6 +795,7 @@ impl AsRef for FunctionAttribute { FunctionAttribute::Test { .. } => "", FunctionAttribute::Recursive => "", FunctionAttribute::Fold => "", + FunctionAttribute::NoPredicates => "", } } } diff --git a/compiler/noirc_frontend/src/lib.rs b/compiler/noirc_frontend/src/lib.rs index 6c77e3d0545..958a18ac2fb 100644 --- a/compiler/noirc_frontend/src/lib.rs +++ b/compiler/noirc_frontend/src/lib.rs @@ -50,7 +50,7 @@ pub mod macros_api { pub use crate::token::SecondaryAttribute; pub use crate::ast::{ - BlockExpression, CallExpression, CastExpression, Distinctness, Expression, ExpressionKind, + BlockExpression, CallExpression, CastExpression, Expression, ExpressionKind, FunctionReturnType, Ident, IndexExpression, ItemVisibility, LetStatement, Literal, MemberAccessExpression, MethodCallExpression, NoirFunction, Path, PathKind, Pattern, Statement, UnresolvedType, UnresolvedTypeData, Visibility, diff --git a/compiler/noirc_frontend/src/monomorphization/ast.rs b/compiler/noirc_frontend/src/monomorphization/ast.rs index 434cc922a05..15c27ee344c 100644 --- a/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -5,8 +5,13 @@ use noirc_errors::{ Location, }; -use crate::ast::{BinaryOpKind, Distinctness, IntegerBitSize, Signedness, Visibility}; use crate::hir_def::function::FunctionSignature; +use crate::{ + ast::{BinaryOpKind, IntegerBitSize, Signedness, Visibility}, + token::{Attributes, FunctionAttribute}, +}; + +use super::HirType; /// The monomorphized AST is expression-based, all statements are also /// folded into this expression enum. Compared to the HIR, the monomorphized @@ -33,7 +38,7 @@ pub enum Expression { ExtractTupleField(Box, usize), Call(Call), Let(Let), - Constrain(Box, Location, Option>), + Constrain(Box, Location, Option>), Assign(Assign), Semi(Box), Break, @@ -200,6 +205,57 @@ pub enum LValue { pub type Parameters = Vec<(LocalId, /*mutable:*/ bool, /*name:*/ String, Type)>; +/// Represents how an Acir function should be inlined. +/// This type is only relevant for ACIR functions as we do not inline any Brillig functions +#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum InlineType { + /// The most basic entry point can expect all its functions to be inlined. + /// All function calls are expected to be inlined into a single ACIR. + #[default] + Inline, + /// Functions marked as foldable will not be inlined and compiled separately into ACIR + Fold, + /// Functions marked to have no predicates will not be inlined in the default inlining pass + /// and will be separately inlined after the flattening pass. + /// They are different from `Fold` as they are expected to be inlined into the program + /// entry point before being used in the backend. + /// This attribute is unsafe and can cause a function whose logic relies on predicates from + /// the flattening pass to fail. + NoPredicates, +} + +impl From<&Attributes> for InlineType { + fn from(attributes: &Attributes) -> Self { + attributes.function.as_ref().map_or(InlineType::default(), |func_attribute| { + match func_attribute { + FunctionAttribute::Fold => InlineType::Fold, + FunctionAttribute::NoPredicates => InlineType::NoPredicates, + _ => InlineType::default(), + } + }) + } +} + +impl InlineType { + pub fn is_entry_point(&self) -> bool { + match self { + InlineType::Inline => false, + InlineType::Fold => true, + InlineType::NoPredicates => false, + } + } +} + +impl std::fmt::Display for InlineType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + InlineType::Inline => write!(f, "inline"), + InlineType::Fold => write!(f, "fold"), + InlineType::NoPredicates => write!(f, "no_predicates"), + } + } +} + #[derive(Debug, Clone, Hash)] pub struct Function { pub id: FuncId, @@ -210,7 +266,7 @@ pub struct Function { pub return_type: Type, pub unconstrained: bool, - pub should_fold: bool, + pub inline_type: InlineType, pub func_sig: FunctionSignature, } @@ -248,11 +304,6 @@ pub struct Program { pub functions: Vec, pub function_signatures: Vec, pub main_function_signature: FunctionSignature, - /// Indicates whether witness indices are allowed to reoccur in the ABI of the resulting ACIR. - /// - /// Note: this has no impact on monomorphization, and is simply attached here for ease of - /// forwarding to the next phase. - pub return_distinctness: Distinctness, pub return_location: Option, pub return_visibility: Visibility, /// Indicates to a backend whether a SNARK-friendly prover should be used. @@ -268,7 +319,6 @@ impl Program { functions: Vec, function_signatures: Vec, main_function_signature: FunctionSignature, - return_distinctness: Distinctness, return_location: Option, return_visibility: Visibility, recursive: bool, @@ -280,7 +330,6 @@ impl Program { functions, function_signatures, main_function_signature, - return_distinctness, return_location, return_visibility, recursive, diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index b130af9d125..f918610af2c 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -30,6 +30,7 @@ use std::{ unreachable, }; +use self::ast::InlineType; use self::debug_types::DebugTypeTracker; use self::{ ast::{Definition, FuncId, Function, LocalId, Program}, @@ -132,7 +133,7 @@ pub fn monomorphize_debug( .finished_functions .iter() .flat_map(|(_, f)| { - if f.should_fold || f.id == Program::main_id() { + if f.inline_type.is_entry_point() || f.id == Program::main_id() { Some(f.func_sig.clone()) } else { None @@ -141,8 +142,7 @@ pub fn monomorphize_debug( .collect(); let functions = vecmap(monomorphizer.finished_functions, |(_, f)| f); - let FuncMeta { return_distinctness, return_visibility, kind, .. } = - monomorphizer.interner.function_meta(&main); + let FuncMeta { return_visibility, kind, .. } = monomorphizer.interner.function_meta(&main); let (debug_variables, debug_functions, debug_types) = monomorphizer.debug_type_tracker.extract_vars_and_types(); @@ -150,7 +150,6 @@ pub fn monomorphize_debug( functions, func_sigs, function_sig, - *return_distinctness, monomorphizer.return_location, *return_visibility, *kind == FunctionKind::Recursive, @@ -304,7 +303,8 @@ impl<'interner> Monomorphizer<'interner> { let return_type = Self::convert_type(return_type, meta.location)?; let unconstrained = modifiers.is_unconstrained; - let should_fold = meta.should_fold; + let attributes = self.interner.function_attributes(&f); + let inline_type = InlineType::from(attributes); let parameters = self.parameters(&meta.parameters)?; let body = self.expr(body_expr_id)?; @@ -315,7 +315,7 @@ impl<'interner> Monomorphizer<'interner> { body, return_type, unconstrained, - should_fold, + inline_type, func_sig, }; @@ -593,7 +593,11 @@ impl<'interner> Monomorphizer<'interner> { let location = self.interner.expr_location(&constrain.0); let assert_message = constrain .2 - .map(|assert_msg_expr| self.expr(assert_msg_expr)) + .map(|assert_msg_expr| { + self.expr(assert_msg_expr).map(|expr| { + (expr, self.interner.id_type(assert_msg_expr).follow_bindings()) + }) + }) .transpose()? .map(Box::new); Ok(ast::Expression::Constrain(Box::new(expr), location, assert_message)) @@ -1100,9 +1104,6 @@ impl<'interner> Monomorphizer<'interner> { // The first argument to the `print` oracle is a bool, indicating a newline to be inserted at the end of the input // The second argument is expected to always be an ident self.append_printable_type_info(&hir_arguments[1], &mut arguments); - } else if name.as_str() == "assert_message" { - // The first argument to the `assert_message` oracle is the expression passed as a message to an `assert` or `assert_eq` statement - self.append_printable_type_info(&hir_arguments[0], &mut arguments); } } } @@ -1398,7 +1399,7 @@ impl<'interner> Monomorphizer<'interner> { body, return_type, unconstrained, - should_fold: false, + inline_type: InlineType::default(), func_sig: FunctionSignature::default(), }; self.push_function(id, function); @@ -1524,7 +1525,7 @@ impl<'interner> Monomorphizer<'interner> { body, return_type, unconstrained, - should_fold: false, + inline_type: InlineType::default(), func_sig: FunctionSignature::default(), }; self.push_function(id, function); @@ -1649,7 +1650,7 @@ impl<'interner> Monomorphizer<'interner> { body, return_type, unconstrained, - should_fold: false, + inline_type: InlineType::default(), func_sig: FunctionSignature::default(), }; self.push_function(id, function); diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 9d3a79820dc..88adc7a9414 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -1,10 +1,11 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::fmt; use std::ops::Deref; -use arena::{Arena, Index}; use fm::FileId; use iter_extended::vecmap; +use noirc_arena::{Arena, Index}; use noirc_errors::{Location, Span, Spanned}; use petgraph::algo::tarjan_scc; use petgraph::prelude::DiGraph; @@ -314,6 +315,12 @@ impl FuncId { } } +impl fmt::Display for FuncId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, PartialOrd, Ord)] pub struct StructId(ModuleId); @@ -653,11 +660,13 @@ impl NodeInterner { let_statement: StmtId, file: FileId, attributes: Vec, + mutable: bool, ) -> GlobalId { let id = GlobalId(self.globals.len()); let location = Location::new(ident.span(), file); let name = ident.to_string(); - let definition_id = self.push_definition(name, false, DefinitionKind::Global(id), location); + let definition_id = + self.push_definition(name, mutable, DefinitionKind::Global(id), location); self.globals.push(GlobalInfo { id, @@ -682,9 +691,13 @@ impl NodeInterner { local_id: LocalModuleId, file: FileId, attributes: Vec, + mutable: bool, ) -> GlobalId { let statement = self.push_stmt(HirStatement::Error); - self.push_global(name, local_id, statement, file, attributes) + let span = name.span(); + let id = self.push_global(name, local_id, statement, file, attributes, mutable); + self.push_statement_location(statement, span, file); + id } /// Intern an empty function. diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index 407b69c818b..9f9a8200954 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -30,6 +30,8 @@ pub enum ParserErrorReason { TraitImplFunctionModifiers, #[error("comptime keyword is deprecated")] ComptimeDeprecated, + #[error("distinct keyword is deprecated. The `distinct` behavior is now the default.")] + DistinctDeprecated, #[error("{0} are experimental and aren't fully supported yet")] ExperimentalFeature(&'static str), #[error( @@ -112,7 +114,7 @@ impl std::fmt::Display for ParserError { let reason_str: String = if self.reason.is_none() { "".to_string() } else { - format!("\nreason: {}", Diagnostic::from(self.clone())) + format!("\nreason: {}", Diagnostic::from(self)) }; let mut expected = vecmap(&self.expected_tokens, ToString::to_string); expected.append(&mut vecmap(&self.expected_labels, |label| format!("{label}"))); @@ -138,9 +140,9 @@ impl std::fmt::Display for ParserError { } } -impl From for Diagnostic { - fn from(error: ParserError) -> Diagnostic { - match error.reason { +impl<'a> From<&'a ParserError> for Diagnostic { + fn from(error: &'a ParserError) -> Diagnostic { + match &error.reason { Some(reason) => { match reason { ParserErrorReason::ConstrainDeprecated => Diagnostic::simple_error( diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index 6e9f3969297..b627714d2a6 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -33,10 +33,10 @@ use super::{ }; use super::{spanned, Item, ItemKind}; use crate::ast::{ - BinaryOp, BinaryOpKind, BlockExpression, Distinctness, ForLoopStatement, ForRange, - FunctionReturnType, Ident, IfExpression, InfixExpression, LValue, Literal, ModuleDeclaration, - NoirTypeAlias, Param, Path, Pattern, Recoverable, Statement, TraitBound, TypeImpl, - UnresolvedTraitConstraint, UnresolvedTypeExpression, UseTree, UseTreeKind, Visibility, + BinaryOp, BinaryOpKind, BlockExpression, ForLoopStatement, ForRange, Ident, IfExpression, + InfixExpression, LValue, Literal, ModuleDeclaration, NoirTypeAlias, Param, Path, Pattern, + Recoverable, Statement, TraitBound, TypeImpl, UnresolvedTraitConstraint, + UnresolvedTypeExpression, UseTree, UseTreeKind, Visibility, }; use crate::ast::{ Expression, ExpressionKind, LetStatement, StatementKind, UnresolvedType, UnresolvedTypeData, @@ -235,16 +235,27 @@ fn implementation() -> impl NoirParser { fn global_declaration() -> impl NoirParser { let p = attributes::attributes() .then(maybe_comp_time()) + .then(spanned(keyword(Keyword::Mut)).or_not()) .then_ignore(keyword(Keyword::Global).labelled(ParsingRuleLabel::Global)) .then(ident().map(Pattern::Identifier)); let p = then_commit(p, optional_type_annotation()); let p = then_commit_ignore(p, just(Token::Assign)); let p = then_commit(p, expression()); - p.validate(|((((attributes, comptime), pattern), r#type), expression), span, emit| { - let global_attributes = attributes::validate_secondary_attributes(attributes, span, emit); - LetStatement { pattern, r#type, comptime, expression, attributes: global_attributes } - }) + p.validate( + |(((((attributes, comptime), mutable), mut pattern), r#type), expression), span, emit| { + let global_attributes = + attributes::validate_secondary_attributes(attributes, span, emit); + + // Only comptime globals are allowed to be mutable, but we always parse the `mut` + // and throw the error in name resolution. + if let Some((_, mut_span)) = mutable { + let span = mut_span.merge(pattern.span()); + pattern = Pattern::Mutable(Box::new(pattern), span, false); + } + LetStatement { pattern, r#type, comptime, expression, attributes: global_attributes } + }, + ) .map(TopLevelStatement::Global) } @@ -285,21 +296,6 @@ fn type_alias_definition() -> impl NoirParser { }) } -fn function_return_type() -> impl NoirParser<((Distinctness, Visibility), FunctionReturnType)> { - just(Token::Arrow) - .ignore_then(optional_distinctness()) - .then(optional_visibility()) - .then(spanned(parse_type())) - .or_not() - .map_with_span(|ret, span| match ret { - Some((head, (ty, _))) => (head, FunctionReturnType::Ty(ty)), - None => ( - (Distinctness::DuplicationAllowed, Visibility::Private), - FunctionReturnType::Default(span), - ), - }) -} - fn self_parameter() -> impl NoirParser { let mut_ref_pattern = just(Token::Ampersand).then_ignore(keyword(Keyword::Mut)); let mut_pattern = keyword(Keyword::Mut); @@ -532,15 +528,16 @@ where P2: ExprParser + 'a, S: NoirParser + 'a, { - keyword(Keyword::Comptime) - .ignore_then(choice(( - declaration(expr), - for_loop(expr_no_constructors, statement.clone()), - block(statement).map_with_span(|block, span| { - StatementKind::Expression(Expression::new(ExpressionKind::Block(block), span)) - }), - ))) - .map(|statement| StatementKind::Comptime(Box::new(statement))) + let comptime_statement = choice(( + declaration(expr), + for_loop(expr_no_constructors, statement.clone()), + block(statement).map_with_span(|block, span| { + StatementKind::Expression(Expression::new(ExpressionKind::Block(block), span)) + }), + )) + .map_with_span(|kind, span| Box::new(Statement { kind, span })); + + keyword(Keyword::Comptime).ignore_then(comptime_statement).map(StatementKind::Comptime) } /// Comptime in an expression position only accepts entire blocks @@ -725,18 +722,11 @@ fn optional_visibility() -> impl NoirParser { }) } -fn optional_distinctness() -> impl NoirParser { - keyword(Keyword::Distinct).or_not().map(|opt| match opt { - Some(_) => Distinctness::Distinct, - None => Distinctness::DuplicationAllowed, - }) -} - fn maybe_comp_time() -> impl NoirParser { keyword(Keyword::Comptime).or_not().validate(|opt, span, emit| { if opt.is_some() { emit(ParserError::with_reason( - ParserErrorReason::ExperimentalFeature("comptime"), + ParserErrorReason::ExperimentalFeature("Comptime values"), span, )); } diff --git a/compiler/noirc_frontend/src/parser/parser/function.rs b/compiler/noirc_frontend/src/parser/parser/function.rs index f39b2ad6292..40180a9f9ac 100644 --- a/compiler/noirc_frontend/src/parser/parser/function.rs +++ b/compiler/noirc_frontend/src/parser/parser/function.rs @@ -1,16 +1,19 @@ use super::{ attributes::{attributes, validate_attributes}, - block, fresh_statement, ident, keyword, maybe_comp_time, nothing, optional_distinctness, - optional_visibility, parameter_name_recovery, parameter_recovery, parenthesized, parse_type, - pattern, self_parameter, where_clause, NoirParser, -}; -use crate::ast::{ - Distinctness, FunctionDefinition, FunctionReturnType, Ident, ItemVisibility, NoirFunction, - Param, Visibility, + block, fresh_statement, ident, keyword, maybe_comp_time, nothing, optional_visibility, + parameter_name_recovery, parameter_recovery, parenthesized, parse_type, pattern, + self_parameter, where_clause, NoirParser, }; use crate::parser::labels::ParsingRuleLabel; use crate::parser::spanned; use crate::token::{Keyword, Token}; +use crate::{ + ast::{ + FunctionDefinition, FunctionReturnType, Ident, ItemVisibility, NoirFunction, Param, + Visibility, + }, + parser::{ParserError, ParserErrorReason}, +}; use chumsky::prelude::*; @@ -43,8 +46,7 @@ pub(super) fn function_definition(allow_self: bool) -> impl NoirParser impl NoirParser> { .map(|opt| opt.unwrap_or_default()) } -fn function_return_type() -> impl NoirParser<((Distinctness, Visibility), FunctionReturnType)> { +#[deprecated = "Distinct keyword is now deprecated. Remove this function after the 0.30.0 release"] +fn optional_distinctness() -> impl NoirParser { + keyword(Keyword::Distinct).or_not().validate(|opt, span, emit| { + if opt.is_some() { + emit(ParserError::with_reason(ParserErrorReason::DistinctDeprecated, span)); + } + opt.is_some() + }) +} + +pub(super) fn function_return_type() -> impl NoirParser<(Visibility, FunctionReturnType)> { + #[allow(deprecated)] just(Token::Arrow) .ignore_then(optional_distinctness()) - .then(optional_visibility()) + .ignore_then(optional_visibility()) .then(spanned(parse_type())) .or_not() .map_with_span(|ret, span| match ret { - Some((head, (ty, _))) => (head, FunctionReturnType::Ty(ty)), - None => ( - (Distinctness::DuplicationAllowed, Visibility::Private), - FunctionReturnType::Default(span), - ), + Some((visibility, (ty, _))) => (visibility, FunctionReturnType::Ty(ty)), + None => (Visibility::Private, FunctionReturnType::Default(span)), }) } @@ -174,7 +184,7 @@ mod test { "fn f(f: pub Field, y : Field, z : Field) -> u8 { x + a }", "fn f(f: pub Field, y : T, z : Field) -> u8 { x + a }", "fn func_name(x: [Field], y : [Field;2],y : pub [Field;2], z : pub [u8;5]) {}", - "fn main(x: pub u8, y: pub u8) -> distinct pub [u8; 2] { [x, y] }", + "fn main(x: pub u8, y: pub u8) -> pub [u8; 2] { [x, y] }", "fn f(f: pub Field, y : Field, z : Field) -> u8 { x + a }", "fn f(f: pub Field, y : T, z : Field) -> u8 { x + a }", "fn func_name(f: Field, y : T) where T: SomeTrait {}", @@ -193,6 +203,11 @@ mod test { "fn func_name(f: Field, y : T) where T: SomeTrait + {}", // The following should produce compile error on later stage. From the parser's perspective it's fine "fn func_name(f: Field, y : Field, z : Field) where T: SomeTrait {}", + // TODO: this fails with known EOF != EOF error + // https://github.com/noir-lang/noir/issues/4763 + // fn func_name(x: impl Eq) {} with error Expected an end of input but found end of input + // "fn func_name(x: impl Eq) {}", + "fn func_name(x: impl Eq, y : T) where T: SomeTrait + Eq {}", ], ); @@ -209,6 +224,8 @@ mod test { // A leading plus is not allowed. "fn func_name(f: Field, y : T) where T: + SomeTrait {}", "fn func_name(f: Field, y : T) where T: TraitX + {}", + // `distinct` is deprecated + "fn main(x: pub u8, y: pub u8) -> distinct pub [u8; 2] { [x, y] }", ], ); } diff --git a/compiler/noirc_frontend/src/parser/parser/test_helpers.rs b/compiler/noirc_frontend/src/parser/parser/test_helpers.rs index 6b8cb80a0a0..83c1e148f0e 100644 --- a/compiler/noirc_frontend/src/parser/parser/test_helpers.rs +++ b/compiler/noirc_frontend/src/parser/parser/test_helpers.rs @@ -15,9 +15,9 @@ where { let (tokens, lexer_errors) = Lexer::lex(program); if !lexer_errors.is_empty() { - return Err(vecmap(lexer_errors, Into::into)); + return Err(vecmap(&lexer_errors, Into::into)); } - parser.then_ignore(just(Token::EOF)).parse(tokens).map_err(|errors| vecmap(errors, Into::into)) + parser.then_ignore(just(Token::EOF)).parse(tokens).map_err(|errors| vecmap(&errors, Into::into)) } pub(crate) fn parse_recover(parser: P, program: &str) -> (Option, Vec) @@ -27,8 +27,8 @@ where let (tokens, lexer_errors) = Lexer::lex(program); let (opt, errs) = parser.then_ignore(force(just(Token::EOF))).parse_recovery(tokens); - let mut errors = vecmap(lexer_errors, Into::into); - errors.extend(errs.into_iter().map(Into::into)); + let mut errors = vecmap(&lexer_errors, Into::into); + errors.extend(errs.iter().map(Into::into)); (opt, errors) } diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index 0507dbdbc71..1aec57c8e41 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -1,9 +1,7 @@ use chumsky::prelude::*; -use super::{ - block, expression, fresh_statement, function, function_declaration_parameters, - function_return_type, -}; +use super::function::function_return_type; +use super::{block, expression, fresh_statement, function, function_declaration_parameters}; use crate::ast::{ Expression, ItemVisibility, NoirTrait, NoirTraitImpl, TraitBound, TraitImplItem, TraitItem, diff --git a/compiler/noirc_frontend/src/resolve_locations.rs b/compiler/noirc_frontend/src/resolve_locations.rs index b5f1b1d0c64..ac8c96a092e 100644 --- a/compiler/noirc_frontend/src/resolve_locations.rs +++ b/compiler/noirc_frontend/src/resolve_locations.rs @@ -1,4 +1,4 @@ -use arena::Index; +use noirc_arena::Index; use noirc_errors::Location; use crate::hir_def::expr::HirExpression; diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 31bf2245b1f..5f99e9e347a 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -31,8 +31,8 @@ mod test { hir::def_map::{CrateDefMap, LocalModuleId}, parse_program, }; - use arena::Arena; use fm::FileManager; + use noirc_arena::Arena; pub(crate) fn has_parser_error(errors: &[(CompilationError, FileId)]) -> bool { errors.iter().any(|(e, _f)| matches!(e, CompilationError::ParseError(_))) @@ -746,6 +746,91 @@ mod test { } } + #[test] + fn test_impl_self_within_default_def() { + let src = " + trait Bar { + fn ok(self) -> Self; + + fn ref_ok(self) -> Self { + self.ok() + } + } + + impl Bar for (T, T) where T: Bar { + fn ok(self) -> Self { + self + } + }"; + let errors = get_program_errors(src); + errors.iter().for_each(|err| println!("{:?}", err)); + assert!(errors.is_empty()); + } + + #[test] + fn check_trait_as_type_as_fn_parameter() { + let src = " + trait Eq { + fn eq(self, other: Self) -> bool; + } + + struct Foo { + a: u64, + } + + impl Eq for Foo { + fn eq(self, other: Foo) -> bool { self.a == other.a } + } + + fn test_eq(x: impl Eq) -> bool { + x.eq(x) + } + + fn main(a: Foo) -> pub bool { + test_eq(a) + }"; + + let errors = get_program_errors(src); + errors.iter().for_each(|err| println!("{:?}", err)); + assert!(errors.is_empty()); + } + + #[test] + fn check_trait_as_type_as_two_fn_parameters() { + let src = " + trait Eq { + fn eq(self, other: Self) -> bool; + } + + trait Test { + fn test(self) -> bool; + } + + struct Foo { + a: u64, + } + + impl Eq for Foo { + fn eq(self, other: Foo) -> bool { self.a == other.a } + } + + impl Test for u64 { + fn test(self) -> bool { self == self } + } + + fn test_eq(x: impl Eq, y: impl Test) -> bool { + x.eq(x) == y.test() + } + + fn main(a: Foo, b: u64) -> pub bool { + test_eq(a, b) + }"; + + let errors = get_program_errors(src); + errors.iter().for_each(|err| println!("{:?}", err)); + assert!(errors.is_empty()); + } + fn get_program_captures(src: &str) -> Vec> { let (program, context, _errors) = get_program(src); let interner = context.def_interner; @@ -1167,7 +1252,7 @@ fn lambda$f1(mut env$l1: (Field)) -> Field { } #[test] - fn deny_cyclic_structs() { + fn deny_mutually_recursive_structs() { let src = r#" struct Foo { bar: Bar } struct Bar { foo: Foo } @@ -1282,4 +1367,48 @@ fn lambda$f1(mut env$l1: (Field)) -> Field { "#; assert_eq!(get_program_errors(src).len(), 0); } + + #[test] + fn ban_mutable_globals() { + // Mutable globals are only allowed in a comptime context + let src = r#" + mut global FOO: Field = 0; + fn main() {} + "#; + assert_eq!(get_program_errors(src).len(), 1); + } + + #[test] + fn deny_inline_attribute_on_unconstrained() { + let src = r#" + #[no_predicates] + unconstrained fn foo(x: Field, y: Field) { + assert(x != y); + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + assert!(matches!( + errors[0].0, + CompilationError::ResolverError( + ResolverError::NoPredicatesAttributeOnUnconstrained { .. } + ) + )); + } + + #[test] + fn deny_fold_attribute_on_unconstrained() { + let src = r#" + #[fold] + unconstrained fn foo(x: Field, y: Field) { + assert(x != y); + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + assert!(matches!( + errors[0].0, + CompilationError::ResolverError(ResolverError::FoldAttributeOnUnconstrained { .. }) + )); + } } diff --git a/compiler/noirc_printable_type/src/lib.rs b/compiler/noirc_printable_type/src/lib.rs index b9240203a5e..cc0dbca247e 100644 --- a/compiler/noirc_printable_type/src/lib.rs +++ b/compiler/noirc_printable_type/src/lib.rs @@ -11,7 +11,7 @@ use thiserror::Error; pub enum PrintableType { Field, Array { - length: Option, + length: u64, #[serde(rename = "type")] typ: Box, }, @@ -186,7 +186,8 @@ fn to_string(value: &PrintableValue, typ: &PrintableType) -> Option { (_, PrintableType::MutableReference { .. }) => { output.push_str("<>"); } - (PrintableValue::Vec { array_elements, is_slice }, PrintableType::Array { typ, .. }) => { + (PrintableValue::Vec { array_elements, is_slice }, PrintableType::Array { typ, .. }) + | (PrintableValue::Vec { array_elements, is_slice }, PrintableType::Slice { typ }) => { if *is_slice { output.push('&') } @@ -317,19 +318,7 @@ pub fn decode_value( PrintableValue::Field(field_element) } - PrintableType::Array { length: None, typ } => { - let length = field_iterator - .next() - .expect("not enough data to decode variable array length") - .to_u128() as usize; - let mut array_elements = Vec::with_capacity(length); - for _ in 0..length { - array_elements.push(decode_value(field_iterator, typ)); - } - - PrintableValue::Vec { array_elements, is_slice: false } - } - PrintableType::Array { length: Some(length), typ } => { + PrintableType::Array { length, typ } => { let length = *length as usize; let mut array_elements = Vec::with_capacity(length); for _ in 0..length { diff --git a/compiler/wasm/package.json b/compiler/wasm/package.json index 3bcf60afbe8..bccf937219e 100644 --- a/compiler/wasm/package.json +++ b/compiler/wasm/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.27.0", + "version": "0.29.0", "license": "(MIT OR Apache-2.0)", "main": "dist/main.js", "types": "./dist/types/src/index.d.cts", diff --git a/docs/docs/noir/concepts/ops.md b/docs/docs/noir/concepts/ops.md index 60425cb8994..c35c36c38a9 100644 --- a/docs/docs/noir/concepts/ops.md +++ b/docs/docs/noir/concepts/ops.md @@ -30,8 +30,8 @@ sidebar_position: 3 | ^ | XOR two private input types together | Types must be integer | | & | AND two private input types together | Types must be integer | | \| | OR two private input types together | Types must be integer | -| \<\< | Left shift an integer by another integer amount | Types must be integer | -| >> | Right shift an integer by another integer amount | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer, shift must be u8 | +| >> | Right shift an integer by another integer amount | Types must be integer, shift must be u8 | | ! | Bitwise not of a value | Type must be integer or boolean | | \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | | \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | diff --git a/docs/docs/noir/standard_library/black_box_fns.md b/docs/docs/noir/standard_library/black_box_fns.md index be8c65679c3..eeead580969 100644 --- a/docs/docs/noir/standard_library/black_box_fns.md +++ b/docs/docs/noir/standard_library/black_box_fns.md @@ -12,6 +12,7 @@ The ACVM spec defines a set of blackbox functions which backends will be expecte Here is a list of the current black box functions: +- [AES128](./cryptographic_primitives/ciphers.mdx#aes128) - [SHA256](./cryptographic_primitives/hashes.mdx#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr.mdx) - [Blake2s](./cryptographic_primitives/hashes.mdx#blake2s) @@ -19,7 +20,7 @@ Here is a list of the current black box functions: - [Pedersen Hash](./cryptographic_primitives/hashes.mdx#pedersen_hash) - [Pedersen Commitment](./cryptographic_primitives/hashes.mdx#pedersen_commitment) - [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification.mdx) -- [Fixed base scalar multiplication](./cryptographic_primitives/scalar.mdx) +- [Embedded curve operations (MSM, addition, ...)](./cryptographic_primitives/embedded_curve_ops.mdx) - AND - XOR - RANGE diff --git a/docs/docs/noir/standard_library/containers/boundedvec.md b/docs/docs/noir/standard_library/containers/boundedvec.md index cd0f725f870..ccce62562f8 100644 --- a/docs/docs/noir/standard_library/containers/boundedvec.md +++ b/docs/docs/noir/standard_library/containers/boundedvec.md @@ -196,6 +196,20 @@ Example: #include_code bounded-vec-extend-from-bounded-vec-example test_programs/noir_test_success/bounded_vec/src/main.nr rust +### from_array + +```rust +pub fn from_array(array: [T; Len]) -> Self +``` + +Creates a new vector, populating it with values derived from an array input. +The maximum length of the vector is determined based on the type signature. + +Example: +```rust +let bounded_vec: BoundedVec = BoundedVec::from_array([1, 2, 3]) +``` + ### any ```rust diff --git a/docs/docs/noir/standard_library/cryptographic_primitives/ciphers.mdx b/docs/docs/noir/standard_library/cryptographic_primitives/ciphers.mdx new file mode 100644 index 00000000000..0103791d2e4 --- /dev/null +++ b/docs/docs/noir/standard_library/cryptographic_primitives/ciphers.mdx @@ -0,0 +1,28 @@ +--- +title: Ciphers +description: + Learn about the implemented ciphers ready to use for any Noir project +keywords: + [ciphers, Noir project, aes128, encrypt] +sidebar_position: 0 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## aes128 + +Given a plaintext as an array of bytes, returns the corresponding aes128 ciphertext (CBC mode). Input padding is automatically performed using PKCS#7, so that the output length is `input.len() + (16 - input.len() % 16)`. + +#include_code aes128 noir_stdlib/src/aes128.nr rust + +```rust +fn main() { + let input: [u8; 4] = [0, 12, 3, 15] // Random bytes, will be padded to 16 bytes. + let iv: [u8; 16] = [0; 16]; // Initialisation vector + let key: [u8; 16] = [0; 16] // AES key + let ciphertext = std::aes128::aes128_encrypt(inputs.as_bytes(), iv.as_bytes(), key.as_bytes()); // In this case, the output length will be 16 bytes. +} +``` + + + \ No newline at end of file diff --git a/docs/docs/noir/standard_library/cryptographic_primitives/embedded_curve_ops.mdx b/docs/docs/noir/standard_library/cryptographic_primitives/embedded_curve_ops.mdx new file mode 100644 index 00000000000..f1122fc37d5 --- /dev/null +++ b/docs/docs/noir/standard_library/cryptographic_primitives/embedded_curve_ops.mdx @@ -0,0 +1,77 @@ +--- +title: Scalar multiplication +description: See how you can perform scalar multiplication in Noir +keywords: [cryptographic primitives, Noir project, scalar multiplication] +sidebar_position: 1 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +The following functions perform operations over the embedded curve whose coordinates are defined by the configured noir field. +For the BN254 scalar field, this is BabyJubJub or Grumpkin. + +:::note +Suffixes `_low` and `_high` denote low and high limbs of a scalar. +::: + +## embedded_curve_ops::multi_scalar_mul + +Performs multi scalar multiplication over the embedded curve. +The function accepts arbitrary amount of point-scalar pairs on the input, it multiplies the individual pairs over +the curve and returns a sum of the resulting points. + +Points represented as x and y coordinates [x1, y1, x2, y2, ...], scalars as low and high limbs [low1, high1, low2, high2, ...]. + +#include_code multi_scalar_mul noir_stdlib/src/embedded_curve_ops.nr rust + +example + +```rust +fn main(point_x: Field, point_y: Field, scalar_low: Field, scalar_high: Field) { + let point = std::embedded_curve_ops::multi_scalar_mul([point_x, point_y], [scalar_low, scalar_high]); + println(point); +} +``` + +## embedded_curve_ops::fixed_base_scalar_mul + +Performs fixed base scalar multiplication over the embedded curve (multiplies input scalar with a generator point). +The function accepts a single scalar on the input represented as 2 fields. + +#include_code fixed_base_scalar_mul noir_stdlib/src/embedded_curve_ops.nr rust + +example + +```rust +fn main(scalar_low: Field, scalar_high: Field) { + let point = std::embedded_curve_ops::fixed_base_scalar_mul(scalar_low, scalar_high); + println(point); +} +``` + +## embedded_curve_ops::embedded_curve_add + +Adds two points on the embedded curve. +This function takes two `EmbeddedCurvePoint` structures as parameters, representing points on the curve, and returns a new `EmbeddedCurvePoint` structure that represents their sum. + +### Parameters: +- `point1` (`EmbeddedCurvePoint`): The first point to add. +- `point2` (`EmbeddedCurvePoint`): The second point to add. + +### Returns: +- `EmbeddedCurvePoint`: The resulting point after the addition of `point1` and `point2`. + +#include_code embedded_curve_add noir_stdlib/src/embedded_curve_ops.nr rust + +example + +```rust +fn main() { + let point1 = EmbeddedCurvePoint { x: 1, y: 2 }; + let point2 = EmbeddedCurvePoint { x: 3, y: 4 }; + let result = std::embedded_curve_ops::embedded_curve_add(point1, point2); + println!("Resulting Point: ({}, {})", result.x, result.y); +} +``` + + diff --git a/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx b/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx index 7329880c7a7..efa52b2c3f2 100644 --- a/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx +++ b/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -13,18 +13,21 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## sha256 Given an array of bytes, returns the resulting sha256 hash. +Specify a message_size to hash only the first `message_size` bytes of the input. #include_code sha256 noir_stdlib/src/hash.nr rust example: +#include_code sha256_var test_programs/execution_success/sha256/src/main.nr rust ```rust fn main() { let x = [163, 117, 178, 149]; // some random bytes - let hash = std::hash::sha256(x); + let hash = std::sha256::sha256_var(x, 4); } ``` + ## blake2s diff --git a/docs/docs/noir/standard_library/traits.md b/docs/docs/noir/standard_library/traits.md index 2536d9a943f..b32a2969563 100644 --- a/docs/docs/noir/standard_library/traits.md +++ b/docs/docs/noir/standard_library/traits.md @@ -232,6 +232,15 @@ impl Rem for i32 { fn rem(self, other: i32) -> i32 { self % other } } impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } ``` +### `std::ops::Neg` + +#include_code neg-trait noir_stdlib/src/ops.nr rust + +`Neg::neg` is equivalent to the unary negation operator `-`. + +Implementations: +#include_code neg-trait-impls noir_stdlib/src/ops.nr rust + ### `std::ops::{ BitOr, BitAnd, BitXor }` #include_code bitor-trait noir_stdlib/src/ops.nr rust diff --git a/docs/docs/tutorials/noirjs_app.md b/docs/docs/tutorials/noirjs_app.md index 6446e0b2a76..3dd9fe7d2b0 100644 --- a/docs/docs/tutorials/noirjs_app.md +++ b/docs/docs/tutorials/noirjs_app.md @@ -24,7 +24,7 @@ Before we start, we want to make sure we have Node and Nargo installed. We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). -As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: +As for `Nargo`, we can follow the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: ```sh curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 49566c5c380..2d5b8941f55 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -47,7 +47,9 @@ export default { }, ], ], - + customFields: { + MATOMO_ENV: process.env.MATOMO_ENV, + }, themeConfig: { colorMode: { respectPrefersColorScheme: true, diff --git a/docs/package.json b/docs/package.json index f9e95fc02f8..c81d0b7b24f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -4,11 +4,12 @@ "private": true, "scripts": { "preprocess": "yarn workspace @noir-lang/acvm_js build && ./scripts/codegen_nargo_reference.sh && yarn node ./scripts/preprocess/index.js", - "start": "yarn preprocess && docusaurus start", + "start": "yarn preprocess && MATOMO_ENV=dev docusaurus start", "build": "yarn preprocess && docusaurus build", "clean": "rm -rf ./processed-docs ./processed-docs ./build", "version::stables": "ts-node ./scripts/setStable.ts", "serve": "serve build", + "swizzle": "docusaurus swizzle", "version": "yarn version::stables && ./scripts/cut_version.sh" }, "dependencies": { diff --git a/docs/src/components/Matomo/matomo.jsx b/docs/src/components/Matomo/matomo.jsx new file mode 100644 index 00000000000..7ee34fc8e51 --- /dev/null +++ b/docs/src/components/Matomo/matomo.jsx @@ -0,0 +1,133 @@ +import { useEffect, useState } from 'react'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import Link from '@docusaurus/Link'; + +function getSiteId(env) { + if (env == 'dev') { + return '3'; + } else if (env == 'staging') { + return '2'; + } else { + return '1'; + } +} +function pushInstruction(name, ...args) { + return window._paq.push([name, ...args]); +} + +export default function useMatomo() { + const { siteConfig } = useDocusaurusContext(); + const [showBanner, setShowBanner] = useState(false); + + const env = siteConfig.customFields.MATOMO_ENV; + const urlBase = 'https://noirlang.matomo.cloud/'; + const trackerUrl = `${urlBase}matomo.php`; + const srcUrl = `${urlBase}matomo.js`; + + window._paq = window._paq || []; + + useEffect(() => { + const storedConsent = localStorage.getItem('matomoConsent'); + if (storedConsent === null) { + setShowBanner(true); + } + }, []); + + useEffect(() => { + pushInstruction('setTrackerUrl', trackerUrl); + pushInstruction('setSiteId', getSiteId(env)); + if (env !== 'prod') { + pushInstruction('setSecureCookie', false); + } + + const doc = document; + const scriptElement = doc.createElement('script'); + const scripts = doc.getElementsByTagName('script')[0]; + + scriptElement.type = 'text/javascript'; + scriptElement.async = true; + scriptElement.defer = true; + scriptElement.src = srcUrl; + + if (scripts && scripts.parentNode) { + scripts.parentNode.insertBefore(scriptElement, scripts); + } + }, []); + + useEffect(() => { + pushInstruction('trackPageView'); + }, [window.location.href]); + + const optIn = () => { + pushInstruction('rememberConsentGiven'); + localStorage.setItem('matomoConsent', true); + setShowBanner(false); + }; + + const optOut = () => { + pushInstruction('forgetConsentGiven'); + localStorage.setItem('matomoConsent', false); + setShowBanner(false); + }; + + const debug = () => { + pushInstruction(function () { + console.log(this.getRememberedConsent()); + console.log(localStorage.getItem('matomoConsent')); + }); + }; + + const reset = () => { + pushInstruction('forgetConsentGiven'); + localStorage.clear('matomoConsent'); + }; + + if (!showBanner && env === 'dev') { + return ( +
+
+

Debugging analytics

+
+ + +
+
+
+ ); + } else if (!showBanner) { + return null; + } + + return ( +
+
+

+ We value your privacy and we only collect statistics and essential cookies. If you'd like to help us improve + our websites, you can allow cookies for tracking page views, time on site, and other analytics. +
+
+ + Find out how we use cookies and how you can change your settings. + +

+
+ + + {env === 'dev' && ( + + )} +
+
+
+ ); +} diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index b08766fbc3b..fb6be87b519 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -214,3 +214,31 @@ input#docsearch-input { background-color: transparent; } + +#optout-form { + position: sticky; + bottom: 10px; + flex-direction: column; + display: flex; + max-width: 800px; + margin: 0 auto; + background-color: var(--ifm-breadcrumb-color-active); +} + + + +.homepage_footer { + text-align: center; + margin-bottom: 1rem; + padding: 1.5rem 2rem; + display: flex; + flex-direction: column; + border: 1px solid #BEC2C3; + border-radius: 12px; +} + +.homepage_cta_footer_container { + display: flex; + justify-content: center; +} + diff --git a/docs/src/pages/index.jsx b/docs/src/pages/index.jsx index b372871e7b4..c7de44b300d 100644 --- a/docs/src/pages/index.jsx +++ b/docs/src/pages/index.jsx @@ -1,9 +1,8 @@ -import React, { lazy, Suspense } from 'react'; +import React from 'react'; import Layout from '@theme/Layout'; import Link from '@docusaurus/Link'; import headerPic from '@site/static/img/homepage_header_pic.png'; -import { BeatLoader } from 'react-spinners'; export default function Landing() { return ( diff --git a/docs/src/theme/Root.js b/docs/src/theme/Root.js new file mode 100644 index 00000000000..68c1e529db3 --- /dev/null +++ b/docs/src/theme/Root.js @@ -0,0 +1,22 @@ +import React from 'react'; +import useMatomo from '@site/src/components/Matomo/matomo'; +import BrowserOnly from '@docusaurus/BrowserOnly'; +import useIsBrowser from '@docusaurus/useIsBrowser'; + +function OptOutForm() { + const banner = useMatomo(); + + return <>{banner}; +} + +export default function Root({ children }) { + const useIsBrowserValue = useIsBrowser(); + if (!useIsBrowserValue) return <>{children}; + + return ( + <> + {children} + {() => } + + ); +} diff --git a/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md b/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md index 142cd02b94c..b3f1d6df747 100644 --- a/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md +++ b/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md @@ -18,7 +18,7 @@ In this guide, we will be pinned to 0.17.0. Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). -First of all, follow the the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: +First of all, follow the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: ```bash nargo compile diff --git a/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md b/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md index 795baa59d59..64ba4a2c44a 100644 --- a/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md +++ b/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md @@ -20,7 +20,7 @@ In this guide, we will be pinned to 0.17.0. Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). -First of all, follow the the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: +First of all, follow the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: ```bash nargo compile diff --git a/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md b/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md index 795baa59d59..64ba4a2c44a 100644 --- a/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md +++ b/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md @@ -20,7 +20,7 @@ In this guide, we will be pinned to 0.17.0. Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). -First of all, follow the the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: +First of all, follow the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: ```bash nargo compile diff --git a/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md b/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md index 795baa59d59..64ba4a2c44a 100644 --- a/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md +++ b/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md @@ -20,7 +20,7 @@ In this guide, we will be pinned to 0.17.0. Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). -First of all, follow the the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: +First of all, follow the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: ```bash nargo compile diff --git a/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md b/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md index 795baa59d59..64ba4a2c44a 100644 --- a/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md +++ b/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md @@ -20,7 +20,7 @@ In this guide, we will be pinned to 0.17.0. Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). -First of all, follow the the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: +First of all, follow the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: ```bash nargo compile diff --git a/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md b/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md index 795baa59d59..64ba4a2c44a 100644 --- a/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md +++ b/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md @@ -20,7 +20,7 @@ In this guide, we will be pinned to 0.17.0. Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). -First of all, follow the the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: +First of all, follow the [Nargo guide](../../getting_started/00_nargo_installation.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: ```bash nargo compile diff --git a/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md index 0763b6224c9..516e07c89fd 100644 --- a/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md @@ -21,7 +21,7 @@ In this guide, we will be pinned to 0.17.0. Make sure you have Node installed on your machine by opening a terminal and executing `node --version`. If you don't see a version, you should install [node](https://github.com/nvm-sh/nvm). You can also use `yarn` if you prefer that package manager over npm (which comes with node). -First of all, follow the the [Nargo guide](../getting_started/installation/index.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: +First of all, follow the [Nargo guide](../getting_started/installation/index.md) to install nargo version 0.17.0 and create a new project with `nargo new circuit`. Once there, `cd` into the `circuit` folder. You should then be able to compile your circuit into `json` format and see it inside the `target` folder: ```bash nargo compile diff --git a/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md index 82899217e61..e3bc8c58b24 100644 --- a/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md @@ -24,7 +24,7 @@ Before we start, we want to make sure we have Node and Nargo installed. We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). -As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: +As for `Nargo`, we can follow the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: ```sh curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash diff --git a/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md index 12beb476994..0d75e2e8045 100644 --- a/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md @@ -24,7 +24,7 @@ Before we start, we want to make sure we have Node and Nargo installed. We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). -As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: +As for `Nargo`, we can follow the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: ```sh curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash diff --git a/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md index 02044cd2ff6..0cea72314ce 100644 --- a/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.25.0/tutorials/noirjs_app.md @@ -24,7 +24,7 @@ Before we start, we want to make sure we have Node and Nargo installed. We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). -As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: +As for `Nargo`, we can follow the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: ```sh curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash diff --git a/docs/versioned_docs/version-v0.26.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.26.0/tutorials/noirjs_app.md index d098827e6d9..a6dda7e08c3 100644 --- a/docs/versioned_docs/version-v0.26.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.26.0/tutorials/noirjs_app.md @@ -24,7 +24,7 @@ Before we start, we want to make sure we have Node and Nargo installed. We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). -As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: +As for `Nargo`, we can follow the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: ```sh curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash diff --git a/docs/versioned_docs/version-v0.27.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.27.0/tutorials/noirjs_app.md index 12beb476994..0d75e2e8045 100644 --- a/docs/versioned_docs/version-v0.27.0/tutorials/noirjs_app.md +++ b/docs/versioned_docs/version-v0.27.0/tutorials/noirjs_app.md @@ -24,7 +24,7 @@ Before we start, we want to make sure we have Node and Nargo installed. We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). -As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: +As for `Nargo`, we can follow the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: ```sh curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash diff --git a/docs/versioned_docs/version-v0.28.0/explainers/explainer-oracle.md b/docs/versioned_docs/version-v0.28.0/explainers/explainer-oracle.md new file mode 100644 index 00000000000..b84ca5dd986 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/explainers/explainer-oracle.md @@ -0,0 +1,57 @@ +--- +title: Oracles +description: This guide provides an in-depth understanding of how Oracles work in Noir programming. Learn how to use outside calculations in your programs, constrain oracles, and understand their uses and limitations. +keywords: + - Noir Programming + - Oracles + - JSON-RPC + - Foreign Call Handlers + - Constrained Functions + - Blockchain Programming +sidebar_position: 1 +--- + +If you've seen "The Matrix" you may recall "The Oracle" as Gloria Foster smoking cigarettes and baking cookies. While she appears to "know things", she is actually providing a calculation of a pre-determined future. Noir Oracles are similar, in a way. They don't calculate the future (yet), but they allow you to use outside calculations in your programs. + +![matrix oracle prediction](@site/static/img/memes/matrix_oracle.jpeg) + +A Noir program is usually self-contained. You can pass certain inputs to it, and it will generate a deterministic output for those inputs. But what if you wanted to defer some calculation to an outside process or source? + +Oracles are functions that provide this feature. + +## Use cases + +An example usage for Oracles is proving something on-chain. For example, proving that the ETH-USDC quote was below a certain target at a certain block time. Or even making more complex proofs like proving the ownership of an NFT as an anonymous login method. + +Another interesting use case is to defer expensive calculations to be made outside of the Noir program, and then constraining the result; similar to the use of [unconstrained functions](../noir/concepts//unconstrained.md). + +In short, anything that can be constrained in a Noir program but needs to be fetched from an external source is a great candidate to be used in oracles. + +## Constraining oracles + +Just like in The Matrix, Oracles are powerful. But with great power, comes great responsibility. Just because you're using them in a Noir program doesn't mean they're true. Noir has no superpowers. If you want to prove that Portugal won the Euro Cup 2016, you're still relying on potentially untrusted information. + +To give a concrete example, Alice wants to login to the [NounsDAO](https://nouns.wtf/) forum with her username "noir_nouner" by proving she owns a noun without revealing her ethereum address. Her Noir program could have a oracle call like this: + +```rust +#[oracle(getNoun)] +unconstrained fn get_noun(address: Field) -> Field +``` + +This oracle could naively resolve with the number of Nouns she possesses. However, it is useless as a trusted source, as the oracle could resolve to anything Alice wants. In order to make this oracle call actually useful, Alice would need to constrain the response from the oracle, by proving her address and the noun count belongs to the state tree of the contract. + +In short, **Oracles don't prove anything. Your Noir program does.** + +:::danger + +If you don't constrain the return of your oracle, you could be clearly opening an attack vector on your Noir program. Make double-triple sure that the return of an oracle call is constrained! + +::: + +## How to use Oracles + +On CLI, Nargo resolves oracles by making JSON RPC calls, which means it would require an RPC node to be running. + +In JavaScript, NoirJS accepts and resolves arbitrary call handlers (that is, not limited to JSON) as long as they matches the expected types the developer defines. Refer to [Foreign Call Handler](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) to learn more about NoirJS's call handling. + +If you want to build using oracles, follow through to the [oracle guide](../how_to/how-to-oracles.md) for a simple example on how to do that. diff --git a/docs/versioned_docs/version-v0.28.0/explainers/explainer-recursion.md b/docs/versioned_docs/version-v0.28.0/explainers/explainer-recursion.md new file mode 100644 index 00000000000..18846176ca7 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/explainers/explainer-recursion.md @@ -0,0 +1,176 @@ +--- +title: Recursive proofs +description: Explore the concept of recursive proofs in Zero-Knowledge programming. Understand how recursion works in Noir, a language for writing smart contracts on the EVM blockchain. Learn through practical examples like Alice and Bob's guessing game, Charlie's recursive merkle tree, and Daniel's reusable components. Discover how to use recursive proofs to optimize computational resources and improve efficiency. + +keywords: + [ + "Recursive Proofs", + "Zero-Knowledge Programming", + "Noir", + "EVM Blockchain", + "Smart Contracts", + "Recursion in Noir", + "Alice and Bob Guessing Game", + "Recursive Merkle Tree", + "Reusable Components", + "Optimizing Computational Resources", + "Improving Efficiency", + "Verification Key", + "Aggregation", + "Recursive zkSNARK schemes", + "PLONK", + "Proving and Verification Keys" + ] +sidebar_position: 1 +pagination_next: how_to/how-to-recursion +--- + +In programming, we tend to think of recursion as something calling itself. A classic example would be the calculation of the factorial of a number: + +```js +function factorial(n) { + if (n === 0 || n === 1) { + return 1; + } else { + return n * factorial(n - 1); + } +} +``` + +In this case, while `n` is not `1`, this function will keep calling itself until it hits the base case, bubbling up the result on the call stack: + +```md + Is `n` 1? <--------- + /\ / + / \ n = n -1 + / \ / + Yes No -------- +``` + +In Zero-Knowledge, recursion has some similarities. + +It is not a Noir function calling itself, but a proof being used as an input to another circuit. In short, you verify one proof *inside* another proof, returning the proof that both proofs are valid. + +This means that, given enough computational resources, you can prove the correctness of any arbitrary number of proofs in a single proof. This could be useful to design state channels (for which a common example would be [Bitcoin's Lightning Network](https://en.wikipedia.org/wiki/Lightning_Network)), to save on gas costs by settling one proof on-chain, or simply to make business logic less dependent on a consensus mechanism. + +## Examples + +Let us look at some of these examples + +### Alice and Bob - Guessing game + +Alice and Bob are friends, and they like guessing games. They want to play a guessing game online, but for that, they need a trusted third-party that knows both of their secrets and finishes the game once someone wins. + +So, they use zero-knowledge proofs. Alice tries to guess Bob's number, and Bob will generate a ZK proof stating whether she succeeded or failed. + +This ZK proof can go on a smart contract, revealing the winner and even giving prizes. However, this means every turn needs to be verified on-chain. This incurs some cost and waiting time that may simply make the game too expensive or time-consuming to be worth it. + +As a solution, Alice proposes the following: "what if Bob generates his proof, and instead of sending it on-chain, I verify it *within* my own proof before playing my own turn?". + +She can then generate a proof that she verified his proof, and so on. + +```md + Did you fail? <-------------------------- + / \ / + / \ n = n -1 + / \ / + Yes No / + | | / + | | / + | You win / + | / + | / +Generate proof of that / + + / + my own guess ---------------- +``` + +### Charlie - Recursive merkle tree + +Charlie is a concerned citizen, and wants to be sure his vote in an election is accounted for. He votes with a ZK proof, but he has no way of knowing that his ZK proof was included in the total vote count! + +If the vote collector puts all of the votes into a [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree), everyone can prove the verification of two proofs within one proof, as such: + +```md + abcd + __________|______________ + | | + ab cd + _____|_____ ______|______ + | | | | + alice bob charlie daniel +``` + +Doing this recursively allows us to arrive on a final proof `abcd` which if true, verifies the correctness of all the votes. + +### Daniel - Reusable components + +Daniel has a big circuit and a big headache. A part of his circuit is a setup phase that finishes with some assertions that need to be made. But that section alone takes most of the proving time, and is largely independent of the rest of the circuit. + +He might find it more efficient to generate a proof for that setup phase separately, and verify that proof recursively in the actual business logic section of his circuit. This will allow for parallelization of both proofs, which results in a considerable speedup. + +## What params do I need + +As you can see in the [recursion reference](noir/standard_library/recursion.md), a simple recursive proof requires: + +- The proof to verify +- The Verification Key of the circuit that generated the proof +- A hash of this verification key, as it's needed for some backends +- The public inputs for the proof + +:::info + +Recursive zkSNARK schemes do not necessarily "verify a proof" in the sense that you expect a true or false to be spit out by the verifier. Rather an aggregation object is built over the public inputs. + +So, taking the example of Alice and Bob and their guessing game: + +- Alice makes her guess. Her proof is *not* recursive: it doesn't verify any proof within it! It's just a standard `assert(x != y)` circuit +- Bob verifies Alice's proof and makes his own guess. In this circuit, he doesn't exactly *prove* the verification of Alice's proof. Instead, he *aggregates* his proof to Alice's proof. The actual verification is done when the full proof is verified, for example when using `nargo verify` or through the verifier smart contract. + +We can imagine recursive proofs a [relay race](https://en.wikipedia.org/wiki/Relay_race). The first runner doesn't have to receive the baton from anyone else, as he/she already starts with it. But when his/her turn is over, the next runner needs to receive it, run a bit more, and pass it along. Even though every runner could theoretically verify the baton mid-run (why not? 🏃🔍), only at the end of the race does the referee verify that the whole race is valid. + +::: + +## Some architecture + +As with everything in computer science, there's no one-size-fits all. But there are some patterns that could help understanding and implementing them. To give three examples: + +### Adding some logic to a proof verification + +This would be an approach for something like our guessing game, where proofs are sent back and forth and are verified by each opponent. This circuit would be divided in two sections: + +- A `recursive verification` section, which would be just the call to `std::verify_proof`, and that would be skipped on the first move (since there's no proof to verify) +- A `guessing` section, which is basically the logic part where the actual guessing happens + +In such a situation, and assuming Alice is first, she would skip the first part and try to guess Bob's number. Bob would then verify her proof on the first section of his run, and try to guess Alice's number on the second part, and so on. + +### Aggregating proofs + +In some one-way interaction situations, recursion would allow for aggregation of simple proofs that don't need to be immediately verified on-chain or elsewhere. + +To give a practical example, a barman wouldn't need to verify a "proof-of-age" on-chain every time he serves alcohol to a customer. Instead, the architecture would comprise two circuits: + +- A `main`, non-recursive circuit with some logic +- A `recursive` circuit meant to verify two proofs in one proof + +The customer's proofs would be intermediate, and made on their phones, and the barman could just verify them locally. He would then aggregate them into a final proof sent on-chain (or elsewhere) at the end of the day. + +### Recursively verifying different circuits + +Nothing prevents you from verifying different circuits in a recursive proof, for example: + +- A `circuit1` circuit +- A `circuit2` circuit +- A `recursive` circuit + +In this example, a regulator could verify that taxes were paid for a specific purchase by aggregating both a `payer` circuit (proving that a purchase was made and taxes were paid), and a `receipt` circuit (proving that the payment was received) + +## How fast is it + +At the time of writing, verifying recursive proofs is surprisingly fast. This is because most of the time is spent on generating the verification key that will be used to generate the next proof. So you are able to cache the verification key and reuse it later. + +Currently, Noir JS packages don't expose the functionality of loading proving and verification keys, but that feature exists in the underlying `bb.js` package. + +## How can I try it + +Learn more about using recursion in Nargo and NoirJS in the [how-to guide](../how_to/how-to-recursion.md) and see a full example in [noir-examples](https://github.com/noir-lang/noir-examples). diff --git a/docs/versioned_docs/version-v0.28.0/getting_started/_category_.json b/docs/versioned_docs/version-v0.28.0/getting_started/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/getting_started/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/_category_.json b/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/index.md b/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/index.md new file mode 100644 index 00000000000..743c4d8d634 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/index.md @@ -0,0 +1,142 @@ +--- +title: Creating a Project +description: + Learn how to create and verify your first Noir program using Nargo, a programming language for + zero-knowledge proofs. +keywords: + [ + Nargo, + Noir, + zero-knowledge proofs, + programming language, + create Noir program, + verify Noir program, + step-by-step guide, + ] +sidebar_position: 1 + +--- + +Now that we have installed Nargo, it is time to make our first hello world program! + +## Create a Project Directory + +Noir code can live anywhere on your computer. Let us create a _projects_ folder in the home +directory to house our Noir programs. + +For Linux, macOS, and Windows PowerShell, create the directory and change directory into it by +running: + +```sh +mkdir ~/projects +cd ~/projects +``` + +## Create Our First Nargo Project + +Now that we are in the projects directory, create a new Nargo project by running: + +```sh +nargo new hello_world +``` + +> **Note:** `hello_world` can be any arbitrary project name, we are simply using `hello_world` for +> demonstration. +> +> In production, the common practice is to name the project folder as `circuits` for better +> identifiability when sitting alongside other folders in the codebase (e.g. `contracts`, `scripts`, +> `test`). + +A `hello_world` folder would be created. Similar to Rust, the folder houses _src/main.nr_ and +_Nargo.toml_ which contain the source code and environmental options of your Noir program +respectively. + +### Intro to Noir Syntax + +Let us take a closer look at _main.nr_. The default _main.nr_ generated should look like this: + +```rust +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` + +The first line of the program specifies the program's inputs: + +```rust +x : Field, y : pub Field +``` + +Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the +keyword `pub` (e.g. `y`). To learn more about private and public values, check the +[Data Types](../../noir/concepts/data_types/index.md) section. + +The next line of the program specifies its body: + +```rust +assert(x != y); +``` + +The Noir syntax `assert` can be interpreted as something similar to constraints in other zk-contract languages. + +For more Noir syntax, check the [Language Concepts](../../noir/concepts/comments.md) chapter. + +## Build In/Output Files + +Change directory into _hello_world_ and build in/output files for your Noir program by running: + +```sh +cd hello_world +nargo check +``` + +Two additional files would be generated in your project directory: + +_Prover.toml_ houses input values, and _Verifier.toml_ houses public values. + +## Prove Our Noir Program + +Now that the project is set up, we can create a proof of correct execution of our Noir program. + +Fill in input values for execution in the _Prover.toml_ file. For example: + +```toml +x = "1" +y = "2" +``` + +Prove the valid execution of your Noir program: + +```sh +nargo prove +``` + +A new folder _proofs_ would then be generated in your project directory, containing the proof file +`.proof`, where the project name is defined in Nargo.toml. + +The _Verifier.toml_ file would also be updated with the public values computed from program +execution (in this case the value of `y`): + +```toml +y = "0x0000000000000000000000000000000000000000000000000000000000000002" +``` + +> **Note:** Values in _Verifier.toml_ are computed as 32-byte hex values. + +## Verify Our Noir Program + +Once a proof is generated, we can verify correct execution of our Noir program by verifying the +proof file. + +Verify your proof by running: + +```sh +nargo verify +``` + +The verification will complete in silence if it is successful. If it fails, it will log the +corresponding error instead. + +Congratulations, you have now created and verified a proof for your very first Noir program! + +In the [next section](./project_breakdown.md), we will go into more detail on each step performed. diff --git a/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/project_breakdown.md b/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/project_breakdown.md new file mode 100644 index 00000000000..6160a102c6c --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/getting_started/hello_noir/project_breakdown.md @@ -0,0 +1,199 @@ +--- +title: Project Breakdown +description: + Learn about the anatomy of a Nargo project, including the purpose of the Prover and Verifier TOML + files, and how to prove and verify your program. +keywords: + [Nargo, Nargo project, Prover.toml, Verifier.toml, proof verification, private asset transfer] +sidebar_position: 2 +--- + +This section breaks down our hello world program from the previous section. We elaborate on the project +structure and what the `prove` and `verify` commands did. + +## Anatomy of a Nargo Project + +Upon creating a new project with `nargo new` and building the in/output files with `nargo check` +commands, you would get a minimal Nargo project of the following structure: + + - src + - Prover.toml + - Verifier.toml + - Nargo.toml + +The source directory _src_ holds the source code for your Noir program. By default only a _main.nr_ +file will be generated within it. + +### Prover.toml + +_Prover.toml_ is used for specifying the input values for executing and proving the program. You can specify `toml` files with different names by using the `--prover-name` or `-p` flags, see the [Prover](#provertoml) section below. Optionally you may specify expected output values for prove-time checking as well. + +### Verifier.toml + +_Verifier.toml_ contains public in/output values computed when executing the Noir program. + +### Nargo.toml + +_Nargo.toml_ contains the environmental options of your project. It contains a "package" section and a "dependencies" section. + +Example Nargo.toml: + +```toml +[package] +name = "noir_starter" +type = "bin" +authors = ["Alice"] +compiler_version = "0.9.0" +description = "Getting started with Noir" +entry = "circuit/main.nr" +license = "MIT" + +[dependencies] +ecrecover = {tag = "v0.9.0", git = "https://github.com/colinnielsen/ecrecover-noir.git"} +``` + +Nargo.toml for a [workspace](../../noir/modules_packages_crates/workspaces.md) will look a bit different. For example: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +#### Package section + +The package section defines a number of fields including: + +- `name` (**required**) - the name of the package +- `type` (**required**) - can be "bin", "lib", or "contract" to specify whether its a binary, library or Aztec contract +- `authors` (optional) - authors of the project +- `compiler_version` - specifies the version of the compiler to use. This is enforced by the compiler and follow's [Rust's versioning](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field), so a `compiler_version = 0.18.0` will enforce Nargo version 0.18.0, `compiler_version = ^0.18.0` will enforce anything above 0.18.0 but below 0.19.0, etc. For more information, see how [Rust handles these operators](https://docs.rs/semver/latest/semver/enum.Op.html) +- `description` (optional) +- `entry` (optional) - a relative filepath to use as the entry point into your package (overrides the default of `src/lib.nr` or `src/main.nr`) +- `backend` (optional) +- `license` (optional) + +#### Dependencies section + +This is where you will specify any dependencies for your project. See the [Dependencies page](../../noir/modules_packages_crates/dependencies.md) for more info. + +`./proofs/` and `./contract/` directories will not be immediately visible until you create a proof or +verifier contract respectively. + +### main.nr + +The _main.nr_ file contains a `main` method, this method is the entry point into your Noir program. + +In our sample program, _main.nr_ looks like this: + +```rust +fn main(x : Field, y : Field) { + assert(x != y); +} +``` + +The parameters `x` and `y` can be seen as the API for the program and must be supplied by the +prover. Since neither `x` nor `y` is marked as public, the verifier does not supply any inputs, when +verifying the proof. + +The prover supplies the values for `x` and `y` in the _Prover.toml_ file. + +As for the program body, `assert` ensures that the condition to be satisfied (e.g. `x != y`) is +constrained by the proof of the execution of said program (i.e. if the condition was not met, the +verifier would reject the proof as an invalid proof). + +### Prover.toml + +The _Prover.toml_ file is a file which the prover uses to supply his witness values(both private and +public). + +In our hello world program the _Prover.toml_ file looks like this: + +```toml +x = "1" +y = "2" +``` + +When the command `nargo prove` is executed, two processes happen: + +1. Noir creates a proof that `x`, which holds the value of `1`, and `y`, which holds the value of `2`, + is not equal. This inequality constraint is due to the line `assert(x != y)`. + +2. Noir creates and stores the proof of this statement in the _proofs_ directory in a file called your-project.proof. So if your project is named "private_voting" (defined in the project Nargo.toml), the proof will be saved at `./proofs/private_voting.proof`. Opening this file will display the proof in hex format. + +#### Arrays of Structs + +The following code shows how to pass an array of structs to a Noir program to generate a proof. + +```rust +// main.nr +struct Foo { + bar: Field, + baz: Field, +} + +fn main(foos: [Foo; 3]) -> pub Field { + foos[2].bar + foos[2].baz +} +``` + +Prover.toml: + +```toml +[[foos]] # foos[0] +bar = 0 +baz = 0 + +[[foos]] # foos[1] +bar = 0 +baz = 0 + +[[foos]] # foos[2] +bar = 1 +baz = 2 +``` + +#### Custom toml files + +You can specify a `toml` file with a different name to use for proving by using the `--prover-name` or `-p` flags. + +This command looks for proof inputs in the default **Prover.toml** and generates the proof and saves it at `./proofs/.proof`: + +```bash +nargo prove +``` + +This command looks for proof inputs in the custom **OtherProver.toml** and generates proof and saves it at `./proofs/.proof`: + +```bash +nargo prove -p OtherProver +``` + +## Verifying a Proof + +When the command `nargo verify` is executed, two processes happen: + +1. Noir checks in the _proofs_ directory for a proof file with the project name (eg. test_project.proof) + +2. If that file is found, the proof's validity is checked + +> **Note:** The validity of the proof is linked to the current Noir program; if the program is +> changed and the verifier verifies the proof, it will fail because the proof is not valid for the +> _modified_ Noir program. + +In production, the prover and the verifier are usually two separate entities. A prover would +retrieve the necessary inputs, execute the Noir program, generate a proof and pass it to the +verifier. The verifier would then retrieve the public inputs, usually from external sources, and +verify the validity of the proof against it. + +Take a private asset transfer as an example: + +A person using a browser as the prover would retrieve private inputs locally (e.g. the user's private key) and +public inputs (e.g. the user's encrypted balance on-chain), compute the transfer, generate a proof +and submit it to the verifier smart contract. + +The verifier contract would then draw the user's encrypted balance directly from the blockchain and +verify the proof submitted against it. If the verification passes, additional functions in the +verifier contract could trigger (e.g. approve the asset transfer). + +Now that you understand the concepts, you'll probably want some editor feedback while you are writing more complex code. diff --git a/docs/versioned_docs/version-v0.28.0/getting_started/installation/_category_.json b/docs/versioned_docs/version-v0.28.0/getting_started/installation/_category_.json new file mode 100644 index 00000000000..0c02fb5d4d7 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/getting_started/installation/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 0, + "label": "Install Nargo", + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/getting_started/installation/index.md b/docs/versioned_docs/version-v0.28.0/getting_started/installation/index.md new file mode 100644 index 00000000000..4ef86aa5914 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/getting_started/installation/index.md @@ -0,0 +1,48 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs. This page is a quick guide on how to install Nargo through the most common and easy method, noirup +keywords: [ + Nargo + Noir + Rust + Cargo + Noirup + Installation + Terminal Commands + Version Check + Nightlies + Specific Versions + Branches + Noirup Repository +] +pagination_next: getting_started/hello_noir/index +--- + +`nargo` is the one-stop-shop for almost everything related with Noir. The name comes from our love for Rust and its package manager `cargo`. + +With `nargo`, you can start new projects, compile, execute, prove, verify, test, generate solidity contracts, and do pretty much all that is available in Noir. + +Similarly to `rustup`, we also maintain an easy installation method that covers most machines: `noirup`. + +## Installing Noirup + +Open a terminal on your machine, and write: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done. That's it. You should have the latest version working. You can check with `nargo --version`. + +You can also install nightlies, specific versions +or branches. Check out the [noirup repository](https://github.com/noir-lang/noirup) for more +information. + +Now we're ready to start working on [our first Noir program!](../hello_noir/index.md) diff --git a/docs/versioned_docs/version-v0.28.0/getting_started/installation/other_install_methods.md b/docs/versioned_docs/version-v0.28.0/getting_started/installation/other_install_methods.md new file mode 100644 index 00000000000..3634723562b --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/getting_started/installation/other_install_methods.md @@ -0,0 +1,102 @@ +--- +title: Alternative Installations +description: There are different ways to install Nargo, the one-stop shop and command-line tool for developing Noir programs. This guide explains how to specify which version to install when using noirup, and using WSL for windows. +keywords: [ + Installation + Nargo + Noirup + Binaries + Compiling from Source + WSL for Windows + macOS + Linux + Nix + Direnv + Uninstalling Nargo + ] +sidebar_position: 1 +--- + +## Encouraged Installation Method: Noirup + +Noirup is the endorsed method for installing Nargo, streamlining the process of fetching binaries or compiling from source. It supports a range of options to cater to your specific needs, from nightly builds and specific versions to compiling from various sources. + +### Installing Noirup + +First, ensure you have `noirup` installed: + +```sh +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +### Fetching Binaries + +With `noirup`, you can easily switch between different Nargo versions, including nightly builds: + +- **Nightly Version**: Install the latest nightly build. + + ```sh + noirup --version nightly + ``` + +- **Specific Version**: Install a specific version of Nargo. + ```sh + noirup --version + ``` + +### Compiling from Source + +`noirup` also enables compiling Nargo from various sources: + +- **From a Specific Branch**: Install from the latest commit on a branch. + + ```sh + noirup --branch + ``` + +- **From a Fork**: Install from the main branch of a fork. + + ```sh + noirup --repo + ``` + +- **From a Specific Branch in a Fork**: Install from a specific branch in a fork. + + ```sh + noirup --repo --branch + ``` + +- **From a Specific Pull Request**: Install from a specific PR. + + ```sh + noirup --pr + ``` + +- **From a Specific Commit**: Install from a specific commit. + + ```sh + noirup -C + ``` + +- **From Local Source**: Compile and install from a local directory. + ```sh + noirup --path ./path/to/local/source + ``` + +## Installation on Windows + +The default backend for Noir (Barretenberg) doesn't provide Windows binaries at this time. For that reason, Noir cannot be installed natively. However, it is available by using Windows Subsystem for Linux (WSL). + +Step 1: Follow the instructions [here](https://learn.microsoft.com/en-us/windows/wsl/install) to install and run WSL. + +step 2: Follow the [Noirup instructions](#encouraged-installation-method-noirup). + +## Uninstalling Nargo + +If you installed Nargo with `noirup`, you can uninstall Nargo by removing the files in `~/.nargo`, `~/nargo`, and `~/noir_cache`. This ensures that all installed binaries, configurations, and cache related to Nargo are fully removed from your system. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` diff --git a/docs/versioned_docs/version-v0.28.0/getting_started/tooling/noir_codegen.md b/docs/versioned_docs/version-v0.28.0/getting_started/tooling/noir_codegen.md new file mode 100644 index 00000000000..d65151da0ab --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/getting_started/tooling/noir_codegen.md @@ -0,0 +1,113 @@ +--- +title: Noir Codegen for TypeScript +description: Learn how to use Noir codegen to generate TypeScript bindings +keywords: [Nargo, Noir, compile, TypeScript] +sidebar_position: 2 +--- + +When using TypeScript, it is extra work to interpret Noir program outputs in a type-safe way. Third party libraries may exist for popular Noir programs, but they are either hard to find or unmaintained. + +Now you can generate TypeScript bindings for your Noir programs in two steps: +1. Exporting Noir functions using `nargo export` +2. Using the TypeScript module `noir_codegen` to generate TypeScript binding + +**Note:** you can only export functions from a Noir *library* (not binary or contract program types). + +## Installation + +### Your TypeScript project + +If you don't already have a TypeScript project you can add the module with `yarn` (or `npm`), then initialize it: + +```bash +yarn add typescript -D +npx tsc --init +``` + +### Add TypeScript module - `noir_codegen` + +The following command will add the module to your project's devDependencies: + +```bash +yarn add @noir-lang/noir_codegen -D +``` + +### Nargo library +Make sure you have Nargo, v0.25.0 or greater, installed. If you don't, follow the [installation guide](../installation/index.md). + +If you're in a new project, make a `circuits` folder and create a new Noir library: + +```bash +mkdir circuits && cd circuits +nargo new --lib myNoirLib +``` + +## Usage + +### Export ABI of specified functions + +First go to the `.nr` files in your Noir library, and add the `#[export]` macro to each function that you want to use in TypeScript. + +```rust +#[export] +fn your_function(... +``` + +From your Noir library (where `Nargo.toml` is), run the following command: + +```bash +nargo export +``` + +You will now have an `export` directory with a .json file per exported function. + +You can also specify the directory of Noir programs using `--program-dir`, for example: + +```bash +nargo export --program-dir=./circuits/myNoirLib +``` + +### Generate TypeScript bindings from exported functions + +To use the `noir-codegen` package we added to the TypeScript project: + +```bash +yarn noir-codegen ./export/your_function.json +``` + +This creates an `exports` directory with an `index.ts` file containing all exported functions. + +**Note:** adding `--out-dir` allows you to specify an output dir for your TypeScript bindings to go. Eg: + +```bash +yarn noir-codegen ./export/*.json --out-dir ./path/to/output/dir +``` + +## Example .nr function to .ts output + +Consider a Noir library with this function: + +```rust +#[export] +fn not_equal(x: Field, y: Field) -> bool { + x != y +} +``` + +After the export and codegen steps, you should have an `index.ts` like: + +```typescript +export type Field = string; + + +export const is_equal_circuit: CompiledCircuit = {"abi":{"parameters":[{"name":"x","type":{"kind":"field"},"visibility":"private"},{"name":"y","type":{"kind":"field"},"visibility":"private"}],"param_witnesses":{"x":[{"start":0,"end":1}],"y":[{"start":1,"end":2}]},"return_type":{"abi_type":{"kind":"boolean"},"visibility":"private"},"return_witnesses":[4]},"bytecode":"H4sIAAAAAAAA/7WUMQ7DIAxFQ0Krrr2JjSGYLVcpKrn/CaqqDQN12WK+hPBgmWd/wEyHbF1SS923uhOs3pfoChI+wKXMAXzIKyNj4PB0TFTYc0w5RUjoqeAeEu1wqK0F54RGkWvW44LPzExnlkbMEs4JNZmN8PxS42uHv82T8a3Jeyn2Ks+VLPcO558HmyLMCDOXAXXtpPt4R/Rt9T36ss6dS9HGPx/eG17nGegKBQAA"}; + +export async function is_equal(x: Field, y: Field, foreignCallHandler?: ForeignCallHandler): Promise { + const program = new Noir(is_equal_circuit); + const args: InputMap = { x, y }; + const { returnValue } = await program.execute(args, foreignCallHandler); + return returnValue as boolean; +} +``` + +Now the `is_equal()` function and relevant types are readily available for use in TypeScript. diff --git a/docs/versioned_docs/version-v0.28.0/how_to/_category_.json b/docs/versioned_docs/version-v0.28.0/how_to/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/how_to/debugger/_category_.json b/docs/versioned_docs/version-v0.28.0/how_to/debugger/_category_.json new file mode 100644 index 00000000000..cc2cbb1c253 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/debugger/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Debugging", + "position": 5, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/how_to/debugger/debugging_with_the_repl.md b/docs/versioned_docs/version-v0.28.0/how_to/debugger/debugging_with_the_repl.md new file mode 100644 index 00000000000..09e5bae68ad --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/debugger/debugging_with_the_repl.md @@ -0,0 +1,164 @@ +--- +title: Using the REPL Debugger +description: + Step by step guide on how to debug your Noir circuits with the REPL Debugger. +keywords: + [ + Nargo, + Noir CLI, + Noir Debugger, + REPL, + ] +sidebar_position: 1 +--- + +#### Pre-requisites + +In order to use the REPL debugger, first you need to install recent enough versions of Nargo and vscode-noir. + +## Debugging a simple circuit + +Let's debug a simple circuit: + +```rust +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` + +To start the REPL debugger, using a terminal, go to a Noir circuit's home directory. Then: + +`$ nargo debug` + +You should be seeing this in your terminal: + +``` +[main] Starting debugger +At ~/noir-examples/recursion/circuits/main/src/main.nr:1:9 + 1 -> fn main(x : Field, y : pub Field) { + 2 assert(x != y); + 3 } +> +``` + +The debugger displays the current Noir code location, and it is now waiting for us to drive it. + +Let's first take a look at the available commands. For that we'll use the `help` command. + +``` +> help +Available commands: + + opcodes display ACIR opcodes + into step into to the next opcode + next step until a new source location is reached + out step until a new source location is reached + and the current stack frame is finished + break LOCATION:OpcodeLocation add a breakpoint at an opcode location + over step until a new source location is reached + without diving into function calls + restart restart the debugging session + delete LOCATION:OpcodeLocation delete breakpoint at an opcode location + witness show witness map + witness index:u32 display a single witness from the witness map + witness index:u32 value:String update a witness with the given value + memset index:usize value:String update a memory cell with the given + value + continue continue execution until the end of the + program + vars show variable values available at this point + in execution + stacktrace display the current stack trace + memory show memory (valid when executing unconstrained code) + step step to the next ACIR opcode + +Other commands: + + help Show this help message + quit Quit repl + +``` + +Some commands operate only for unconstrained functions, such as `memory` and `memset`. If you try to use them while execution is paused at an ACIR opcode, the debugger will simply inform you that you are not executing unconstrained code: + +``` +> memory +Unconstrained VM memory not available +> +``` + +Before continuing, we can take a look at the initial witness map: + +``` +> witness +_0 = 1 +_1 = 2 +> +``` + +Cool, since `x==1`, `y==2`, and we want to check that `x != y`, our circuit should succeed. At this point we could intervene and use the witness setter command to change one of the witnesses. Let's set `y=3`, then back to 2, so we don't affect the expected result: + +``` +> witness +_0 = 1 +_1 = 2 +> witness 1 3 +_1 = 3 +> witness +_0 = 1 +_1 = 3 +> witness 1 2 +_1 = 2 +> witness +_0 = 1 +_1 = 2 +> +``` + +Now we can inspect the current state of local variables. For that we use the `vars` command. + +``` +> vars +> +``` + +We currently have no vars in context, since we are at the entry point of the program. Let's use `next` to execute until the next point in the program. + +``` +> vars +> next +At ~/noir-examples/recursion/circuits/main/src/main.nr:1:20 + 1 -> fn main(x : Field, y : pub Field) { + 2 assert(x != y); + 3 } +> vars +x:Field = 0x01 +``` + +As a result of stepping, the variable `x`, whose initial value comes from the witness map, is now in context and returned by `vars`. + +``` +> next + 1 fn main(x : Field, y : pub Field) { + 2 -> assert(x != y); + 3 } +> vars +y:Field = 0x02 +x:Field = 0x01 +``` + +Stepping again we can finally see both variables and their values. And now we can see that the next assertion should succeed. + +Let's continue to the end: + +``` +> continue +(Continuing execution...) +Finished execution +> q +[main] Circuit witness successfully solved +``` + +Upon quitting the debugger after a solved circuit, the resulting circuit witness gets saved, equivalent to what would happen if we had run the same circuit with `nargo execute`. + +We just went through the basics of debugging using Noir REPL debugger. For a comprehensive reference, check out [the reference page](../../reference/debugger/debugger_repl.md). diff --git a/docs/versioned_docs/version-v0.28.0/how_to/debugger/debugging_with_vs_code.md b/docs/versioned_docs/version-v0.28.0/how_to/debugger/debugging_with_vs_code.md new file mode 100644 index 00000000000..a5858c1a5eb --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/debugger/debugging_with_vs_code.md @@ -0,0 +1,68 @@ +--- +title: Using the VS Code Debugger +description: + Step by step guide on how to debug your Noir circuits with the VS Code Debugger configuration and features. +keywords: + [ + Nargo, + Noir CLI, + Noir Debugger, + VS Code, + IDE, + ] +sidebar_position: 0 +--- + +This guide will show you how to use VS Code with the vscode-noir extension to debug a Noir project. + +#### Pre-requisites + +- Nargo +- vscode-noir +- A Noir project with a `Nargo.toml`, `Prover.toml` and at least one Noir (`.nr`) containing an entry point function (typically `main`). + +## Running the debugger + +The easiest way to start debugging is to open the file you want to debug, and press `F5`. This will cause the debugger to launch, using your `Prover.toml` file as input. + +You should see something like this: + +![Debugger launched](@site/static/img/debugger/1-started.png) + +Let's inspect the state of the program. For that, we open VS Code's _Debug pane_. Look for this icon: + +![Debug pane icon](@site/static/img/debugger/2-icon.png) + +You will now see two categories of variables: Locals and Witness Map. + +![Debug pane expanded](@site/static/img/debugger/3-debug-pane.png) + +1. **Locals**: variables of your program. At this point in execution this section is empty, but as we step through the code it will get populated by `x`, `result`, `digest`, etc. + +2. **Witness map**: these are initially populated from your project's `Prover.toml` file. In this example, they will be used to populate `x` and `result` at the beginning of the `main` function. + +Most of the time you will probably be focusing mostly on locals, as they represent the high level state of your program. + +You might be interested in inspecting the witness map in case you are trying to solve a really low level issue in the compiler or runtime itself, so this concerns mostly advanced or niche users. + +Let's step through the program, by using the debugger buttons or their corresponding keyboard shortcuts. + +![Debugger buttons](@site/static/img/debugger/4-debugger-buttons.png) + +Now we can see in the variables pane that there's values for `digest`, `result` and `x`. + +![Inspecting locals](@site/static/img/debugger/5-assert.png) + +We can also inspect the values of variables by directly hovering on them on the code. + +![Hover locals](@site/static/img/debugger/6-hover.png) + +Let's set a break point at the `keccak256` function, so we can continue execution up to the point when it's first invoked without having to go one step at a time. + +We just need to click the to the right of the line number 18. Once the breakpoint appears, we can click the `continue` button or use its corresponding keyboard shortcut (`F5` by default). + +![Breakpoint](@site/static/img/debugger/7-break.png) + +Now we are debugging the `keccak256` function, notice the _Call Stack pane_ at the lower right. This lets us inspect the current call stack of our process. + +That covers most of the current debugger functionalities. Check out [the reference](../../reference/debugger/debugger_vscode.md) for more details on how to configure the debugger. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/how_to/how-to-oracles.md b/docs/versioned_docs/version-v0.28.0/how_to/how-to-oracles.md new file mode 100644 index 00000000000..8cf8035a5c4 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/how-to-oracles.md @@ -0,0 +1,276 @@ +--- +title: How to use Oracles +description: Learn how to use oracles in your Noir program with examples in both Nargo and NoirJS. This guide also covers writing a JSON RPC server and providing custom foreign call handlers for NoirJS. +keywords: + - Noir Programming + - Oracles + - Nargo + - NoirJS + - JSON RPC Server + - Foreign Call Handlers +sidebar_position: 1 +--- + +This guide shows you how to use oracles in your Noir program. For the sake of clarity, it assumes that: + +- You have read the [explainer on Oracles](../explainers/explainer-oracle.md) and are comfortable with the concept. +- You have a Noir program to add oracles to. You can create one using the [vite-hardhat starter](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) as a boilerplate. +- You understand the concept of a JSON-RPC server. Visit the [JSON-RPC website](https://www.jsonrpc.org/) if you need a refresher. +- You are comfortable with server-side JavaScript (e.g. Node.js, managing packages, etc.). + +For reference, you can find the snippets used in this tutorial on the [Aztec DevRel Repository](https://github.com/AztecProtocol/dev-rel/tree/main/code-snippets/how-to-oracles). + +## Rundown + +This guide has 3 major steps: + +1. How to modify our Noir program to make use of oracle calls as unconstrained functions +2. How to write a JSON RPC Server to resolve these oracle calls with Nargo +3. How to use them in Nargo and how to provide a custom resolver in NoirJS + +## Step 1 - Modify your Noir program + +An oracle is defined in a Noir program by defining two methods: + +- An unconstrained method - This tells the compiler that it is executing an [unconstrained functions](../noir/concepts//unconstrained.md). +- A decorated oracle method - This tells the compiler that this method is an RPC call. + +An example of an oracle that returns a `Field` would be: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt(number: Field) -> Field { } + +unconstrained fn get_sqrt(number: Field) -> Field { + sqrt(number) +} +``` + +In this example, we're wrapping our oracle function in a unconstrained method, and decorating it with `oracle(getSqrt)`. We can then call the unconstrained function as we would call any other function: + +```rust +fn main(input: Field) { + let sqrt = get_sqrt(input); +} +``` + +In the next section, we will make this `getSqrt` (defined on the `sqrt` decorator) be a method of the RPC server Noir will use. + +:::danger + +As explained in the [Oracle Explainer](../explainers/explainer-oracle.md), this `main` function is unsafe unless you constrain its return value. For example: + +```rust +fn main(input: Field) { + let sqrt = get_sqrt(input); + assert(sqrt.pow_32(2) as u64 == input as u64); // <---- constrain the return of an oracle! +} +``` + +::: + +:::info + +Currently, oracles only work with single params or array params. For example: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt([Field; 2]) -> [Field; 2] { } +``` + +::: + +## Step 2 - Write an RPC server + +Brillig will call *one* RPC server. Most likely you will have to write your own, and you can do it in whatever language you prefer. In this guide, we will do it in Javascript. + +Let's use the above example of an oracle that consumes an array with two `Field` and returns their square roots: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt(input: [Field; 2]) -> [Field; 2] { } + +unconstrained fn get_sqrt(input: [Field; 2]) -> [Field; 2] { + sqrt(input) +} + +fn main(input: [Field; 2]) { + let sqrt = get_sqrt(input); + assert(sqrt[0].pow_32(2) as u64 == input[0] as u64); + assert(sqrt[1].pow_32(2) as u64 == input[1] as u64); +} +``` + +:::info + +Why square root? + +In general, computing square roots is computationally more expensive than multiplications, which takes a toll when speaking about ZK applications. In this case, instead of calculating the square root in Noir, we are using our oracle to offload that computation to be made in plain. In our circuit we can simply multiply the two values. + +::: + +Now, we should write the correspondent RPC server, starting with the [default JSON-RPC 2.0 boilerplate](https://www.npmjs.com/package/json-rpc-2.0#example): + +```js +import { JSONRPCServer } from "json-rpc-2.0"; +import express from "express"; +import bodyParser from "body-parser"; + +const app = express(); +app.use(bodyParser.json()); + +const server = new JSONRPCServer(); +app.post("/", (req, res) => { + const jsonRPCRequest = req.body; + server.receive(jsonRPCRequest).then((jsonRPCResponse) => { + if (jsonRPCResponse) { + res.json(jsonRPCResponse); + } else { + res.sendStatus(204); + } + }); +}); + +app.listen(5555); +``` + +Now, we will add our `getSqrt` method, as expected by the `#[oracle(getSqrt)]` decorator in our Noir code. It maps through the params array and returns their square roots: + +```js +server.addMethod("getSqrt", async (params) => { + const values = params[0].Array.map((field) => { + return `${Math.sqrt(parseInt(field, 16))}`; + }); + return { values: [{ Array: values }] }; +}); +``` + +:::tip + +Brillig expects an object with an array of values. Each value is an object declaring to be `Single` or `Array` and returning a field element *as a string*. For example: + +```json +{ "values": [{ "Array": ["1", "2"] }]} +{ "values": [{ "Single": "1" }]} +{ "values": [{ "Single": "1" }, { "Array": ["1", "2"] }]} +``` + +If you're using Typescript, the following types may be helpful in understanding the expected return value and making sure they're easy to follow: + +```js +interface SingleForeignCallParam { + Single: string, +} + +interface ArrayForeignCallParam { + Array: string[], +} + +type ForeignCallParam = SingleForeignCallParam | ArrayForeignCallParam; + +interface ForeignCallResult { + values: ForeignCallParam[], +} +``` + +::: + +## Step 3 - Usage with Nargo + +Using the [`nargo` CLI tool](../getting_started/installation/index.md), you can use oracles in the `nargo test`, `nargo execute` and `nargo prove` commands by passing a value to `--oracle-resolver`. For example: + +```bash +nargo test --oracle-resolver http://localhost:5555 +``` + +This tells `nargo` to use your RPC Server URL whenever it finds an oracle decorator. + +## Step 4 - Usage with NoirJS + +In a JS environment, an RPC server is not strictly necessary, as you may want to resolve your oracles without needing any JSON call at all. NoirJS simply expects that you pass a callback function when you generate proofs, and that callback function can be anything. + +For example, if your Noir program expects the host machine to provide CPU pseudo-randomness, you could simply pass it as the `foreignCallHandler`. You don't strictly need to create an RPC server to serve pseudo-randomness, as you may as well get it directly in your app: + +```js +const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc + +await noir.generateProof(inputs, foreignCallHandler) +``` + +As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. + +:::tip + +Does this mean you don't have to write an RPC server like in [Step #2](#step-2---write-an-rpc-server)? + +You don't technically have to, but then how would you run `nargo test` or `nargo prove`? To use both `Nargo` and `NoirJS` in your development flow, you will have to write a JSON RPC server. + +::: + +In this case, let's make `foreignCallHandler` call the JSON RPC Server we created in [Step #2](#step-2---write-an-rpc-server), by making it a JSON RPC Client. + +For example, using the same `getSqrt` program in [Step #1](#step-1---modify-your-noir-program) (comments in the code): + +```js +import { JSONRPCClient } from "json-rpc-2.0"; + +// declaring the JSONRPCClient +const client = new JSONRPCClient((jsonRPCRequest) => { +// hitting the same JSON RPC Server we coded above + return fetch("http://localhost:5555", { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify(jsonRPCRequest), + }).then((response) => { + if (response.status === 200) { + return response + .json() + .then((jsonRPCResponse) => client.receive(jsonRPCResponse)); + } else if (jsonRPCRequest.id !== undefined) { + return Promise.reject(new Error(response.statusText)); + } + }); +}); + +// declaring a function that takes the name of the foreign call (getSqrt) and the inputs +const foreignCallHandler = async (name, input) => { + // notice that the "inputs" parameter contains *all* the inputs + // in this case we to make the RPC request with the first parameter "numbers", which would be input[0] + const oracleReturn = await client.request(name, [ + { Array: input[0].map((i) => i.toString("hex")) }, + ]); + return [oracleReturn.values[0].Array]; +}; + +// the rest of your NoirJS code +const input = { input: [4, 16] }; +const { witness } = await noir.execute(numbers, foreignCallHandler); +``` + +:::tip + +If you're in a NoirJS environment running your RPC server together with a frontend app, you'll probably hit a familiar problem in full-stack development: requests being blocked by [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) policy. For development only, you can simply install and use the [`cors` npm package](https://www.npmjs.com/package/cors) to get around the problem: + +```bash +yarn add cors +``` + +and use it as a middleware: + +```js +import cors from "cors"; + +const app = express(); +app.use(cors()) +``` + +::: + +## Conclusion + +Hopefully by the end of this guide, you should be able to: + +- Write your own logic around Oracles and how to write a JSON RPC server to make them work with your Nargo commands. +- Provide custom foreign call handlers for NoirJS. diff --git a/docs/versioned_docs/version-v0.28.0/how_to/how-to-recursion.md b/docs/versioned_docs/version-v0.28.0/how_to/how-to-recursion.md new file mode 100644 index 00000000000..4c45bb87ae2 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/how-to-recursion.md @@ -0,0 +1,179 @@ +--- +title: How to use recursion on NoirJS +description: Learn how to implement recursion with NoirJS, a powerful tool for creating smart contracts on the EVM blockchain. This guide assumes familiarity with NoirJS, solidity verifiers, and the Barretenberg proving backend. Discover how to generate both final and intermediate proofs using `noir_js` and `backend_barretenberg`. +keywords: + [ + "NoirJS", + "EVM blockchain", + "smart contracts", + "recursion", + "solidity verifiers", + "Barretenberg backend", + "noir_js", + "backend_barretenberg", + "intermediate proofs", + "final proofs", + "nargo compile", + "json import", + "recursive circuit", + "recursive app" + ] +sidebar_position: 1 +--- + +This guide shows you how to use recursive proofs in your NoirJS app. For the sake of clarity, it is assumed that: + +- You already have a NoirJS app. If you don't, please visit the [NoirJS tutorial](../tutorials/noirjs_app.md) and the [reference](../reference/NoirJS/noir_js/index.md). +- You are familiar with what are recursive proofs and you have read the [recursion explainer](../explainers/explainer-recursion.md) +- You already built a recursive circuit following [the reference](../noir/standard_library/recursion.md), and understand how it works. + +It is also assumed that you're not using `noir_wasm` for compilation, and instead you've used [`nargo compile`](../reference/nargo_commands.md) to generate the `json` you're now importing into your project. However, the guide should work just the same if you're using `noir_wasm`. + +:::info + +As you've read in the [explainer](../explainers/explainer-recursion.md), a recursive proof is an intermediate proof. This means that it doesn't necessarily generate the final step that makes it verifiable in a smart contract. However, it is easy to verify within another circuit. + +While "standard" usage of NoirJS packages abstracts final proofs, it currently lacks the necessary interface to abstract away intermediate proofs. This means that these proofs need to be created by using the backend directly. + +In short: + +- `noir_js` generates *only* final proofs +- `backend_barretenberg` generates both types of proofs + +::: + +In a standard recursive app, you're also dealing with at least two circuits. For the purpose of this guide, we will assume the following: + +- `main`: a circuit of type `assert(x != y)`, where `main` is marked with a `#[recursive]` attribute. This attribute states that the backend should generate proofs that are friendly for verification within another circuit. +- `recursive`: a circuit that verifies `main` + +For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir-lang/noir-examples) repository. We will *not* be using it as a reference for this guide. + +## Step 1: Setup + +In a common NoirJS app, you need to instantiate a backend with something like `const backend = new Backend(circuit)`. Then you feed it to the `noir_js` interface. + +For recursion, this doesn't happen, and the only need for `noir_js` is only to `execute` a circuit and get its witness and return value. Everything else is not interfaced, so it needs to happen on the `backend` object. + +It is also recommended that you instantiate the backend with as many threads as possible, to allow for maximum concurrency: + +```js +const backend = new Backend(circuit, { threads: 8 }) +``` + +:::tip +You can use the [`os.cpus()`](https://nodejs.org/api/os.html#oscpus) object in `nodejs` or [`navigator.hardwareConcurrency`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/hardwareConcurrency) on the browser to make the most out of those glorious cpu cores +::: + +## Step 2: Generating the witness and the proof for `main` + +After instantiating the backend, you should also instantiate `noir_js`. We will use it to execute the circuit and get the witness. + +```js +const noir = new Noir(circuit, backend) +const { witness } = noir.execute(input) +``` + +With this witness, you are now able to generate the intermediate proof for the main circuit: + +```js +const { proof, publicInputs } = await backend.generateProof(witness) +``` + +:::warning + +Always keep in mind what is actually happening on your development process, otherwise you'll quickly become confused about what circuit we are actually running and why! + +In this case, you can imagine that Alice (running the `main` circuit) is proving something to Bob (running the `recursive` circuit), and Bob is verifying her proof within his proof. + +With this in mind, it becomes clear that our intermediate proof is the one *meant to be verified within another circuit*, so it must be Alice's. Actually, the only final proof in this theoretical scenario would be the last one, sent on-chain. + +::: + +## Step 3 - Verification and proof artifacts + +Optionally, you are able to verify the intermediate proof: + +```js +const verified = await backend.verifyProof({ proof, publicInputs }) +``` + +This can be useful to make sure our intermediate proof was correctly generated. But the real goal is to do it within another circuit. For that, we need to generate recursive proof artifacts that will be passed to the circuit that is verifying the proof we just generated. Instead of passing the proof and verification key as a byte array, we pass them as fields which makes it cheaper to verify in a circuit: + +```js +const { proofAsFields, vkAsFields, vkHash } = await backend.generateRecursiveProofArtifacts( { publicInputs, proof }, publicInputsCount) +``` + +This call takes the public inputs and the proof, but also the public inputs count. While this is easily retrievable by simply counting the `publicInputs` length, the backend interface doesn't currently abstract it away. + +:::info + +The `proofAsFields` has a constant size `[Field; 93]` and verification keys in Barretenberg are always `[Field; 114]`. + +::: + +:::warning + +One common mistake is to forget *who* makes this call. + +In a situation where Alice is generating the `main` proof, if she generates the proof artifacts and sends them to Bob, which gladly takes them as true, this would mean Alice could prove anything! + +Instead, Bob needs to make sure *he* extracts the proof artifacts, using his own instance of the `main` circuit backend. This way, Alice has to provide a valid proof for the correct `main` circuit. + +::: + +## Step 4 - Recursive proof generation + +With the artifacts, generating a recursive proof is no different from a normal proof. You simply use the `backend` (with the recursive circuit) to generate it: + +```js +const recursiveInputs = { + verification_key: vkAsFields, // array of length 114 + proof: proofAsFields, // array of length 93 + size of public inputs + publicInputs: [mainInput.y], // using the example above, where `y` is the only public input + key_hash: vkHash, +} + +const { witness, returnValue } = noir.execute(recursiveInputs) // we're executing the recursive circuit now! +const { proof, publicInputs } = backend.generateProof(witness) +const verified = backend.verifyProof({ proof, publicInputs }) +``` + +You can obviously chain this proof into another proof. In fact, if you're using recursive proofs, you're probably interested of using them this way! + +:::tip + +Managing circuits and "who does what" can be confusing. To make sure your naming is consistent, you can keep them in an object. For example: + +```js +const circuits = { + main: mainJSON, + recursive: recursiveJSON +} +const backends = { + main: new BarretenbergBackend(circuits.main), + recursive: new BarretenbergBackend(circuits.recursive) +} +const noir_programs = { + main: new Noir(circuits.main, backends.main), + recursive: new Noir(circuits.recursive, backends.recursive) +} +``` + +This allows you to neatly call exactly the method you want without conflicting names: + +```js +// Alice runs this 👇 +const { witness: mainWitness } = await noir_programs.main.execute(input) +const proof = await backends.main.generateProof(mainWitness) + +// Bob runs this 👇 +const verified = await backends.main.verifyProof(proof) +const { proofAsFields, vkAsFields, vkHash } = await backends.main.generateRecursiveProofArtifacts( + proof, + numPublicInputs, +); +const recursiveProof = await noir_programs.recursive.generateProof(recursiveInputs) +``` + +::: diff --git a/docs/versioned_docs/version-v0.28.0/how_to/how-to-solidity-verifier.md b/docs/versioned_docs/version-v0.28.0/how_to/how-to-solidity-verifier.md new file mode 100644 index 00000000000..e3c7c1065da --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/how-to-solidity-verifier.md @@ -0,0 +1,231 @@ +--- +title: Generate a Solidity Verifier +description: + Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier + contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart + contract. Read more to find out +keywords: + [ + solidity verifier, + smart contract, + blockchain, + compiler, + plonk_vk.sol, + EVM blockchain, + verifying Noir programs, + proving backend, + Barretenberg, + ] +sidebar_position: 0 +pagination_next: tutorials/noirjs_app +--- + +Noir has the ability to generate a verifier contract in Solidity, which can be deployed in many EVM-compatible blockchains such as Ethereum. + +This allows for a powerful feature set, as one can make use of the conciseness and the privacy provided by Noir in an immutable ledger. Applications can range from simple P2P guessing games, to complex private DeFi interactions. + +This guide shows you how to generate a Solidity Verifier and deploy it on the [Remix IDE](https://remix.ethereum.org/). It is assumed that: + +- You are comfortable with the Solidity programming language and understand how contracts are deployed on the Ethereum network +- You have Noir installed and you have a Noir program. If you don't, [get started](../getting_started/installation/index.md) with Nargo and the example Hello Noir circuit +- You are comfortable navigating RemixIDE. If you aren't or you need a refresher, you can find some video tutorials [here](https://www.youtube.com/channel/UCjTUPyFEr2xDGN6Cg8nKDaA) that could help you. + +## Rundown + +Generating a Solidity Verifier contract is actually a one-command process. However, compiling it and deploying it can have some caveats. Here's the rundown of this guide: + +1. How to generate a solidity smart contract +2. How to compile the smart contract in the RemixIDE +3. How to deploy it to a testnet + +## Step 1 - Generate a contract + +This is by far the most straight-forward step. Just run: + +```sh +nargo codegen-verifier +``` + +A new `contract` folder would then be generated in your project directory, containing the Solidity +file `plonk_vk.sol`. It can be deployed to any EVM blockchain acting as a verifier smart contract. + +:::info + +It is possible to generate verifier contracts of Noir programs for other smart contract platforms as long as the proving backend supplies an implementation. + +Barretenberg, the default proving backend for Nargo, supports generation of verifier contracts, for the time being these are only in Solidity. +::: + +## Step 2 - Compiling + +We will mostly skip the details of RemixIDE, as the UI can change from version to version. For now, we can just open +
Remix and create a blank workspace. + +![Create Workspace](@site/static/img/how-tos/solidity_verifier_1.png) + +We will create a new file to contain the contract Nargo generated, and copy-paste its content. + +:::warning + +You'll likely see a warning advising you to not trust pasted code. While it is an important warning, it is irrelevant in the context of this guide and can be ignored. We will not be deploying anywhere near a mainnet. + +::: + +To compile our the verifier, we can navigate to the compilation tab: + +![Compilation Tab](@site/static/img/how-tos/solidity_verifier_2.png) + +Remix should automatically match a suitable compiler version. However, hitting the "Compile" button will most likely generate a "Stack too deep" error: + +![Stack too deep](@site/static/img/how-tos/solidity_verifier_3.png) + +This is due to the verify function needing to put many variables on the stack, but enabling the optimizer resolves the issue. To do this, let's open the "Advanced Configurations" tab and enable optimization. The default 200 runs will suffice. + +:::info + +This time we will see a warning about an unused function parameter. This is expected, as the `verify` function doesn't use the `_proof` parameter inside a solidity block, it is loaded from calldata and used in assembly. + +::: + +![Compilation success](@site/static/img/how-tos/solidity_verifier_4.png) + +## Step 3 - Deploying + +At this point we should have a compiled contract read to deploy. If we navigate to the deploy section in Remix, we will see many different environments we can deploy to. The steps to deploy on each environment would be out-of-scope for this guide, so we will just use the default Remix VM. + +Looking closely, we will notice that our "Solidity Verifier" is actually three contracts working together: + +- An `UltraVerificationKey` library which simply stores the verification key for our circuit. +- An abstract contract `BaseUltraVerifier` containing most of the verifying logic. +- A main `UltraVerifier` contract that inherits from the Base and uses the Key contract. + +Remix will take care of the dependencies for us so we can simply deploy the UltraVerifier contract by selecting it and hitting "deploy": + +![Deploying UltraVerifier](@site/static/img/how-tos/solidity_verifier_5.png) + +A contract will show up in the "Deployed Contracts" section, where we can retrieve the Verification Key Hash. This is particularly useful for double-checking the deployer contract is the correct one. + +:::note + +Why "UltraVerifier"? + +To be precise, the Noir compiler (`nargo`) doesn't generate the verifier contract directly. It compiles the Noir code into an intermediate language (ACIR), which is then executed by the backend. So it is the backend that returns the verifier smart contract, not Noir. + +In this case, the Barretenberg Backend uses the UltraPlonk proving system, hence the "UltraVerifier" name. + +::: + +## Step 4 - Verifying + +To verify a proof using the Solidity verifier contract, we call the `verify` function in this extended contract: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +When using the default example in the [Hello Noir](../getting_started/hello_noir/index.md) guide, the easiest way to confirm that the verifier contract is doing its job is by calling the `verify` function via remix with the required parameters. For `_proof`, run `nargo prove` and use the string in `proof/.proof` (adding the hex `0x` prefix). We can also copy the public input from `Verifier.toml`, as it will be properly formatted as 32-byte strings: + +``` +0x...... , [0x0000.....02] +``` + +A programmatic example of how the `verify` function is called can be seen in the example zk voting application [here](https://github.com/noir-lang/noir-examples/blob/33e598c257e2402ea3a6b68dd4c5ad492bce1b0a/foundry-voting/src/zkVote.sol#L35): + +```solidity +function castVote(bytes calldata proof, uint proposalId, uint vote, bytes32 nullifierHash) public returns (bool) { + // ... + bytes32[] memory publicInputs = new bytes32[](4); + publicInputs[0] = merkleRoot; + publicInputs[1] = bytes32(proposalId); + publicInputs[2] = bytes32(vote); + publicInputs[3] = nullifierHash; + require(verifier.verify(proof, publicInputs), "Invalid proof"); +``` + +:::info[Return Values] + +A circuit doesn't have the concept of a return value. Return values are just syntactic sugar in +Noir. + +Under the hood, the return value is passed as an input to the circuit and is checked at the end of +the circuit program. + +For example, if you have Noir program like this: + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +the `verify` function will expect the public inputs array (second function parameter) to be of length 3, the two inputs and the return value. Like before, these values are populated in Verifier.toml after running `nargo prove`. + +Passing only two inputs will result in an error such as `PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case, the inputs parameter to `verify` would be an array ordered as `[pubkey_x, pubkey_y, return]`. + +::: + +:::tip[Structs] + +You can pass structs to the verifier contract. They will be flattened so that the array of inputs is 1-dimensional array. + +For example, consider the following program: + +```rust +struct Type1 { + val1: Field, + val2: Field, +} + +struct Nested { + t1: Type1, + is_true: bool, +} + +fn main(x: pub Field, nested: pub Nested, y: pub Field) { + //... +} +``` + +The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +::: + +The other function you can call is our entrypoint `verify` function, as defined above. + +:::tip + +It's worth noticing that the `verify` function is actually a `view` function. A `view` function does not alter the blockchain state, so it doesn't need to be distributed (i.e. it will run only on the executing node), and therefore doesn't cost any gas. + +This can be particularly useful in some situations. If Alice generated a proof and wants Bob to verify its correctness, Bob doesn't need to run Nargo, NoirJS, or any Noir specific infrastructure. He can simply make a call to the blockchain with the proof and verify it is correct without paying any gas. + +It would be incorrect to say that a Noir proof verification costs any gas at all. However, most of the time the result of `verify` is used to modify state (for example, to update a balance, a game state, etc). In that case the whole network needs to execute it, which does incur gas costs (calldata and execution, but not storage). + +::: + +## A Note on EVM chains + +ZK-SNARK verification depends on some precompiled cryptographic primitives such as Elliptic Curve Pairings (if you like complex math, you can read about EC Pairings [here](https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627)). Not all EVM chains support EC Pairings, notably some of the ZK-EVMs. This means that you won't be able to use the verifier contract in all of them. + +For example, chains like `zkSync ERA` and `Polygon zkEVM` do not currently support these precompiles, so proof verification via Solidity verifier contracts won't work. Here's a quick list of EVM chains that have been tested and are known to work: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. + +## What's next + +Now that you know how to call a Noir Solidity Verifier on a smart contract using Remix, you should be comfortable with using it with some programmatic frameworks, such as [hardhat](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) and [foundry](https://github.com/noir-lang/noir-starter/tree/main/with-foundry). + +You can find other tools, examples, boilerplates and libraries in the [awesome-noir](https://github.com/noir-lang/awesome-noir) repository. + +You should also be ready to write and deploy your first NoirJS app and start generating proofs on websites, phones, and NodeJS environments! Head on to the [NoirJS tutorial](../tutorials/noirjs_app.md) to learn how to do that. diff --git a/docs/versioned_docs/version-v0.28.0/how_to/merkle-proof.mdx b/docs/versioned_docs/version-v0.28.0/how_to/merkle-proof.mdx new file mode 100644 index 00000000000..16c425bed76 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/merkle-proof.mdx @@ -0,0 +1,49 @@ +--- +title: Prove Merkle Tree Membership +description: + Learn how to use merkle membership proof in Noir to prove that a given leaf is a member of a + merkle tree with a specified root, at a given index. +keywords: + [merkle proof, merkle membership proof, Noir, rust, hash function, Pedersen, sha256, merkle tree] +sidebar_position: 4 +--- + +Let's walk through an example of a merkle membership proof in Noir that proves that a given leaf is +in a merkle tree. + +```rust +use dep::std; + +fn main(message : [Field; 62], index : Field, hashpath : [Field; 40], root : Field) { + let leaf = std::hash::hash_to_field(message.as_slice()); + let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); + assert(merkle_root == root); +} + +``` + +The message is hashed using `hash_to_field`. The specific hash function that is being used is chosen +by the backend. The only requirement is that this hash function can heuristically be used as a +random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen_hash` +instead. + +```rust +let leaf = std::hash::hash_to_field(message.as_slice()); +``` + +The leaf is then passed to a compute_merkle_root function with the root, index and hashpath. The returned root can then be asserted to be the same as the provided root. + +```rust +let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); +assert (merkle_root == root); +``` + +> **Note:** It is possible to re-implement the merkle tree implementation without standard library. +> However, for most usecases, it is enough. In general, the standard library will always opt to be +> as conservative as possible, while striking a balance with efficiency. + +An example, the merkle membership proof, only requires a hash function that has collision +resistance, hence a hash function like Pedersen is allowed, which in most cases is more efficient +than the even more conservative sha256. + +[View an example on the starter repo](https://github.com/noir-lang/noir-examples/blob/3ea09545cabfa464124ec2f3ea8e60c608abe6df/stealthdrop/circuits/src/main.nr#L20) diff --git a/docs/versioned_docs/version-v0.28.0/how_to/using-devcontainers.mdx b/docs/versioned_docs/version-v0.28.0/how_to/using-devcontainers.mdx new file mode 100644 index 00000000000..727ec6ca667 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/how_to/using-devcontainers.mdx @@ -0,0 +1,110 @@ +--- +title: Developer Containers and Codespaces +description: "Learn how to set up a devcontainer in your GitHub repository for a seamless coding experience with Codespaces. Follow our easy 8-step guide to create your own Noir environment without installing Nargo locally." +keywords: ["Devcontainer", "Codespaces", "GitHub", "Noir Environment", "Docker Image", "Development Environment", "Remote Coding", "GitHub Codespaces", "Noir Programming", "Nargo", "VSCode Extensions", "Noirup"] +sidebar_position: 1 +--- + +Adding a developer container configuration file to your Noir project is one of the easiest way to unlock coding in browser. + +## What's a devcontainer after all? + +A [Developer Container](https://containers.dev/) (devcontainer for short) is a Docker image that comes preloaded with tools, extensions, and other tools you need to quickly get started or continue a project, without having to install Nargo locally. Think of it as a development environment in a box. + +There are many advantages to this: + +- It's platform and architecture agnostic +- You don't need to have an IDE installed, or Nargo, or use a terminal at all +- It's safer for using on a public machine or public network + +One of the best ways of using devcontainers is... not using your machine at all, for maximum control, performance, and ease of use. +Enter Codespaces. + +## Codespaces + +If a devcontainer is just a Docker image, then what stops you from provisioning a `p3dn.24xlarge` AWS EC2 instance with 92 vCPUs and 768 GiB RAM and using it to prove your 10-gate SNARK proof? + +Nothing! Except perhaps the 30-40$ per hour it will cost you. + +The problem is that provisioning takes time, and I bet you don't want to see the AWS console every time you want to code something real quick. + +Fortunately, there's an easy and free way to get a decent remote machine ready and loaded in less than 2 minutes: Codespaces. [Codespaces is a Github feature](https://github.com/features/codespaces) that allows you to code in a remote machine by using devcontainers, and it's pretty cool: + +- You can start coding Noir in less than a minute +- It uses the resources of a remote machine, so you can code on your grandma's phone if needed be +- It makes it easy to share work with your frens +- It's fully reusable, you can stop and restart whenever you need to + +:::info + +Don't take out your wallet just yet. Free GitHub accounts get about [15-60 hours of coding](https://github.com/features/codespaces) for free per month, depending on the size of your provisioned machine. + +::: + +## Tell me it's _actually_ easy + +It is! + +Github comes with a default codespace and you can use it to code your own devcontainer. That's exactly what we will be doing in this guide. + + + +8 simple steps: + +#### 1. Create a new repository on GitHub. + +#### 2. Click "Start coding with Codespaces". This will use the default image. + +#### 3. Create a folder called `.devcontainer` in the root of your repository. + +#### 4. Create a Dockerfile in that folder, and paste the following code: + +```docker +FROM --platform=linux/amd64 node:lts-bookworm-slim +SHELL ["/bin/bash", "-c"] +RUN apt update && apt install -y curl bash git tar gzip libc++-dev +RUN curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +ENV PATH="/root/.nargo/bin:$PATH" +RUN noirup +ENTRYPOINT ["nargo"] +``` +#### 5. Create a file called `devcontainer.json` in the same folder, and paste the following code: + +```json +{ + "name": "Noir on Codespaces", + "build": { + "context": ".", + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "extensions": ["noir-lang.vscode-noir"] + } + } +} +``` +#### 6. Commit and push your changes + +This will pull the new image and build it, so it could take a minute or so + +#### 8. Done! +Just wait for the build to finish, and there's your easy Noir environment. + + +Refer to [noir-starter](https://github.com/noir-lang/noir-starter/) as an example of how devcontainers can be used together with codespaces. + + + +## How do I use it? + +Using the codespace is obviously much easier than setting it up. +Just navigate to your repository and click "Code" -> "Open with Codespaces". It should take a few seconds to load, and you're ready to go. + +:::info + +If you really like the experience, you can add a badge to your readme, links to existing codespaces, and more. +Check out the [official docs](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/setting-up-your-repository/facilitating-quick-creation-and-resumption-of-codespaces) for more info. diff --git a/docs/versioned_docs/version-v0.28.0/index.mdx b/docs/versioned_docs/version-v0.28.0/index.mdx new file mode 100644 index 00000000000..75086ddcdde --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/index.mdx @@ -0,0 +1,67 @@ +--- +title: Noir Lang +hide_title: true +description: + Learn about the public alpha release of Noir, a domain specific language heavily influenced by Rust that compiles to + an intermediate language which can be compiled to an arithmetic circuit or a rank-1 constraint system. +keywords: + [Noir, + Domain Specific Language, + Rust, + Intermediate Language, + Arithmetic Circuit, + Rank-1 Constraint System, + Ethereum Developers, + Protocol Developers, + Blockchain Developers, + Proving System, + Smart Contract Language] +sidebar_position: 0 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Noir Logo + +Noir is a Domain-Specific Language for SNARK proving systems developed by [Aztec Labs](https://aztec.network/). It allows you to generate complex Zero-Knowledge Programs (ZKP) by using simple and flexible syntax, requiring no previous knowledge on the underlying mathematics or cryptography. + +ZK programs are programs that can generate short proofs of a certain statement without revealing some details about it. You can read more about ZKPs [here](https://dev.to/spalladino/a-beginners-intro-to-coding-zero-knowledge-proofs-c56). + +## What's new about Noir? + +Noir works differently from most ZK languages by taking a two-pronged path. First, it compiles the program to an adaptable intermediate language known as ACIR. From there, depending on a given project's needs, ACIR can be further compiled into an arithmetic circuit for integration with the proving backend. + +:::info + +Noir is backend agnostic, which means it makes no assumptions on which proving backend powers the ZK proof. Being the language that powers [Aztec Contracts](https://docs.aztec.network/developers/contracts/main), it defaults to Aztec's Barretenberg proving backend. + +However, the ACIR output can be transformed to be compatible with other PLONK-based backends, or into a [rank-1 constraint system](https://www.rareskills.io/post/rank-1-constraint-system) suitable for backends such as Arkwork's Marlin. + +::: + +## Who is Noir for? + +Noir can be used both in complex cloud-based backends and in user's smartphones, requiring no knowledge on the underlying math or cryptography. From authorization systems that keep a password in the user's device, to complex on-chain verification of recursive proofs, Noir is designed to abstract away complexity without any significant overhead. Here are some examples of situations where Noir can be used: + + + + Noir Logo + + Aztec Contracts leverage Noir to allow for the storage and execution of private information. Writing an Aztec Contract is as easy as writing Noir, and Aztec developers can easily interact with the network storage and execution through the [Aztec.nr](https://docs.aztec.network/developers/contracts/main) library. + + + Soliditry Verifier Example + Noir can auto-generate Solidity verifier contracts that verify Noir proofs. This allows for non-interactive verification of proofs containing private information in an immutable system. This feature powers a multitude of use-case scenarios, from P2P chess tournaments, to [Aztec Layer-2 Blockchain](https://docs.aztec.network/) + + + Aztec Labs developed NoirJS, an easy interface to generate and verify Noir proofs in a Javascript environment. This allows for Noir to be used in webpages, mobile apps, games, and any other environment supporting JS execution in a standalone manner. + + + + +## Libraries + +Noir is meant to be easy to extend by simply importing Noir libraries just like in Rust. +The [awesome-noir repo](https://github.com/noir-lang/awesome-noir#libraries) is a collection of libraries developed by the Noir community. +Writing a new library is easy and makes code be composable and easy to reuse. See the section on [dependencies](noir/modules_packages_crates/dependencies.md) for more information. diff --git a/docs/versioned_docs/version-v0.28.0/migration_notes.md b/docs/versioned_docs/version-v0.28.0/migration_notes.md new file mode 100644 index 00000000000..6bd740024e5 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/migration_notes.md @@ -0,0 +1,105 @@ +--- +title: Migration notes +description: Read about migration notes from previous versions, which could solve problems while updating +keywords: [Noir, notes, migration, updating, upgrading] +--- + +Noir is in full-speed development. Things break fast, wild, and often. This page attempts to leave some notes on errors you might encounter when upgrading and how to resolve them until proper patches are built. + +### `backend encountered an error: libc++.so.1` + +Depending on your OS, you may encounter the following error when running `nargo prove` for the first time: + +```text +The backend encountered an error: "/home/codespace/.nargo/backends/acvm-backend-barretenberg/backend_binary: error while loading shared libraries: libc++.so.1: cannot open shared object file: No such file or directory\n" +``` + +Install the `libc++-dev` library with: + +```bash +sudo apt install libc++-dev +``` + +## ≥0.19 + +### Enforcing `compiler_version` + +From this version on, the compiler will check for the `compiler_version` field in `Nargo.toml`, and will error if it doesn't match the current Nargo version in use. + +To update, please make sure this field in `Nargo.toml` matches the output of `nargo --version`. + +## ≥0.14 + +The index of the [for loops](noir/concepts/control_flow.md#loops) is now of type `u64` instead of `Field`. An example refactor would be: + +```rust +for i in 0..10 { + let i = i as Field; +} +``` + +## ≥v0.11.0 and Nargo backend + +From this version onwards, Nargo starts managing backends through the `nargo backend` command. Upgrading to the versions per usual steps might lead to: + +### `backend encountered an error` + +This is likely due to the existing locally installed version of proving backend (e.g. barretenberg) is incompatible with the version of Nargo in use. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo prove +``` + +with your Noir program. + +This will trigger the download and installation of the latest version of barretenberg compatible with your Nargo in use. + +### `backend encountered an error: illegal instruction` + +On certain Intel-based systems, an `illegal instruction` error may arise due to incompatibility of barretenberg with certain CPU instructions. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/barretenberg-js-binary/raw/master/run-bb.tar.gz +``` + +This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. + +The gzipped file is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. + +Then run: + +``` +DESIRED_BINARY_VERSION=0.8.1 nargo info +``` + +This overrides the bb native binary with a bb.js node application instead, which should be compatible with most if not all hardware. This does come with the drawback of being generally slower than native binary. + +0.8.1 indicates bb.js version 0.8.1, so if you change that it will update to a different version or the default version in the script if none was supplied. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/_category_.json b/docs/versioned_docs/version-v0.28.0/noir/concepts/_category_.json new file mode 100644 index 00000000000..7da08f8a8c5 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Concepts", + "position": 0, + "collapsible": true, + "collapsed": true +} \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/assert.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/assert.md new file mode 100644 index 00000000000..bcff613a695 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/assert.md @@ -0,0 +1,45 @@ +--- +title: Assert Function +description: + Learn about the assert function in Noir, which can be used to explicitly constrain the predicate or + comparison expression that follows to be true, and what happens if the expression is false at + runtime. +keywords: [Noir programming language, assert statement, predicate expression, comparison expression] +sidebar_position: 4 +--- + +Noir includes a special `assert` function which will explicitly constrain the predicate/comparison +expression that follows to be true. If this expression is false at runtime, the program will fail to +be proven. Example: + +```rust +fn main(x : Field, y : Field) { + assert(x == y); +} +``` + +> Assertions only work for predicate operations, such as `==`. If there's any ambiguity on the operation, the program will fail to compile. For example, it is unclear if `assert(x + y)` would check for `x + y == 0` or simply would return `true`. + +You can optionally provide a message to be logged when the assertion fails: + +```rust +assert(x == y, "x and y are not equal"); +``` + +Aside string literals, the optional message can be a format string or any other type supported as input for Noir's [print](../standard_library/logging.md) functions. This feature lets you incorporate runtime variables into your failed assertion logs: + +```rust +assert(x == y, f"Expected x == y, but got {x} == {y}"); +``` + +Using a variable as an assertion message directly: + +```rust +struct myStruct { + myField: Field +} + +let s = myStruct { myField: y }; +assert(s.myField == x, s); +``` + diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/comments.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/comments.md new file mode 100644 index 00000000000..b51a85f5c94 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/comments.md @@ -0,0 +1,33 @@ +--- +title: Comments +description: + Learn how to write comments in Noir programming language. A comment is a line of code that is + ignored by the compiler, but it can be read by programmers. Single-line and multi-line comments + are supported in Noir. +keywords: [Noir programming language, comments, single-line comments, multi-line comments] +sidebar_position: 10 +--- + +A comment is a line in your codebase which the compiler ignores, however it can be read by +programmers. + +Here is a single line comment: + +```rust +// This is a comment and is ignored +``` + +`//` is used to tell the compiler to ignore the rest of the line. + +Noir also supports multi-line block comments. Start a block comment with `/*` and end the block with `*/`. + +Noir does not natively support doc comments. You may be able to use [Rust doc comments](https://doc.rust-lang.org/reference/comments.html) in your code to leverage some Rust documentation build tools with Noir code. + +```rust +/* + This is a block comment describing a complex function. +*/ +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/control_flow.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/control_flow.md new file mode 100644 index 00000000000..045d3c3a5f5 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/control_flow.md @@ -0,0 +1,77 @@ +--- +title: Control Flow +description: + Learn how to use loops and if expressions in the Noir programming language. Discover the syntax + and examples for for loops and if-else statements. +keywords: [Noir programming language, loops, for loop, if-else statements, Rust syntax] +sidebar_position: 2 +--- + +## If Expressions + +Noir supports `if-else` statements. The syntax is most similar to Rust's where it is not required +for the statement's conditional to be surrounded by parentheses. + +```rust +let a = 0; +let mut x: u32 = 0; + +if a == 0 { + if a != 0 { + x = 6; + } else { + x = 2; + } +} else { + x = 5; + assert(x == 5); +} +assert(x == 2); +``` + +## Loops + +Noir has one kind of loop: the `for` loop. `for` loops allow you to repeat a block of code multiple +times. + +The following block of code between the braces is run 10 times. + +```rust +for i in 0..10 { + // do something +} +``` + +The index for loops is of type `u64`. + +### Break and Continue + +In unconstrained code, `break` and `continue` are also allowed in `for` loops. These are only allowed +in unconstrained code since normal constrained code requires that Noir knows exactly how many iterations +a loop may have. `break` and `continue` can be used like so: + +```rust +for i in 0 .. 10 { + println("Iteration start") + + if i == 2 { + continue; + } + + if i == 5 { + break; + } + + println(i); +} +println("Loop end") +``` + +When used, `break` will end the current loop early and jump to the statement after the for loop. In the example +above, the `break` will stop the loop and jump to the `println("Loop end")`. + +`continue` will stop the current iteration of the loop, and jump to the start of the next iteration. In the example +above, `continue` will jump to `println("Iteration start")` when used. Note that the loop continues as normal after this. +The iteration variable `i` is still increased by one as normal when `continue` is used. + +`break` and `continue` cannot currently be used to jump out of more than a single loop at a time. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_bus.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_bus.md new file mode 100644 index 00000000000..e54fc861257 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_bus.md @@ -0,0 +1,21 @@ +--- +title: Data Bus +sidebar_position: 13 +--- +**Disclaimer** this feature is experimental, do not use it! + +The data bus is an optimization that the backend can use to make recursion more efficient. +In order to use it, you must define some inputs of the program entry points (usually the `main()` +function) with the `call_data` modifier, and the return values with the `return_data` modifier. +These modifiers are incompatible with `pub` and `mut` modifiers. + +## Example + +```rust +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { + let a = z[x]; + a+y +} +``` + +As a result, both call_data and return_data will be treated as private inputs and encapsulated into a read-only array each, for the backend to process. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/_category_.json b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/arrays.md new file mode 100644 index 00000000000..efce3e95d32 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/arrays.md @@ -0,0 +1,251 @@ +--- +title: Arrays +description: + Dive into the Array data type in Noir. Grasp its methods, practical examples, and best practices for efficiently using Arrays in your Noir code. +keywords: + [ + noir, + array type, + methods, + examples, + indexing, + ] +sidebar_position: 4 +--- + +An array is one way of grouping together values into one compound type. Array types can be inferred +or explicitly specified via the syntax `[; ]`: + +```rust +fn main(x : Field, y : Field) { + let my_arr = [x, y]; + let your_arr: [Field; 2] = [x, y]; +} +``` + +Here, both `my_arr` and `your_arr` are instantiated as an array containing two `Field` elements. + +Array elements can be accessed using indexing: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; + + let first = a[0]; + let second = a[1]; +} +``` + +All elements in an array must be of the same type (i.e. homogeneous). That is, an array cannot group +a `Field` value and a `u8` value together for example. + +You can write mutable arrays, like: + +```rust +fn main() { + let mut arr = [1, 2, 3, 4, 5]; + assert(arr[0] == 1); + + arr[0] = 42; + assert(arr[0] == 42); +} +``` + +You can instantiate a new array of a fixed size with the same value repeated for each element. The following example instantiates an array of length 32 where each element is of type Field and has the value 0. + +```rust +let array: [Field; 32] = [0; 32]; +``` + +Like in Rust, arrays in Noir are a fixed size. However, if you wish to convert an array to a [slice](./slices), you can just call `as_slice` on your array: + +```rust +let array: [Field; 32] = [0; 32]; +let sl = array.as_slice() +``` + +You can define multidimensional arrays: + +```rust +let array : [[Field; 2]; 2]; +let element = array[0][0]; +``` +However, multidimensional slices are not supported. For example, the following code will error at compile time: +```rust +let slice : [[Field]] = &[]; +``` + +## Types + +You can create arrays of primitive types or structs. There is not yet support for nested arrays +(arrays of arrays) or arrays of structs that contain arrays. + +## Methods + +For convenience, the STD provides some ready-to-use, common methods for arrays. +Each of these functions are located within the generic impl `impl [T; N] {`. +So anywhere `self` appears, it refers to the variable `self: [T; N]`. + +### len + +Returns the length of an array + +```rust +fn len(self) -> Field +``` + +example + +```rust +fn main() { + let array = [42, 42]; + assert(array.len() == 2); +} +``` + +### sort + +Returns a new sorted array. The original array remains untouched. Notice that this function will +only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting +logic it uses internally is optimized specifically for these values. If you need a sort function to +sort any type, you should use the function `sort_via` described below. + +```rust +fn sort(self) -> [T; N] +``` + +example + +```rust +fn main() { + let arr = [42, 32]; + let sorted = arr.sort(); + assert(sorted == [32, 42]); +} +``` + +### sort_via + +Sorts the array with a custom comparison function + +```rust +fn sort_via(self, ordering: fn(T, T) -> bool) -> [T; N] +``` + +example + +```rust +fn main() { + let arr = [42, 32] + let sorted_ascending = arr.sort_via(|a, b| a < b); + assert(sorted_ascending == [32, 42]); // verifies + + let sorted_descending = arr.sort_via(|a, b| a > b); + assert(sorted_descending == [32, 42]); // does not verify +} +``` + +### map + +Applies a function to each element of the array, returning a new array containing the mapped elements. + +```rust +fn map(self, f: fn(T) -> U) -> [U; N] +``` + +example + +```rust +let a = [1, 2, 3]; +let b = a.map(|a| a * 2); // b is now [2, 4, 6] +``` + +### fold + +Applies a function to each element of the array, returning the final accumulated value. The first +parameter is the initial value. + +```rust +fn fold(self, mut accumulator: U, f: fn(U, T) -> U) -> U +``` + +This is a left fold, so the given function will be applied to the accumulator and first element of +the array, then the second, and so on. For a given call the expected result would be equivalent to: + +```rust +let a1 = [1]; +let a2 = [1, 2]; +let a3 = [1, 2, 3]; + +let f = |a, b| a - b; +a1.fold(10, f) //=> f(10, 1) +a2.fold(10, f) //=> f(f(10, 1), 2) +a3.fold(10, f) //=> f(f(f(10, 1), 2), 3) +``` + +example: + +```rust + +fn main() { + let arr = [2, 2, 2, 2, 2]; + let folded = arr.fold(0, |a, b| a + b); + assert(folded == 10); +} + +``` + +### reduce + +Same as fold, but uses the first element as starting element. + +```rust +fn reduce(self, f: fn(T, T) -> T) -> T +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 2]; + let reduced = arr.reduce(|a, b| a + b); + assert(reduced == 10); +} +``` + +### all + +Returns true if all the elements satisfy the given predicate + +```rust +fn all(self, predicate: fn(T) -> bool) -> bool +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 2]; + let all = arr.all(|a| a == 2); + assert(all); +} +``` + +### any + +Returns true if any of the elements satisfy the given predicate + +```rust +fn any(self, predicate: fn(T) -> bool) -> bool +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 5]; + let any = arr.any(|a| a == 5); + assert(any); +} + +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/booleans.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/booleans.md new file mode 100644 index 00000000000..69826fcd724 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/booleans.md @@ -0,0 +1,31 @@ +--- +title: Booleans +description: + Delve into the Boolean data type in Noir. Understand its methods, practical examples, and best practices for using Booleans in your Noir programs. +keywords: + [ + noir, + boolean type, + methods, + examples, + logical operations, + ] +sidebar_position: 2 +--- + + +The `bool` type in Noir has two possible values: `true` and `false`: + +```rust +fn main() { + let t = true; + let f: bool = false; +} +``` + +> **Note:** When returning a boolean value, it will show up as a value of 1 for `true` and 0 for +> `false` in _Verifier.toml_. + +The boolean type is most commonly used in conditionals like `if` expressions and `assert` +statements. More about conditionals is covered in the [Control Flow](../control_flow) and +[Assert Function](../assert) sections. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/fields.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/fields.md new file mode 100644 index 00000000000..a10a4810788 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/fields.md @@ -0,0 +1,192 @@ +--- +title: Fields +description: + Dive deep into the Field data type in Noir. Understand its methods, practical examples, and best practices to effectively use Fields in your Noir programs. +keywords: + [ + noir, + field type, + methods, + examples, + best practices, + ] +sidebar_position: 0 +--- + +The field type corresponds to the native field type of the proving backend. + +The size of a Noir field depends on the elliptic curve's finite field for the proving backend +adopted. For example, a field would be a 254-bit integer when paired with the default backend that +spans the Grumpkin curve. + +Fields support integer arithmetic and are often used as the default numeric type in Noir: + +```rust +fn main(x : Field, y : Field) { + let z = x + y; +} +``` + +`x`, `y` and `z` are all private fields in this example. Using the `let` keyword we defined a new +private value `z` constrained to be equal to `x + y`. + +If proving efficiency is of priority, fields should be used as a default for solving problems. +Smaller integer types (e.g. `u64`) incur extra range constraints. + +## Methods + +After declaring a Field, you can use these common methods on it: + +### to_le_bits + +Transforms the field into an array of bits, Little Endian. + +```rust +fn to_le_bits(_x : Field, _bit_size: u32) -> [u1] +``` + +example: + +```rust +fn main() { + let field = 2; + let bits = field.to_le_bits(32); +} +``` + +### to_be_bits + +Transforms the field into an array of bits, Big Endian. + +```rust +fn to_be_bits(_x : Field, _bit_size: u32) -> [u1] +``` + +example: + +```rust +fn main() { + let field = 2; + let bits = field.to_be_bits(32); +} +``` + +### to_le_bytes + +Transforms into an array of bytes, Little Endian + +```rust +fn to_le_bytes(_x : Field, byte_size: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let bytes = field.to_le_bytes(4); +} +``` + +### to_be_bytes + +Transforms into an array of bytes, Big Endian + +```rust +fn to_be_bytes(_x : Field, byte_size: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let bytes = field.to_be_bytes(4); +} +``` + +### to_le_radix + +Decomposes into a vector over the specified base, Little Endian + +```rust +fn to_le_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let radix = field.to_le_radix(256, 4); +} +``` + +### to_be_radix + +Decomposes into a vector over the specified base, Big Endian + +```rust +fn to_be_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let radix = field.to_be_radix(256, 4); +} +``` + +### pow_32 + +Returns the value to the power of the specified exponent + +```rust +fn pow_32(self, exponent: Field) -> Field +``` + +example: + +```rust +fn main() { + let field = 2 + let pow = field.pow_32(4); + assert(pow == 16); +} +``` + +### assert_max_bit_size + +Adds a constraint to specify that the field can be represented with `bit_size` number of bits + +```rust +fn assert_max_bit_size(self, bit_size: u32) +``` + +example: + +```rust +fn main() { + let field = 2 + field.assert_max_bit_size(32); +} +``` + +### sgn0 + +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. + +```rust +fn sgn0(self) -> u1 +``` + + +### lt + +Returns true if the field is less than the other field + +```rust +pub fn lt(self, another: Field) -> bool +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/function_types.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/function_types.md new file mode 100644 index 00000000000..f6121af17e2 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/function_types.md @@ -0,0 +1,26 @@ +--- +title: Function types +sidebar_position: 10 +--- + +Noir supports higher-order functions. The syntax for a function type is as follows: + +```rust +fn(arg1_type, arg2_type, ...) -> return_type +``` + +Example: + +```rust +fn assert_returns_100(f: fn() -> Field) { // f takes no args and returns a Field + assert(f() == 100); +} + +fn main() { + assert_returns_100(|| 100); // ok + assert_returns_100(|| 150); // fails +} +``` + +A function type also has an optional capture environment - this is necessary to support closures. +See [Lambdas](../lambdas.md) for more details. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/index.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/index.md new file mode 100644 index 00000000000..357813c147a --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/index.md @@ -0,0 +1,110 @@ +--- +title: Data Types +description: + Get a clear understanding of the two categories of Noir data types - primitive types and compound + types. Learn about their characteristics, differences, and how to use them in your Noir + programming. +keywords: + [ + noir, + data types, + primitive types, + compound types, + private types, + public types, + ] +--- + +Every value in Noir has a type, which determines which operations are valid for it. + +All values in Noir are fundamentally composed of `Field` elements. For a more approachable +developing experience, abstractions are added on top to introduce different data types in Noir. + +Noir has two category of data types: primitive types (e.g. `Field`, integers, `bool`) and compound +types that group primitive types (e.g. arrays, tuples, structs). Each value can either be private or +public. + +## Private & Public Types + +A **private value** is known only to the Prover, while a **public value** is known by both the +Prover and Verifier. Mark values as `private` when the value should only be known to the prover. All +primitive types (including individual fields of compound types) in Noir are private by default, and +can be marked public when certain values are intended to be revealed to the Verifier. + +> **Note:** For public values defined in Noir programs paired with smart contract verifiers, once +> the proofs are verified on-chain the values can be considered known to everyone that has access to +> that blockchain. + +Public data types are treated no differently to private types apart from the fact that their values +will be revealed in proofs generated. Simply changing the value of a public type will not change the +circuit (where the same goes for changing values of private types as well). + +_Private values_ are also referred to as _witnesses_ sometimes. + +> **Note:** The terms private and public when applied to a type (e.g. `pub Field`) have a different +> meaning than when applied to a function (e.g. `pub fn foo() {}`). +> +> The former is a visibility modifier for the Prover to interpret if a value should be made known to +> the Verifier, while the latter is a visibility modifier for the compiler to interpret if a +> function should be made accessible to external Noir programs like in other languages. + +### pub Modifier + +All data types in Noir are private by default. Types are explicitly declared as public using the +`pub` modifier: + +```rust +fn main(x : Field, y : pub Field) -> pub Field { + x + y +} +``` + +In this example, `x` is **private** while `y` and `x + y` (the return value) are **public**. Note +that visibility is handled **per variable**, so it is perfectly valid to have one input that is +private and another that is public. + +> **Note:** Public types can only be declared through parameters on `main`. + +## Type Aliases + +A type alias is a new name for an existing type. Type aliases are declared with the keyword `type`: + +```rust +type Id = u8; + +fn main() { + let id: Id = 1; + let zero: u8 = 0; + assert(zero + 1 == id); +} +``` + +Type aliases can also be used with [generics](../generics.md): + +```rust +type Id = Size; + +fn main() { + let id: Id = 1; + let zero: u32 = 0; + assert(zero + 1 == id); +} +``` + +Type aliases can even refer to other aliases. An error will be issued if they form a cycle: + +```rust +// Ok! +type A = B; +type B = Field; + +type Bad1 = Bad2; + +// error: Dependency cycle found +type Bad2 = Bad1; +// ^^^^^^^^^^^ 'Bad2' recursively depends on itself: Bad2 -> Bad1 -> Bad2 +``` + +### BigInt + +You can achieve BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/integers.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/integers.md new file mode 100644 index 00000000000..1c6b375db49 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/integers.md @@ -0,0 +1,155 @@ +--- +title: Integers +description: Explore the Integer data type in Noir. Learn about its methods, see real-world examples, and grasp how to efficiently use Integers in your Noir code. +keywords: [noir, integer types, methods, examples, arithmetic] +sidebar_position: 1 +--- + +An integer type is a range constrained field type. The Noir frontend supports both unsigned and signed integer types. The allowed sizes are 1, 8, 32 and 64 bits. + +:::info + +When an integer is defined in Noir without a specific type, it will default to `Field`. + +The one exception is for loop indices which default to `u64` since comparisons on `Field`s are not possible. + +::: + +## Unsigned Integers + +An unsigned integer type is specified first with the letter `u` (indicating its unsigned nature) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: u8 = 1; + let y: u8 = 1; + let z = x + y; + assert (z == 2); +} +``` + +The bit size determines the maximum value the integer type can store. For example, a `u8` variable can store a value in the range of 0 to 255 (i.e. $\\2^{8}-1\\$). + +## Signed Integers + +A signed integer type is specified first with the letter `i` (which stands for integer) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: i8 = -1; + let y: i8 = -1; + let z = x + y; + assert (z == -2); +} +``` + +The bit size determines the maximum and minimum range of value the integer type can store. For example, an `i8` variable can store a value in the range of -128 to 127 (i.e. $\\-2^{7}\\$ to $\\2^{7}-1\\$). + +## 128 bits Unsigned Integers + +The built-in structure `U128` allows you to use 128-bit unsigned integers almost like a native integer type. However, there are some differences to keep in mind: +- You cannot cast between a native integer and `U128` +- There is a higher performance cost when using `U128`, compared to a native type. + +Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. `from_integer` also accepts the `Field` type as input. + +```rust +fn main() { + let x = U128::from_integer(23); + let y = U128::from_hex("0x7"); + let z = x + y; + assert(z.to_integer() == 30); +} +``` + +`U128` is implemented with two 64 bits limbs, representing the low and high bits, which explains the performance cost. You should expect `U128` to be twice more costly for addition and four times more costly for multiplication. +You can construct a U128 from its limbs: +```rust +fn main(x: u64, y: u64) { + let x = U128::from_u64s_be(x,y); + assert(z.hi == x as Field); + assert(z.lo == y as Field); +} +``` + +Note that the limbs are stored as Field elements in order to avoid unnecessary conversions. +Apart from this, most operations will work as usual: + +```rust +fn main(x: U128, y: U128) { + // multiplication + let c = x * y; + // addition and subtraction + let c = c - x + y; + // division + let c = x / y; + // bit operation; + let c = x & y | y; + // bit shift + let c = x << y; + // comparisons; + let c = x < y; + let c = x == y; +} +``` + +## Overflows + +Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: + +```rust +fn main(x: u8, y: u8) { + let z = x + y; +} +``` + +With: + +```toml +x = "255" +y = "1" +``` + +Would result in: + +``` +$ nargo prove +error: Assertion failed: 'attempt to add with overflow' +┌─ ~/src/main.nr:9:13 +│ +│ let z = x + y; +│ ----- +│ += Call stack: + ... +``` + +A similar error would happen with signed integers: + +```rust +fn main() { + let x: i8 = -118; + let y: i8 = -11; + let z = x + y; +} +``` + +### Wrapping methods + +Although integer overflow is expected to error, some use-cases rely on wrapping. For these use-cases, the standard library provides `wrapping` variants of certain common operations: + +```rust +fn wrapping_add(x: T, y: T) -> T; +fn wrapping_sub(x: T, y: T) -> T; +fn wrapping_mul(x: T, y: T) -> T; +``` + +Example of how it is used: + +```rust +use dep::std; + +fn main(x: u8, y: u8) -> pub u8 { + std::wrapping_add(x, y) +} +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/references.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/references.md new file mode 100644 index 00000000000..a5293d11cfb --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/references.md @@ -0,0 +1,23 @@ +--- +title: References +sidebar_position: 9 +--- + +Noir supports first-class references. References are a bit like pointers: they point to a specific address that can be followed to access the data stored at that address. You can use Rust-like syntax to use pointers in Noir: the `&` operator references the variable, the `*` operator dereferences it. + +Example: + +```rust +fn main() { + let mut x = 2; + + // you can reference x as &mut and pass it to multiplyBy2 + multiplyBy2(&mut x); +} + +// you can access &mut here +fn multiplyBy2(x: &mut Field) { + // and dereference it with * + *x = *x * 2; +} +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/slices.mdx b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/slices.mdx new file mode 100644 index 00000000000..4eccc677b80 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/slices.mdx @@ -0,0 +1,195 @@ +--- +title: Slices +description: Explore the Slice data type in Noir. Understand its methods, see real-world examples, and learn how to effectively use Slices in your Noir programs. +keywords: [noir, slice type, methods, examples, subarrays] +sidebar_position: 5 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A slice is a dynamically-sized view into a sequence of elements. They can be resized at runtime, but because they don't own the data, they cannot be returned from a circuit. You can treat slices as arrays without a constrained size. + +```rust +use dep::std::slice; + +fn main() -> pub Field { + let mut slice: [Field] = &[0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice.len() +} +``` + +To write a slice literal, use a preceeding ampersand as in: `&[0; 2]` or +`&[1, 2, 3]`. + +It is important to note that slices are not references to arrays. In Noir, +`&[..]` is more similar to an immutable, growable vector. + +View the corresponding test file [here][test-file]. + +[test-file]: https://github.com/noir-lang/noir/blob/f387ec1475129732f72ba294877efdf6857135ac/crates/nargo_cli/tests/test_data_ssa_refactor/slices/src/main.nr + +## Methods + +For convenience, the STD provides some ready-to-use, common methods for slices: + +### push_back + +Pushes a new element to the end of the slice, returning a new slice with a length one greater than the original unmodified slice. + +```rust +fn push_back(_self: [T], _elem: T) -> [T] +``` + +example: + +```rust +fn main() -> pub Field { + let mut slice: [Field] = &[0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice.len() +} +``` + +View the corresponding test file [here][test-file]. + +### push_front + +Returns a new array with the specified element inserted at index 0. The existing elements indexes are incremented by 1. + +```rust +fn push_front(_self: Self, _elem: T) -> Self +``` + +Example: + +```rust +let mut new_slice: [Field] = &[]; +new_slice = new_slice.push_front(20); +assert(new_slice[0] == 20); // returns true +``` + +View the corresponding test file [here][test-file]. + +### pop_front + +Returns a tuple of two items, the first element of the array and the rest of the array. + +```rust +fn pop_front(_self: Self) -> (T, Self) +``` + +Example: + +```rust +let (first_elem, rest_of_slice) = slice.pop_front(); +``` + +View the corresponding test file [here][test-file]. + +### pop_back + +Returns a tuple of two items, the beginning of the array with the last element omitted and the last element. + +```rust +fn pop_back(_self: Self) -> (Self, T) +``` + +Example: + +```rust +let (popped_slice, last_elem) = slice.pop_back(); +``` + +View the corresponding test file [here][test-file]. + +### append + +Loops over a slice and adds it to the end of another. + +```rust +fn append(mut self, other: Self) -> Self +``` + +Example: + +```rust +let append = &[1, 2].append(&[3, 4, 5]); +``` + +### insert + +Inserts an element at a specified index and shifts all following elements by 1. + +```rust +fn insert(_self: Self, _index: Field, _elem: T) -> Self +``` + +Example: + +```rust +new_slice = rest_of_slice.insert(2, 100); +assert(new_slice[2] == 100); +``` + +View the corresponding test file [here][test-file]. + +### remove + +Remove an element at a specified index, shifting all elements after it to the left, returning the altered slice and the removed element. + +```rust +fn remove(_self: Self, _index: Field) -> (Self, T) +``` + +Example: + +```rust +let (remove_slice, removed_elem) = slice.remove(3); +``` + +### len + +Returns the length of a slice + +```rust +fn len(self) -> Field +``` + +Example: + +```rust +fn main() { + let slice = &[42, 42]; + assert(slice.len() == 2); +} +``` + +### as_array + +Converts this slice into an array. + +Make sure to specify the size of the resulting array. +Panics if the resulting array length is different than the slice's length. + +```rust +fn as_array(self) -> [T; N] +``` + +Example: + +```rust +fn main() { + let slice = &[5, 6]; + + // Always specify the length of the resulting array! + let array: [Field; 2] = slice.as_array(); + + assert(array[0] == slice[0]); + assert(array[1] == slice[1]); +} +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/strings.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/strings.md new file mode 100644 index 00000000000..311dfd64416 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/strings.md @@ -0,0 +1,80 @@ +--- +title: Strings +description: + Discover the String data type in Noir. Learn about its methods, see real-world examples, and understand how to effectively manipulate and use Strings in Noir. +keywords: + [ + noir, + string type, + methods, + examples, + concatenation, + ] +sidebar_position: 3 +--- + + +The string type is a fixed length value defined with `str`. + +You can use strings in `assert()` functions or print them with +`println()`. See more about [Logging](../../standard_library/logging). + +```rust +use dep::std; + +fn main(message : pub str<11>, hex_as_string : str<4>) { + println(message); + assert(message == "hello world"); + assert(hex_as_string == "0x41"); +} +``` + +You can convert a `str` to a byte array by calling `as_bytes()` +or a vector by calling `as_bytes_vec()`. + +```rust +fn main() { + let message = "hello world"; + let message_bytes = message.as_bytes(); + let mut message_vec = message.as_bytes_vec(); + assert(message_bytes.len() == 11); + assert(message_bytes[0] == 104); + assert(message_bytes[0] == message_vec.get(0)); +} +``` + +## Escape characters + +You can use escape characters for your strings: + +| Escape Sequence | Description | +|-----------------|-----------------| +| `\r` | Carriage Return | +| `\n` | Newline | +| `\t` | Tab | +| `\0` | Null Character | +| `\"` | Double Quote | +| `\\` | Backslash | + +Example: + +```rust +let s = "Hello \"world" // prints "Hello "world" +let s = "hey \tyou"; // prints "hey you" +``` + +## Raw strings + +A raw string begins with the letter `r` and is optionally delimited by a number of hashes `#`. + +Escape characters are *not* processed within raw strings. All contents are interpreted literally. + +Example: + +```rust +let s = r"Hello world"; +let s = r#"Simon says "hello world""#; + +// Any number of hashes may be used (>= 1) as long as the string also terminates with the same number of hashes +let s = r#####"One "#, Two "##, Three "###, Four "####, Five will end the string."#####; +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/structs.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/structs.md new file mode 100644 index 00000000000..dbf68c99813 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/structs.md @@ -0,0 +1,70 @@ +--- +title: Structs +description: + Explore the Struct data type in Noir. Learn about its methods, see real-world examples, and grasp how to effectively define and use Structs in your Noir programs. +keywords: + [ + noir, + struct type, + methods, + examples, + data structures, + ] +sidebar_position: 8 +--- + +A struct also allows for grouping multiple values of different types. Unlike tuples, we can also +name each field. + +> **Note:** The usage of _field_ here refers to each element of the struct and is unrelated to the +> field type of Noir. + +Defining a struct requires giving it a name and listing each field within as `: ` pairs: + +```rust +struct Animal { + hands: Field, + legs: Field, + eyes: u8, +} +``` + +An instance of a struct can then be created with actual values in `: ` pairs in any +order. Struct fields are accessible using their given names: + +```rust +fn main() { + let legs = 4; + + let dog = Animal { + eyes: 2, + hands: 0, + legs, + }; + + let zero = dog.hands; +} +``` + +Structs can also be destructured in a pattern, binding each field to a new variable: + +```rust +fn main() { + let Animal { hands, legs: feet, eyes } = get_octopus(); + + let ten = hands + feet + eyes as u8; +} + +fn get_octopus() -> Animal { + let octopus = Animal { + hands: 0, + legs: 8, + eyes: 2, + }; + + octopus +} +``` + +The new variables can be bound with names different from the original struct field names, as +showcased in the `legs --> feet` binding in the example above. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/tuples.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/tuples.md new file mode 100644 index 00000000000..2ec5c9c4113 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/tuples.md @@ -0,0 +1,48 @@ +--- +title: Tuples +description: + Dive into the Tuple data type in Noir. Understand its methods, practical examples, and best practices for efficiently using Tuples in your Noir code. +keywords: + [ + noir, + tuple type, + methods, + examples, + multi-value containers, + ] +sidebar_position: 7 +--- + +A tuple collects multiple values like an array, but with the added ability to collect values of +different types: + +```rust +fn main() { + let tup: (u8, u64, Field) = (255, 500, 1000); +} +``` + +One way to access tuple elements is via destructuring using pattern matching: + +```rust +fn main() { + let tup = (1, 2); + + let (one, two) = tup; + + let three = one + two; +} +``` + +Another way to access tuple elements is via direct member access, using a period (`.`) followed by +the index of the element we want to access. Index `0` corresponds to the first tuple element, `1` to +the second and so on: + +```rust +fn main() { + let tup = (5, 6, 7, 8); + + let five = tup.0; + let eight = tup.3; +} +``` diff --git a/docs/docs/noir/concepts/distinct.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/distinct.md similarity index 100% rename from docs/docs/noir/concepts/distinct.md rename to docs/versioned_docs/version-v0.28.0/noir/concepts/distinct.md diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/functions.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/functions.md new file mode 100644 index 00000000000..f656cdfd97a --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/functions.md @@ -0,0 +1,226 @@ +--- +title: Functions +description: + Learn how to declare functions and methods in Noir, a programming language with Rust semantics. + This guide covers parameter declaration, return types, call expressions, and more. +keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] +sidebar_position: 1 +--- + +Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. + +To declare a function the `fn` keyword is used. + +```rust +fn foo() {} +``` + +By default, functions are visible only within the package they are defined. To make them visible outside of that package (for example, as part of a [library](../modules_packages_crates/crates_and_packages.md#libraries)), you should mark them as `pub`: + +```rust +pub fn foo() {} +``` + +You can also restrict the visibility of the function to only the crate it was defined in, by specifying `pub(crate)`: + +```rust +pub(crate) fn foo() {} //foo can only be called within its crate +``` + +All parameters in a function must have a type and all types are known at compile time. The parameter +is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. + +```rust +fn foo(x : Field, y : Field){} +``` + +The return type of a function can be stated by using the `->` arrow notation. The function below +states that the foo function must return a `Field`. If the function returns no value, then the arrow +is omitted. + +```rust +fn foo(x : Field, y : Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## Main function + +If you're writing a binary, the `main` function is the starting point of your program. You can pass all types of expressions to it, as long as they have a fixed size at compile time: + +```rust +fn main(x : Field) // this is fine: passing a Field +fn main(x : [Field; 2]) // this is also fine: passing a Field with known size at compile-time +fn main(x : (Field, bool)) // 👌: passing a (Field, bool) tuple means size 2 +fn main(x : str<5>) // this is fine, as long as you pass a string of size 5 + +fn main(x : Vec) // can't compile, has variable size +fn main(x : [Field]) // can't compile, has variable size +fn main(....// i think you got it by now +``` + +Keep in mind [tests](../../tooling/testing.md) don't differentiate between `main` and any other function. The following snippet passes tests, but won't compile or prove: + +```rust +fn main(x : [Field]) { + assert(x[0] == 1); +} + +#[test] +fn test_one() { + main(&[1, 2]); +} +``` + +```bash +$ nargo test +[testing] Running 1 test functions +[testing] Testing test_one... ok +[testing] All tests passed + +$ nargo check +The application panicked (crashed). +Message: Cannot have variable sized arrays as a parameter to main +``` + +## Call Expressions + +Calling a function in Noir is executed by using the function name and passing in the necessary +arguments. + +Below we show how to call the `foo` function from the `main` function using a call expression: + +```rust +fn main(x : Field, y : Field) { + let z = foo(x); +} + +fn foo(x : Field) -> Field { + x + x +} +``` + +## Methods + +You can define methods in Noir on any struct type in scope. + +```rust +struct MyStruct { + foo: Field, + bar: Field, +} + +impl MyStruct { + fn new(foo: Field) -> MyStruct { + MyStruct { + foo, + bar: 2, + } + } + + fn sum(self) -> Field { + self.foo + self.bar + } +} + +fn main() { + let s = MyStruct::new(40); + assert(s.sum() == 42); +} +``` + +Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as +follows: + +```rust +assert(MyStruct::sum(s) == 42); +``` + +It is also possible to specialize which method is chosen depending on the [generic](./generics.md) type that is used. In this example, the `foo` function returns different values depending on its type: + +```rust +struct Foo {} + +impl Foo { + fn foo(self) -> Field { 1 } +} + +impl Foo { + fn foo(self) -> Field { 2 } +} + +fn main() { + let f1: Foo = Foo{}; + let f2: Foo = Foo{}; + assert(f1.foo() + f2.foo() == 3); +} +``` + +Also note that impls with the same method name defined in them cannot overlap. For example, if we already have `foo` defined for `Foo` and `Foo` like we do above, we cannot also define `foo` in an `impl Foo` since it would be ambiguous which version of `foo` to choose. + +```rust +// Including this impl in the same project as the above snippet would +// cause an overlapping impls error +impl Foo { + fn foo(self) -> Field { 3 } +} +``` + +## Lambdas + +Lambdas are anonymous functions. They follow the syntax of Rust - `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +See [Lambdas](./lambdas.md) for more details. + +## Attributes + +Attributes are metadata that can be applied to a function, using the following syntax: `#[attribute(value)]`. + +Supported attributes include: + +- **builtin**: the function is implemented by the compiler, for efficiency purposes. +- **deprecated**: mark the function as _deprecated_. Calling the function will generate a warning: `warning: use of deprecated function` +- **field**: Used to enable conditional compilation of code depending on the field size. See below for more details +- **oracle**: mark the function as _oracle_; meaning it is an external unconstrained function, implemented in noir_js. See [Unconstrained](./unconstrained.md) and [NoirJS](../../reference/NoirJS/noir_js/index.md) for more details. +- **test**: mark the function as unit tests. See [Tests](../../tooling/testing.md) for more details + +### Field Attribute + +The field attribute defines which field the function is compatible for. The function is conditionally compiled, under the condition that the field attribute matches the Noir native field. +The field can be defined implicitly, by using the name of the elliptic curve usually associated to it - for instance bn254, bls12_381 - or explicitly by using the field (prime) order, in decimal or hexadecimal form. +As a result, it is possible to define multiple versions of a function with each version specialized for a different field attribute. This can be useful when a function requires different parameters depending on the underlying elliptic curve. + +Example: we define the function `foo()` three times below. Once for the default Noir bn254 curve, once for the field $\mathbb F_{23}$, which will normally never be used by Noir, and once again for the bls12_381 curve. + +```rust +#[field(bn254)] +fn foo() -> u32 { + 1 +} + +#[field(23)] +fn foo() -> u32 { + 2 +} + +// This commented code would not compile as foo would be defined twice because it is the same field as bn254 +// #[field(21888242871839275222246405745257275088548364400416034343698204186575808495617)] +// fn foo() -> u32 { +// 2 +// } + +#[field(bls12_381)] +fn foo() -> u32 { + 3 +} +``` + +If the field name is not known to Noir, it will discard the function. Field names are case insensitive. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/generics.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/generics.md new file mode 100644 index 00000000000..ddd42bf1f9b --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/generics.md @@ -0,0 +1,106 @@ +--- +title: Generics +description: Learn how to use Generics in Noir +keywords: [Noir, Rust, generics, functions, structs] +sidebar_position: 7 +--- + +Generics allow you to use the same functions with multiple different concrete data types. You can +read more about the concept of generics in the Rust documentation +[here](https://doc.rust-lang.org/book/ch10-01-syntax.html). + +Here is a trivial example showing the identity function that supports any type. In Rust, it is +common to refer to the most general type as `T`. We follow the same convention in Noir. + +```rust +fn id(x: T) -> T { + x +} +``` + +## In Structs + +Generics are useful for specifying types in structs. For example, we can specify that a field in a +struct will be of a certain generic type. In this case `value` is of type `T`. + +```rust +struct RepeatedValue { + value: T, + count: Field, +} + +impl RepeatedValue { + fn print(self) { + for _i in 0 .. self.count { + println(self.value); + } + } +} + +fn main() { + let repeated = RepeatedValue { value: "Hello!", count: 2 }; + repeated.print(); +} +``` + +The `print` function will print `Hello!` an arbitrary number of times, twice in this case. + +If we want to be generic over array lengths (which are type-level integers), we can use numeric +generics. Using these looks just like using regular generics, but these generics can resolve to +integers at compile-time, rather than resolving to types. Here's an example of a struct that is +generic over the size of the array it contains internally: + +```rust +struct BigInt { + limbs: [u32; N], +} + +impl BigInt { + // `N` is in scope of all methods in the impl + fn first(first: BigInt, second: BigInt) -> Self { + assert(first.limbs != second.limbs); + first + + fn second(first: BigInt, second: Self) -> Self { + assert(first.limbs != second.limbs); + second + } +} +``` + +## Calling functions on generic parameters + +Since a generic type `T` can represent any type, how can we call functions on the underlying type? +In other words, how can we go from "any type `T`" to "any type `T` that has certain methods available?" + +This is what [traits](../concepts/traits) are for in Noir. Here's an example of a function generic over +any type `T` that implements the `Eq` trait for equality: + +```rust +fn first_element_is_equal(array1: [T; N], array2: [T; N]) -> bool + where T: Eq +{ + if (array1.len() == 0) | (array2.len() == 0) { + true + } else { + array1[0] == array2[0] + } +} + +fn main() { + assert(first_element_is_equal([1, 2, 3], [1, 5, 6])); + + // We can use first_element_is_equal for arrays of any type + // as long as we have an Eq impl for the types we pass in + let array = [MyStruct::new(), MyStruct::new()]; + assert(array_eq(array, array, MyStruct::eq)); +} + +impl Eq for MyStruct { + fn eq(self, other: MyStruct) -> bool { + self.foo == other.foo + } +} +``` + +You can find more details on traits and trait implementations on the [traits page](../concepts/traits). diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/globals.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/globals.md new file mode 100644 index 00000000000..063a3d89248 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/globals.md @@ -0,0 +1,72 @@ +--- +title: Global Variables +description: + Learn about global variables in Noir. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, globals, global variables, constants] +sidebar_position: 8 +--- + +## Globals + + +Noir supports global variables. The global's type can be inferred by the compiler entirely: + +```rust +global N = 5; // Same as `global N: Field = 5` + +global TUPLE = (3, 2); + +fn main() { + assert(N == 5); + assert(N == TUPLE.0 + TUPLE.1); +} +``` + +:::info + +Globals can be defined as any expression, so long as they don't depend on themselves - otherwise there would be a dependency cycle! For example: + +```rust +global T = foo(T); // dependency error +``` + +::: + + +If they are initialized to a literal integer, globals can be used to specify an array's length: + +```rust +global N: Field = 2; + +fn main(y : [Field; N]) { + assert(y[0] == y[1]) +} +``` + +A global from another module can be imported or referenced externally like any other name: + +```rust +global N = 20; + +fn main() { + assert(my_submodule::N != N); +} + +mod my_submodule { + global N: Field = 10; +} +``` + +When a global is used, Noir replaces the name with its definition on each occurrence. +This means globals defined using function calls will repeat the call each time they're used: + +```rust +global RESULT = foo(); + +fn foo() -> [Field; 100] { ... } +``` + +This is usually fine since Noir will generally optimize any function call that does not +refer to a program input into a constant. It should be kept in mind however, if the called +function performs side-effects like `println`, as these will still occur on each use. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/lambdas.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/lambdas.md new file mode 100644 index 00000000000..be3c7e0b5ca --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/lambdas.md @@ -0,0 +1,81 @@ +--- +title: Lambdas +description: Learn how to use anonymous functions in Noir programming language. +keywords: [Noir programming language, lambda, closure, function, anonymous function] +sidebar_position: 9 +--- + +## Introduction + +Lambdas are anonymous functions. The syntax is `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +A block can be used as the body of a lambda, allowing you to declare local variables inside it: + +```rust +let cool = || { + let x = 100; + let y = 100; + x + y +} + +assert(cool() == 200); +``` + +## Closures + +Inside the body of a lambda, you can use variables defined in the enclosing function. Such lambdas are called **closures**. In this example `x` is defined inside `main` and is accessed from within the lambda: + +```rust +fn main() { + let x = 100; + let closure = || x + 150; + assert(closure() == 250); +} +``` + +## Passing closures to higher-order functions + +It may catch you by surprise that the following code fails to compile: + +```rust +fn foo(f: fn () -> Field) -> Field { + f() +} + +fn main() { + let (x, y) = (50, 50); + assert(foo(|| x + y) == 100); // error :( +} +``` + +The reason is that the closure's capture environment affects its type - we have a closure that captures two Fields and `foo` +expects a regular function as an argument - those are incompatible. +:::note + +Variables contained within the `||` are the closure's parameters, and the expression that follows it is the closure's body. The capture environment is comprised of any variables used in the closure's body that are not parameters. + +E.g. in |x| x + y, y would be a captured variable, but x would not be, since it is a parameter of the closure. + +::: +The syntax for the type of a closure is `fn[env](args) -> ret_type`, where `env` is the capture environment of the closure - +in this example that's `(Field, Field)`. + +The best solution in our case is to make `foo` generic over the environment type of its parameter, so that it can be called +with closures with any environment, as well as with regular functions: + +```rust +fn foo(f: fn[Env]() -> Field) -> Field { + f() +} + +fn main() { + let (x, y) = (50, 50); + assert(foo(|| x + y) == 100); // compiles fine + assert(foo(|| 60) == 60); // compiles fine +} +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/mutability.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/mutability.md new file mode 100644 index 00000000000..fdeef6a87c5 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/mutability.md @@ -0,0 +1,121 @@ +--- +title: Mutability +description: + Learn about mutable variables in Noir. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, mutability in noir, mutable variables] +sidebar_position: 8 +--- + +Variables in noir can be declared mutable via the `mut` keyword. Mutable variables can be reassigned +to via an assignment expression. + +```rust +let x = 2; +x = 3; // error: x must be mutable to be assigned to + +let mut y = 3; +let y = 4; // OK +``` + +The `mut` modifier can also apply to patterns: + +```rust +let (a, mut b) = (1, 2); +a = 11; // error: a must be mutable to be assigned to +b = 12; // OK + +let mut (c, d) = (3, 4); +c = 13; // OK +d = 14; // OK + +// etc. +let MyStruct { x: mut y } = MyStruct { x: a }; +// y is now in scope +``` + +Note that mutability in noir is local and everything is passed by value, so if a called function +mutates its parameters then the parent function will keep the old value of the parameters. + +```rust +fn main() -> pub Field { + let x = 3; + helper(x); + x // x is still 3 +} + +fn helper(mut x: i32) { + x = 4; +} +``` + +## Non-local mutability + +Non-local mutability can be achieved through the mutable reference type `&mut T`: + +```rust +fn set_to_zero(x: &mut Field) { + *x = 0; +} + +fn main() { + let mut y = 42; + set_to_zero(&mut y); + assert(*y == 0); +} +``` + +When creating a mutable reference, the original variable being referred to (`y` in this +example) must also be mutable. Since mutable references are a reference type, they must +be explicitly dereferenced via `*` to retrieve the underlying value. Note that this yields +a copy of the value, so mutating this copy will not change the original value behind the +reference: + +```rust +fn main() { + let mut x = 1; + let x_ref = &mut x; + + let mut y = *x_ref; + let y_ref = &mut y; + + x = 2; + *x_ref = 3; + + y = 4; + *y_ref = 5; + + assert(x == 3); + assert(*x_ref == 3); + assert(y == 5); + assert(*y_ref == 5); +} +``` + +Note that types in Noir are actually deeply immutable so the copy that occurs when +dereferencing is only a conceptual copy - no additional constraints will occur. + +Mutable references can also be stored within structs. Note that there is also +no lifetime parameter on these unlike rust. This is because the allocated memory +always lasts the entire program - as if it were an array of one element. + +```rust +struct Foo { + x: &mut Field +} + +impl Foo { + fn incr(mut self) { + *self.x += 1; + } +} + +fn main() { + let foo = Foo { x: &mut 0 }; + foo.incr(); + assert(*foo.x == 1); +} +``` + +In general, you should avoid non-local & shared mutability unless it is needed. Sticking +to only local mutability will improve readability and potentially improve compiler optimizations as well. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/ops.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/ops.md new file mode 100644 index 00000000000..60425cb8994 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/ops.md @@ -0,0 +1,98 @@ +--- +title: Logical Operations +description: + Learn about the supported arithmetic and logical operations in the Noir programming language. + Discover how to perform operations on private input types, integers, and booleans. +keywords: + [ + Noir programming language, + supported operations, + arithmetic operations, + logical operations, + predicate operators, + bitwise operations, + short-circuiting, + backend, + ] +sidebar_position: 3 +--- + +# Operations + +## Table of Supported Operations + +| Operation | Description | Requirements | +| :-------- | :------------------------------------------------------------: | -------------------------------------: | +| + | Adds two private input types together | Types must be private input | +| - | Subtracts two private input types together | Types must be private input | +| \* | Multiplies two private input types together | Types must be private input | +| / | Divides two private input types together | Types must be private input | +| ^ | XOR two private input types together | Types must be integer | +| & | AND two private input types together | Types must be integer | +| \| | OR two private input types together | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | +| >> | Right shift an integer by another integer amount | Types must be integer | +| ! | Bitwise not of a value | Type must be integer or boolean | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| > | returns a bool if one value is more than the other | Upper bound must have a known bit size | +| >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | +| == | returns a bool if one value is equal to the other | Both types must not be constants | +| != | returns a bool if one value is not equal to the other | Both types must not be constants | + +### Predicate Operators + +`<,<=, !=, == , >, >=` are known as predicate/comparison operations because they compare two values. +This differs from the operations such as `+` where the operands are used in _computation_. + +### Bitwise Operations Example + +```rust +fn main(x : Field) { + let y = x as u32; + let z = y & y; +} +``` + +`z` is implicitly constrained to be the result of `y & y`. The `&` operand is used to denote bitwise +`&`. + +> `x & x` would not compile as `x` is a `Field` and not an integer type. + +### Logical Operators + +Noir has no support for the logical operators `||` and `&&`. This is because encoding the +short-circuiting that these operators require can be inefficient for Noir's backend. Instead you can +use the bitwise operators `|` and `&` which operate identically for booleans, just without the +short-circuiting. + +```rust +let my_val = 5; + +let mut flag = 1; +if (my_val > 6) | (my_val == 0) { + flag = 0; +} +assert(flag == 1); + +if (my_val != 10) & (my_val < 50) { + flag = 0; +} +assert(flag == 0); +``` + +### Shorthand operators + +Noir shorthand operators for most of the above operators, namely `+=, -=, *=, /=, %=, &=, |=, ^=, <<=`, and `>>=`. These allow for more concise syntax. For example: + +```rust +let mut i = 0; +i = i + 1; +``` + +could be written as: + +```rust +let mut i = 0; +i += 1; +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/oracles.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/oracles.md new file mode 100644 index 00000000000..aa380b5f7b8 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/oracles.md @@ -0,0 +1,31 @@ +--- +title: Oracles +description: Dive into how Noir supports Oracles via RPC calls, and learn how to declare an Oracle in Noir with our comprehensive guide. +keywords: + - Noir + - Oracles + - RPC Calls + - Unconstrained Functions + - Programming + - Blockchain +sidebar_position: 6 +--- + +:::note + +This is an experimental feature that is not fully documented. If you notice any outdated information or potential improvements to this page, pull request contributions are very welcome: https://github.com/noir-lang/noir + +::: + +Noir has support for Oracles via RPC calls. This means Noir will make an RPC call and use the return value for proof generation. + +Since Oracles are not resolved by Noir, they are [`unconstrained` functions](./unconstrained.md) + +You can declare an Oracle through the `#[oracle()]` flag. Example: + +```rust +#[oracle(get_number_sequence)] +unconstrained fn get_number_sequence(_size: Field) -> [Field] {} +``` + +The timeout for when using an external RPC oracle resolver can be set with the `NARGO_FOREIGN_CALL_TIMEOUT` environment variable. This timeout is in units of milliseconds. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/shadowing.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/shadowing.md new file mode 100644 index 00000000000..5ce6130d201 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/shadowing.md @@ -0,0 +1,44 @@ +--- +title: Shadowing +sidebar_position: 12 +--- + +Noir allows for inheriting variables' values and re-declaring them with the same name similar to Rust, known as shadowing. + +For example, the following function is valid in Noir: + +```rust +fn main() { + let x = 5; + + { + let x = x * 2; + assert (x == 10); + } + + assert (x == 5); +} +``` + +In this example, a variable x is first defined with the value 5. + +The local scope that follows shadows the original x, i.e. creates a local mutable x based on the value of the original x. It is given a value of 2 times the original x. + +When we return to the main scope, x once again refers to just the original x, which stays at the value of 5. + +## Temporal mutability + +One way that shadowing is useful, in addition to ergonomics across scopes, is for temporarily mutating variables. + +```rust +fn main() { + let age = 30; + // age = age + 5; // Would error as `age` is immutable by default. + + let mut age = age + 5; // Temporarily mutates `age` with a new value. + + let age = age; // Locks `age`'s mutability again. + + assert (age == 35); +} +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/traits.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/traits.md new file mode 100644 index 00000000000..ef1445a5907 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/traits.md @@ -0,0 +1,389 @@ +--- +title: Traits +description: + Traits in Noir can be used to abstract out a common interface for functions across + several data types. +keywords: [noir programming language, traits, interfaces, generic, protocol] +sidebar_position: 14 +--- + +## Overview + +Traits in Noir are a useful abstraction similar to interfaces or protocols in other languages. Each trait defines +the interface of several methods contained within the trait. Types can then implement this trait by providing +implementations for these methods. For example in the program: + +```rust +struct Rectangle { + width: Field, + height: Field, +} + +impl Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +fn log_area(r: Rectangle) { + println(r.area()); +} +``` + +We have a function `log_area` to log the area of a `Rectangle`. Now how should we change the program if we want this +function to work on `Triangle`s as well?: + +```rust +struct Triangle { + width: Field, + height: Field, +} + +impl Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Making `log_area` generic over all types `T` would be invalid since not all types have an `area` method. Instead, we can +introduce a new `Area` trait and make `log_area` generic over all types `T` that implement `Area`: + +```rust +trait Area { + fn area(self) -> Field; +} + +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +We also need to explicitly implement `Area` for `Rectangle` and `Triangle`. We can do that by changing their existing +impls slightly. Note that the parameter types and return type of each of our `area` methods must match those defined +by the `Area` trait. + +```rust +impl Area for Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +impl Area for Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Now we have a working program that is generic over any type of Shape that is used! Others can even use this program +as a library with their own types - such as `Circle` - as long as they also implement `Area` for these types. + +## Where Clauses + +As seen in `log_area` above, when we want to create a function or method that is generic over any type that implements +a trait, we can add a where clause to the generic function. + +```rust +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +It is also possible to apply multiple trait constraints on the same variable at once by combining traits with the `+` +operator. Similarly, we can have multiple trait constraints by separating each with a comma: + +```rust +fn foo(elements: [T], thing: U) where + T: Default + Add + Eq, + U: Bar, +{ + let mut sum = T::default(); + + for element in elements { + sum += element; + } + + if sum == T::default() { + thing.bar(); + } +} +``` + +## Generic Implementations + +You can add generics to a trait implementation by adding the generic list after the `impl` keyword: + +```rust +trait Second { + fn second(self) -> Field; +} + +impl Second for (T, Field) { + fn second(self) -> Field { + self.1 + } +} +``` + +You can also implement a trait for every type this way: + +```rust +trait Debug { + fn debug(self); +} + +impl Debug for T { + fn debug(self) { + println(self); + } +} + +fn main() { + 1.debug(); +} +``` + +### Generic Trait Implementations With Where Clauses + +Where clauses can also be placed on trait implementations themselves to restrict generics in a similar way. +For example, while `impl Foo for T` implements the trait `Foo` for every type, `impl Foo for T where T: Bar` +will implement `Foo` only for types that also implement `Bar`. This is often used for implementing generic types. +For example, here is the implementation for array equality: + +```rust +impl Eq for [T; N] where T: Eq { + // Test if two arrays have the same elements. + // Because both arrays must have length N, we know their lengths already match. + fn eq(self, other: Self) -> bool { + let mut result = true; + + for i in 0 .. self.len() { + // The T: Eq constraint is needed to call == on the array elements here + result &= self[i] == other[i]; + } + + result + } +} +``` + +## Generic Traits + +Traits themselves can also be generic by placing the generic arguments after the trait name. These generics are in +scope of every item within the trait. + +```rust +trait Into { + // Convert `self` to type `T` + fn into(self) -> T; +} +``` + +When implementing generic traits the generic arguments of the trait must be specified. This is also true anytime +when referencing a generic trait (e.g. in a `where` clause). + +```rust +struct MyStruct { + array: [Field; 2], +} + +impl Into<[Field; 2]> for MyStruct { + fn into(self) -> [Field; 2] { + self.array + } +} + +fn as_array(x: T) -> [Field; 2] + where T: Into<[Field; 2]> +{ + x.into() +} + +fn main() { + let array = [1, 2]; + let my_struct = MyStruct { array }; + + assert_eq(as_array(my_struct), array); +} +``` + +## Trait Methods With No `self` + +A trait can contain any number of methods, each of which have access to the `Self` type which represents each type +that eventually implements the trait. Similarly, the `self` variable is available as well but is not required to be used. +For example, we can define a trait to create a default value for a type. This trait will need to return the `Self` type +but doesn't need to take any parameters: + +```rust +trait Default { + fn default() -> Self; +} +``` + +Implementing this trait can be done similarly to any other trait: + +```rust +impl Default for Field { + fn default() -> Field { + 0 + } +} + +struct MyType {} + +impl Default for MyType { + fn default() -> Field { + MyType {} + } +} +``` + +However, since there is no `self` parameter, we cannot call it via the method call syntax `object.method()`. +Instead, we'll need to refer to the function directly. This can be done either by referring to the +specific impl `MyType::default()` or referring to the trait itself `Default::default()`. In the later +case, type inference determines the impl that is selected. + +```rust +let my_struct = MyStruct::default(); + +let x: Field = Default::default(); +let result = x + Default::default(); +``` + +:::warning + +```rust +let _ = Default::default(); +``` + +If type inference cannot select which impl to use because of an ambiguous `Self` type, an impl will be +arbitrarily selected. This occurs most often when the result of a trait function call with no parameters +is unused. To avoid this, when calling a trait function with no `self` or `Self` parameters or return type, +always refer to it via the implementation type's namespace - e.g. `MyType::default()`. +This is set to change to an error in future Noir versions. + +::: + +## Default Method Implementations + +A trait can also have default implementations of its methods by giving a body to the desired functions. +Note that this body must be valid for all types that may implement the trait. As a result, the only +valid operations on `self` will be operations valid for any type or other operations on the trait itself. + +```rust +trait Numeric { + fn add(self, other: Self) -> Self; + + // Default implementation of double is (self + self) + fn double(self) -> Self { + self.add(self) + } +} +``` + +When implementing a trait with default functions, a type may choose to implement only the required functions: + +```rust +impl Numeric for Field { + fn add(self, other: Field) -> Field { + self + other + } +} +``` + +Or it may implement the optional methods as well: + +```rust +impl Numeric for u32 { + fn add(self, other: u32) -> u32 { + self + other + } + + fn double(self) -> u32 { + self * 2 + } +} +``` + +## Impl Specialization + +When implementing traits for a generic type it is possible to implement the trait for only a certain combination +of generics. This can be either as an optimization or because those specific generics are required to implement the trait. + +```rust +trait Sub { + fn sub(self, other: Self) -> Self; +} + +struct NonZero { + value: T, +} + +impl Sub for NonZero { + fn sub(self, other: Self) -> Self { + let value = self.value - other.value; + assert(value != 0); + NonZero { value } + } +} +``` + +## Overlapping Implementations + +Overlapping implementations are disallowed by Noir to ensure Noir's decision on which impl to select is never ambiguous. +This means if a trait `Foo` is already implemented +by a type `Bar` for all `T`, then we cannot also have a separate impl for `Bar` (or any other +type argument). Similarly, if there is an impl for all `T` such as `impl Debug for T`, we cannot create +any more impls to `Debug` for other types since it would be ambiguous which impl to choose for any given +method call. + +```rust +trait Trait {} + +// Previous impl defined here +impl Trait for (A, B) {} + +// error: Impl for type `(Field, Field)` overlaps with existing impl +impl Trait for (Field, Field) {} +``` + +## Trait Coherence + +Another restriction on trait implementations is coherence. This restriction ensures other crates cannot create +impls that may overlap with other impls, even if several unrelated crates are used as dependencies in the same +program. + +The coherence restriction is: to implement a trait, either the trait itself or the object type must be declared +in the crate the impl is in. + +In practice this often comes up when using types provided by libraries. If a library provides a type `Foo` that does +not implement a trait in the standard library such as `Default`, you may not `impl Default for Foo` in your own crate. +While restrictive, this prevents later issues or silent changes in the program if the `Foo` library later added its +own impl for `Default`. If you are a user of the `Foo` library in this scenario and need a trait not implemented by the +library your choices are to either submit a patch to the library or use the newtype pattern. + +### The Newtype Pattern + +The newtype pattern gets around the coherence restriction by creating a new wrapper type around the library type +that we cannot create `impl`s for. Since the new wrapper type is defined in our current crate, we can create +impls for any trait we need on it. + +```rust +struct Wrapper { + foo: dep::some_library::Foo, +} + +impl Default for Wrapper { + fn default() -> Wrapper { + Wrapper { + foo: dep::some_library::Foo::new(), + } + } +} +``` + +Since we have an impl for our own type, the behavior of this code will not change even if `some_library` is updated +to provide its own `impl Default for Foo`. The downside of this pattern is that it requires extra wrapping and +unwrapping of values when converting to and from the `Wrapper` and `Foo` types. diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/unconstrained.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/unconstrained.md new file mode 100644 index 00000000000..b8e71fe65f0 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/unconstrained.md @@ -0,0 +1,99 @@ +--- +title: Unconstrained Functions +description: "Learn about what unconstrained functions in Noir are, how to use them and when you'd want to." + +keywords: [Noir programming language, unconstrained, open] +sidebar_position: 5 +--- + +Unconstrained functions are functions which do not constrain any of the included computation and allow for non-deterministic computation. + +## Why? + +Zero-knowledge (ZK) domain-specific languages (DSL) enable developers to generate ZK proofs from their programs by compiling code down to the constraints of an NP complete language (such as R1CS or PLONKish languages). However, the hard bounds of a constraint system can be very limiting to the functionality of a ZK DSL. + +Enabling a circuit language to perform unconstrained execution is a powerful tool. Said another way, unconstrained execution lets developers generate witnesses from code that does not generate any constraints. Being able to execute logic outside of a circuit is critical for both circuit performance and constructing proofs on information that is external to a circuit. + +Fetching information from somewhere external to a circuit can also be used to enable developers to improve circuit efficiency. + +A ZK DSL does not just prove computation, but proves that some computation was handled correctly. Thus, it is necessary that when we switch from performing some operation directly inside of a circuit to inside of an unconstrained environment that the appropriate constraints are still laid down elsewhere in the circuit. + +## Example + +An in depth example might help drive the point home. This example comes from the excellent [post](https://discord.com/channels/1113924620781883405/1124022445054111926/1128747641853972590) by Tom in the Noir Discord. + +Let's look at how we can optimize a function to turn a `u72` into an array of `u8`s. + +```rust +fn main(num: u72) -> pub [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8)) as u72 & 0xff) as u8; + } + + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 91 +Backend circuit size: 3619 +``` + +A lot of the operations in this function are optimized away by the compiler (all the bit-shifts turn into divisions by constants). However we can save a bunch of gates by casting to u8 a bit earlier. This automatically truncates the bit-shifted value to fit in a u8 which allows us to remove the AND against 0xff. This saves us ~480 gates in total. + +```rust +fn main(num: u72) -> pub [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8)) as u8; + } + + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 75 +Backend circuit size: 3143 +``` + +Those are some nice savings already but we can do better. This code is all constrained so we're proving every step of calculating out using num, but we don't actually care about how we calculate this, just that it's correct. This is where brillig comes in. + +It turns out that truncating a u72 into a u8 is hard to do inside a snark, each time we do as u8 we lay down 4 ACIR opcodes which get converted into multiple gates. It's actually much easier to calculate num from out than the other way around. All we need to do is multiply each element of out by a constant and add them all together, both relatively easy operations inside a snark. + +We can then run u72_to_u8 as unconstrained brillig code in order to calculate out, then use that result in our constrained function and assert that if we were to do the reverse calculation we'd get back num. This looks a little like the below: + +```rust +fn main(num: u72) -> pub [u8; 8] { + let out = u72_to_u8(num); + + let mut reconstructed_num: u72 = 0; + for i in 0..8 { + reconstructed_num += (out[i] as u72 << (56 - (8 * i))); + } + assert(num == reconstructed_num); + out +} + +unconstrained fn u72_to_u8(num: u72) -> [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8))) as u8; + } + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 78 +Backend circuit size: 2902 +``` + +This ends up taking off another ~250 gates from our circuit! We've ended up with more ACIR opcodes than before but they're easier for the backend to prove (resulting in fewer gates). + +Generally we want to use brillig whenever there's something that's easy to verify but hard to compute within the circuit. For example, if you wanted to calculate a square root of a number it'll be a much better idea to calculate this in brillig and then assert that if you square the result you get back your number. + +## Break and Continue + +In addition to loops over runtime bounds, `break` and `continue` are also available in unconstrained code. See [break and continue](../concepts/control_flow/#break-and-continue) diff --git a/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/_category_.json b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/_category_.json new file mode 100644 index 00000000000..1debcfe7675 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Modules, Packages and Crates", + "position": 2, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/crates_and_packages.md b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/crates_and_packages.md new file mode 100644 index 00000000000..95ee9f52ab2 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/crates_and_packages.md @@ -0,0 +1,43 @@ +--- +title: Crates and Packages +description: Learn how to use Crates and Packages in your Noir project +keywords: [Nargo, dependencies, package management, crates, package] +sidebar_position: 0 +--- + +## Crates + +A crate is the smallest amount of code that the Noir compiler considers at a time. +Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as we’ll see in the coming sections. + +### Crate Types + +A Noir crate can come in several forms: binaries, libraries or contracts. + +#### Binaries + +_Binary crates_ are programs which you can compile to an ACIR circuit which you can then create proofs against. Each must have a function called `main` that defines the ACIR circuit which is to be proved. + +#### Libraries + +_Library crates_ don't have a `main` function and they don't compile down to ACIR. Instead they define functionality intended to be shared with multiple projects, and eventually included in a binary crate. + +#### Contracts + +Contract crates are similar to binary crates in that they compile to ACIR which you can create proofs against. They are different in that they do not have a single `main` function, but are a collection of functions to be deployed to the [Aztec network](https://aztec.network). You can learn more about the technical details of Aztec in the [monorepo](https://github.com/AztecProtocol/aztec-packages) or contract [examples](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/noir-contracts/contracts). + +### Crate Root + +Every crate has a root, which is the source file that the compiler starts, this is also known as the root module. The Noir compiler does not enforce any conditions on the name of the file which is the crate root, however if you are compiling via Nargo the crate root must be called `lib.nr` or `main.nr` for library or binary crates respectively. + +## Packages + +A Nargo _package_ is a collection of one of more crates that provides a set of functionality. A package must include a Nargo.toml file. + +A package _must_ contain either a library or a binary crate, but not both. + +### Differences from Cargo Packages + +One notable difference between Rust's Cargo and Noir's Nargo is that while Cargo allows a package to contain an unlimited number of binary crates and a single library crate, Nargo currently only allows a package to contain a single crate. + +In future this restriction may be lifted to allow a Nargo package to contain both a binary and library crate or multiple binary crates. diff --git a/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/dependencies.md b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/dependencies.md new file mode 100644 index 00000000000..04c1703d929 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/dependencies.md @@ -0,0 +1,124 @@ +--- +title: Dependencies +description: + Learn how to specify and manage dependencies in Nargo, allowing you to upload packages to GitHub + and use them easily in your project. +keywords: [Nargo, dependencies, GitHub, package management, versioning] +sidebar_position: 1 +--- + +Nargo allows you to upload packages to GitHub and use them as dependencies. + +## Specifying a dependency + +Specifying a dependency requires a tag to a specific commit and the git url to the url containing +the package. + +Currently, there are no requirements on the tag contents. If requirements are added, it would follow +semver 2.0 guidelines. + +> Note: Without a `tag` , there would be no versioning and dependencies would change each time you +> compile your project. + +For example, to add the [ecrecover-noir library](https://github.com/colinnielsen/ecrecover-noir) to your project, add it to `Nargo.toml`: + +```toml +# Nargo.toml + +[dependencies] +ecrecover = {tag = "v0.8.0", git = "https://github.com/colinnielsen/ecrecover-noir"} +``` + +If the module is in a subdirectory, you can define a subdirectory in your git repository, for example: + +```toml +# Nargo.toml + +[dependencies] +easy_private_token_contract = {tag ="v0.1.0-alpha62", git = "https://github.com/AztecProtocol/aztec-packages", directory = "noir-contracts/contracts/easy_private_token_contract"} +``` + +## Specifying a local dependency + +You can also specify dependencies that are local to your machine. + +For example, this file structure has a library and binary crate + +```tree +├── binary_crate +│   ├── Nargo.toml +│   └── src +│   └── main.nr +└── lib_a + ├── Nargo.toml + └── src + └── lib.nr +``` + +Inside of the binary crate, you can specify: + +```toml +# Nargo.toml + +[dependencies] +lib_a = { path = "../lib_a" } +``` + +## Importing dependencies + +You can import a dependency to a Noir file using the following syntax. For example, to import the +ecrecover-noir library and local lib_a referenced above: + +```rust +use dep::ecrecover; +use dep::lib_a; +``` + +You can also import only the specific parts of dependency that you want to use, like so: + +```rust +use dep::std::hash::sha256; +use dep::std::scalar_mul::fixed_base_embedded_curve; +``` + +Lastly, as demonstrated in the +[elliptic curve example](../standard_library/cryptographic_primitives/ec_primitives#examples), you +can import multiple items in the same line by enclosing them in curly braces: + +```rust +use dep::std::ec::tecurve::affine::{Curve, Point}; +``` + +We don't have a way to consume libraries from inside a [workspace](./workspaces) as external dependencies right now. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. + +## Dependencies of Dependencies + +Note that when you import a dependency, you also get access to all of the dependencies of that package. + +For example, the [phy_vector](https://github.com/resurgencelabs/phy_vector) library imports an [fraction](https://github.com/resurgencelabs/fraction) library. If you're importing the phy_vector library, then you can access the functions in fractions library like so: + +```rust +use dep::phy_vector; + +fn main(x : Field, y : pub Field) { + //... + let f = phy_vector::fraction::toFraction(true, 2, 1); + //... +} +``` + +## Available Libraries + +Noir does not currently have an official package manager. You can find a list of available Noir libraries in the [awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). + +Some libraries that are available today include: + +- [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library +- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage proof verification (or verification of any trie proof involving 32-byte long keys) +- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing for computations on large unsigned integers +- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and return the source Ethereum address +- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of sparse Merkle trees +- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data type, allowing access to negative numbers on Noir +- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, allowing results that aren't whole numbers diff --git a/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/modules.md b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/modules.md new file mode 100644 index 00000000000..ae822a1cff4 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/modules.md @@ -0,0 +1,105 @@ +--- +title: Modules +description: + Learn how to organize your files using modules in Noir, following the same convention as Rust's + module system. Examples included. +keywords: [Noir, Rust, modules, organizing files, sub-modules] +sidebar_position: 2 +--- + +Noir's module system follows the same convention as the _newer_ version of Rust's module system. + +## Purpose of Modules + +Modules are used to organize files. Without modules all of your code would need to live in a single +file. In Noir, the compiler does not automatically scan all of your files to detect modules. This +must be done explicitly by the developer. + +## Examples + +### Importing a module in the crate root + +Filename : `src/main.nr` + +```rust +mod foo; + +fn main() { + foo::hello_world(); +} +``` + +Filename : `src/foo.nr` + +```rust +fn from_foo() {} +``` + +In the above snippet, the crate root is the `src/main.nr` file. The compiler sees the module +declaration `mod foo` which prompts it to look for a foo.nr file. + +Visually this module hierarchy looks like the following : + +``` +crate + ├── main + │ + └── foo + └── from_foo + +``` + +### Importing a module throughout the tree + +All modules are accessible from the `crate::` namespace. + +``` +crate + ├── bar + ├── foo + └── main + +``` + +In the above snippet, if `bar` would like to use functions in `foo`, it can do so by `use crate::foo::function_name`. + +### Sub-modules + +Filename : `src/main.nr` + +```rust +mod foo; + +fn main() { + foo::from_foo(); +} +``` + +Filename : `src/foo.nr` + +```rust +mod bar; +fn from_foo() {} +``` + +Filename : `src/foo/bar.nr` + +```rust +fn from_bar() {} +``` + +In the above snippet, we have added an extra module to the module tree; `bar`. `bar` is a submodule +of `foo` hence we declare bar in `foo.nr` with `mod bar`. Since `foo` is not the crate root, the +compiler looks for the file associated with the `bar` module in `src/foo/bar.nr` + +Visually the module hierarchy looks as follows: + +``` +crate + ├── main + │ + └── foo + ├── from_foo + └── bar + └── from_bar +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/workspaces.md b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/workspaces.md new file mode 100644 index 00000000000..513497f12bf --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/modules_packages_crates/workspaces.md @@ -0,0 +1,42 @@ +--- +title: Workspaces +sidebar_position: 3 +--- + +Workspaces are a feature of nargo that allow you to manage multiple related Noir packages in a single repository. A workspace is essentially a group of related projects that share common build output directories and configurations. + +Each Noir project (with it's own Nargo.toml file) can be thought of as a package. Each package is expected to contain exactly one "named circuit", being the "name" defined in Nargo.toml with the program logic defined in `./src/main.nr`. + +For a project with the following structure: + +```tree +├── crates +│ ├── a +│ │ ├── Nargo.toml +│ │ └── Prover.toml +│ │ └── src +│ │ └── main.nr +│ └── b +│ ├── Nargo.toml +│ └── Prover.toml +│ └── src +│ └── main.nr +│ +└── Nargo.toml +``` + +You can define a workspace in Nargo.toml like so: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +`members` indicates which packages are included in the workspace. As such, all member packages of a workspace will be processed when the `--workspace` flag is used with various commands or if a `default-member` is not specified. + +`default-member` indicates which package various commands process by default. + +Libraries can be defined in a workspace. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/_category_.json b/docs/versioned_docs/version-v0.28.0/noir/standard_library/_category_.json new file mode 100644 index 00000000000..af04c0933fd --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Standard Library", + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/bigint.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/bigint.md new file mode 100644 index 00000000000..2bfdeec6631 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/bigint.md @@ -0,0 +1,122 @@ +--- +title: Big Integers +description: How to use big integers from Noir standard library +keywords: + [ + Big Integer, + Noir programming language, + Noir libraries, + ] +--- + +The BigInt module in the standard library exposes some class of integers which do not fit (well) into a Noir native field. It implements modulo arithmetic, modulo a 'big' prime number. + +:::note + +The module can currently be considered as `Field`s with fixed modulo sizes used by a set of elliptic curves, in addition to just the native curve. [More work](https://github.com/noir-lang/noir/issues/510) is needed to achieve arbitrarily sized big integers. + +::: + +Currently 6 classes of integers (i.e 'big' prime numbers) are available in the module, namely: + +- BN254 Fq: Bn254Fq +- BN254 Fr: Bn254Fr +- Secp256k1 Fq: Secpk1Fq +- Secp256k1 Fr: Secpk1Fr +- Secp256r1 Fr: Secpr1Fr +- Secp256r1 Fq: Secpr1Fq + +Where XXX Fq and XXX Fr denote respectively the order of the base and scalar field of the (usual) elliptic curve XXX. +For instance the big integer 'Secpk1Fq' in the standard library refers to integers modulo $2^{256}-2^{32}-977$. + +Feel free to explore the source code for the other primes: + +```rust title="big_int_definition" showLineNumbers +struct BigInt { + pointer: u32, + modulus: u32, +} +``` +> Source code: noir_stdlib/src/bigint.nr#L14-L19 + + +## Example usage + +A common use-case is when constructing a big integer from its bytes representation, and performing arithmetic operations on it: + +```rust title="big_int_example" showLineNumbers +fn big_int_example(x: u8, y: u8) { + let a = Secpk1Fq::from_le_bytes(&[x, y, 0, 45, 2]); + let b = Secpk1Fq::from_le_bytes(&[y, x, 9]); + let c = (a + b) * b / a; + let d = c.to_le_bytes(); + println(d[0]); +} +``` +> Source code: test_programs/execution_success/bigint/src/main.nr#L70-L78 + + +## Methods + +The available operations for each big integer are: + +### from_le_bytes + +Construct a big integer from its little-endian bytes representation. Example: + +```rust + // Construct a big integer from a slice of bytes + let a = Secpk1Fq::from_le_bytes(&[x, y, 0, 45, 2]); + // Construct a big integer from an array of 32 bytes + let a = Secpk1Fq::from_le_bytes_32([1;32]); + ``` + +Sure, here's the formatted version of the remaining methods: + +### to_le_bytes + +Return the little-endian bytes representation of a big integer. Example: + +```rust +let bytes = a.to_le_bytes(); +``` + +### add + +Add two big integers. Example: + +```rust +let sum = a + b; +``` + +### sub + +Subtract two big integers. Example: + +```rust +let difference = a - b; +``` + +### mul + +Multiply two big integers. Example: + +```rust +let product = a * b; +``` + +### div + +Divide two big integers. Note that division is field division and not euclidean division. Example: + +```rust +let quotient = a / b; +``` + +### eq + +Compare two big integers. Example: + +```rust +let are_equal = a == b; +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/black_box_fns.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/black_box_fns.md new file mode 100644 index 00000000000..be8c65679c3 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/black_box_fns.md @@ -0,0 +1,31 @@ +--- +title: Black Box Functions +description: Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. +keywords: [noir, black box functions] +--- + +Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. This makes certain zk-snark unfriendly computations cheaper than if they were implemented in Noir. + +The ACVM spec defines a set of blackbox functions which backends will be expected to implement. This allows backends to use optimized implementations of these constraints if they have them, however they may also fallback to less efficient naive implementations if not. + +## Function list + +Here is a list of the current black box functions: + +- [SHA256](./cryptographic_primitives/hashes.mdx#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr.mdx) +- [Blake2s](./cryptographic_primitives/hashes.mdx#blake2s) +- [Blake3](./cryptographic_primitives/hashes.mdx#blake3) +- [Pedersen Hash](./cryptographic_primitives/hashes.mdx#pedersen_hash) +- [Pedersen Commitment](./cryptographic_primitives/hashes.mdx#pedersen_commitment) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification.mdx) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar.mdx) +- AND +- XOR +- RANGE +- [Keccak256](./cryptographic_primitives/hashes.mdx#keccak256) +- [Recursive proof verification](./recursion) + +Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. + +You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/noir/blob/master/acvm-repo/acir/src/circuit/black_box_functions.rs). diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/bn254.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/bn254.md new file mode 100644 index 00000000000..3294f005dbb --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/bn254.md @@ -0,0 +1,46 @@ +--- +title: Bn254 Field Library +--- + +Noir provides a module in standard library with some optimized functions for bn254 Fr in `std::field::bn254`. + +## decompose + +```rust +fn decompose(x: Field) -> (Field, Field) {} +``` + +Decomposes a single field into two fields, low and high. The low field contains the lower 16 bytes of the input field and the high field contains the upper 16 bytes of the input field. Both field results are range checked to 128 bits. + + +## assert_gt + +```rust +fn assert_gt(a: Field, b: Field) {} +``` + +Asserts that a > b. This will generate less constraints than using `assert(gt(a, b))`. + +## assert_lt + +```rust +fn assert_lt(a: Field, b: Field) {} +``` + +Asserts that a < b. This will generate less constraints than using `assert(lt(a, b))`. + +## gt + +```rust +fn gt(a: Field, b: Field) -> bool {} +``` + +Returns true if a > b. + +## lt + +```rust +fn lt(a: Field, b: Field) -> bool {} +``` + +Returns true if a < b. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/boundedvec.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/boundedvec.md new file mode 100644 index 00000000000..ce4529f6e57 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/boundedvec.md @@ -0,0 +1,326 @@ +--- +title: Bounded Vectors +keywords: [noir, vector, bounded vector, slice] +sidebar_position: 1 +--- + +A `BoundedVec` is a growable storage similar to a `Vec` except that it +is bounded with a maximum possible length. Unlike `Vec`, `BoundedVec` is not implemented +via slices and thus is not subject to the same restrictions slices are (notably, nested +slices - and thus nested vectors as well - are disallowed). + +Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by +pushing an additional element is also more efficient - the length only needs to be increased +by one. + +For these reasons `BoundedVec` should generally be preferred over `Vec` when there +is a reasonable maximum bound that can be placed on the vector. + +Example: + +```rust +let mut vector: BoundedVec = BoundedVec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +assert(vector.max_len() == 10); +``` + +## Methods + +### new + +```rust +pub fn new() -> Self +``` + +Creates a new, empty vector of length zero. + +Since this container is backed by an array internally, it still needs an initial value +to give each element. To resolve this, each element is zeroed internally. This value +is guaranteed to be inaccessible unless `get_unchecked` is used. + +Example: + +```rust +let empty_vector: BoundedVec = BoundedVec::new(); +assert(empty_vector.len() == 0); +``` + +Note that whenever calling `new` the maximum length of the vector should always be specified +via a type signature: + +```rust title="new_example" showLineNumbers +fn foo() -> BoundedVec { + // Ok! MaxLen is specified with a type annotation + let v1: BoundedVec = BoundedVec::new(); + let v2 = BoundedVec::new(); + + // Ok! MaxLen is known from the type of foo's return value + v2 +} + +fn bad() { + let mut v3 = BoundedVec::new(); + + // Not Ok! We don't know if v3's MaxLen is at least 1, and the compiler often infers 0 by default. + v3.push(5); +} +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L11-L27 + + +This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions +but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a constraint failure at runtime when the vec is pushed to. + +### get + +```rust +pub fn get(mut self: Self, index: u64) -> T { +``` + +Retrieves an element from the vector at the given index, starting from zero. + +If the given index is equal to or greater than the length of the vector, this +will issue a constraint failure. + +Example: + +```rust +fn foo(v: BoundedVec) { + let first = v.get(0); + let last = v.get(v.len() - 1); + assert(first != last); +} +``` + +### get_unchecked + +```rust +pub fn get_unchecked(mut self: Self, index: u64) -> T { +``` + +Retrieves an element from the vector at the given index, starting from zero, without +performing a bounds check. + +Since this function does not perform a bounds check on length before accessing the element, +it is unsafe! Use at your own risk! + +Example: + +```rust title="get_unchecked_example" showLineNumbers +fn sum_of_first_three(v: BoundedVec) -> u32 { + // Always ensure the length is larger than the largest + // index passed to get_unchecked + assert(v.len() > 2); + let first = v.get_unchecked(0); + let second = v.get_unchecked(1); + let third = v.get_unchecked(2); + first + second + third +} +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L54-L64 + + + +### push + +```rust +pub fn push(&mut self, elem: T) { +``` + +Pushes an element to the end of the vector. This increases the length +of the vector by one. + +Panics if the new length of the vector will be greater than the max length. + +Example: + +```rust title="bounded-vec-push-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + + v.push(1); + v.push(2); + + // Panics with failed assertion "push out of bounds" + v.push(3); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L68-L76 + + +### pop + +```rust +pub fn pop(&mut self) -> T +``` + +Pops the element at the end of the vector. This will decrease the length +of the vector by one. + +Panics if the vector is empty. + +Example: + +```rust title="bounded-vec-pop-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + v.push(1); + v.push(2); + + let two = v.pop(); + let one = v.pop(); + + assert(two == 2); + assert(one == 1); + // error: cannot pop from an empty vector + // let _ = v.pop(); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L81-L93 + + +### len + +```rust +pub fn len(self) -> u64 { +``` + +Returns the current length of this vector + +Example: + +```rust title="bounded-vec-len-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + assert(v.len() == 0); + + v.push(100); + assert(v.len() == 1); + + v.push(200); + v.push(300); + v.push(400); + assert(v.len() == 4); + + let _ = v.pop(); + let _ = v.pop(); + assert(v.len() == 2); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L98-L113 + + +### max_len + +```rust +pub fn max_len(_self: BoundedVec) -> u64 { +``` + +Returns the maximum length of this vector. This is always +equal to the `MaxLen` parameter this vector was initialized with. + +Example: + +```rust title="bounded-vec-max-len-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + + assert(v.max_len() == 5); + v.push(10); + assert(v.max_len() == 5); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L118-L124 + + +### storage + +```rust +pub fn storage(self) -> [T; MaxLen] { +``` + +Returns the internal array within this vector. +Since arrays in Noir are immutable, mutating the returned storage array will not mutate +the storage held internally by this vector. + +Note that uninitialized elements may be zeroed out! + +Example: + +```rust title="bounded-vec-storage-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + + assert(v.storage() == [0, 0, 0, 0, 0]); + + v.push(57); + assert(v.storage() == [57, 0, 0, 0, 0]); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L129-L136 + + +### extend_from_array + +```rust +pub fn extend_from_array(&mut self, array: [T; Len]) +``` + +Pushes each element from the given array to this vector. + +Panics if pushing each element would cause the length of this vector +to exceed the maximum length. + +Example: + +```rust title="bounded-vec-extend-from-array-example" showLineNumbers +let mut vec: BoundedVec = BoundedVec::new(); + vec.extend_from_array([2, 4]); + + assert(vec.len == 2); + assert(vec.get(0) == 2); + assert(vec.get(1) == 4); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L141-L148 + + +### extend_from_bounded_vec + +```rust +pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) +``` + +Pushes each element from the other vector to this vector. The length of +the other vector is left unchanged. + +Panics if pushing each element would cause the length of this vector +to exceed the maximum length. + +Example: + +```rust title="bounded-vec-extend-from-bounded-vec-example" showLineNumbers +let mut v1: BoundedVec = BoundedVec::new(); + let mut v2: BoundedVec = BoundedVec::new(); + + v2.extend_from_array([1, 2, 3]); + v1.extend_from_bounded_vec(v2); + + assert(v1.storage() == [1, 2, 3, 0, 0]); + assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L153-L162 + + +### any + +```rust +pub fn any(self, predicate: fn[Env](T) -> bool) -> bool +``` + +Returns true if the given predicate returns true for any element +in this vector. + +Example: + +```rust title="bounded-vec-any-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + v.extend_from_array([2, 4, 6]); + + let all_even = !v.any(|elem: u32| elem % 2 != 0); + assert(all_even); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L229-L235 + diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/hashmap.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/hashmap.md new file mode 100644 index 00000000000..47faa99aba6 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/hashmap.md @@ -0,0 +1,570 @@ +--- +title: HashMap +keywords: [noir, map, hash, hashmap] +sidebar_position: 1 +--- + +`HashMap` is used to efficiently store and look up key-value pairs. + +`HashMap` is a bounded type which can store anywhere from zero to `MaxLen` total elements. +Note that due to hash collisions, the actual maximum number of elements stored by any particular +hashmap is likely lower than `MaxLen`. This is true even with cryptographic hash functions since +every hash value will be performed modulo `MaxLen`. + +When creating `HashMap`s, the `MaxLen` generic should always be specified if it is not already +known. Otherwise, the compiler may infer a different value for `MaxLen` (such as zero), which +will likely change the result of the program. This behavior is set to become an error in future +versions instead. + +Example: + +```rust +// Create a mapping from Fields to u32s with a maximum length of 12 +// using a poseidon2 hasher +use dep::std::hash::poseidon2::Poseidon2Hasher; +let mut map: HashMap> = HashMap::default(); + +map.insert(1, 2); +map.insert(3, 4); + +let two = map.get(1).unwrap(); +``` + +## Methods + +### default + +```rust title="default" showLineNumbers +impl Default for HashMap +where + B: BuildHasher + Default, + H: Hasher + Default +{ + fn default() -> Self { +``` +> Source code: noir_stdlib/src/collections/map.nr#L462-L469 + + +Creates a fresh, empty HashMap. + +When using this function, always make sure to specify the maximum size of the hash map. + +This is the same `default` from the `Default` implementation given further below. It is +repeated here for convenience since it is the recommended way to create a hashmap. + +Example: + +```rust title="default_example" showLineNumbers +let hashmap: HashMap> = HashMap::default(); + assert(hashmap.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L202-L205 + + +Because `HashMap` has so many generic arguments that are likely to be the same throughout +your program, it may be helpful to create a type alias: + +```rust title="type_alias" showLineNumbers +type MyMap = HashMap>; +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L196-L198 + + +### with_hasher + +```rust title="with_hasher" showLineNumbers +pub fn with_hasher(_build_hasher: B) -> Self + where + B: BuildHasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L82-L86 + + +Creates a hashmap with an existing `BuildHasher`. This can be used to ensure multiple +hashmaps are created with the same hasher instance. + +Example: + +```rust title="with_hasher_example" showLineNumbers +let my_hasher: BuildHasherDefault = Default::default(); + let hashmap: HashMap> = HashMap::with_hasher(my_hasher); + assert(hashmap.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L207-L211 + + +### get + +```rust title="get" showLineNumbers +pub fn get( + self, + key: K + ) -> Option + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L278-L287 + + +Retrieves a value from the hashmap, returning `Option::none()` if it was not found. + +Example: + +```rust title="get_example" showLineNumbers +fn get_example(map: HashMap>) { + let x = map.get(12); + + if x.is_some() { + assert(x.unwrap() == 42); + } +} +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L299-L307 + + +### insert + +```rust title="insert" showLineNumbers +pub fn insert( + &mut self, + key: K, + value: V + ) + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L313-L323 + + +Inserts a new key-value pair into the map. If the key was already in the map, its +previous value will be overridden with the newly provided one. + +Example: + +```rust title="insert_example" showLineNumbers +let mut map: HashMap> = HashMap::default(); + map.insert(12, 42); + assert(map.len() == 1); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L213-L217 + + +### remove + +```rust title="remove" showLineNumbers +pub fn remove( + &mut self, + key: K + ) + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L356-L365 + + +Removes the given key-value pair from the map. If the key was not already present +in the map, this does nothing. + +Example: + +```rust title="remove_example" showLineNumbers +map.remove(12); + assert(map.is_empty()); + + // If a key was not present in the map, remove does nothing + map.remove(12); + assert(map.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L221-L228 + + +### is_empty + +```rust title="is_empty" showLineNumbers +pub fn is_empty(self) -> bool { +``` +> Source code: noir_stdlib/src/collections/map.nr#L115-L117 + + +True if the length of the hash map is empty. + +Example: + +```rust title="is_empty_example" showLineNumbers +assert(map.is_empty()); + + map.insert(1, 2); + assert(!map.is_empty()); + + map.remove(1); + assert(map.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L230-L238 + + +### len + +```rust title="len" showLineNumbers +pub fn len(self) -> u64 { +``` +> Source code: noir_stdlib/src/collections/map.nr#L264-L266 + + +Returns the current length of this hash map. + +Example: + +```rust title="len_example" showLineNumbers +// This is equivalent to checking map.is_empty() + assert(map.len() == 0); + + map.insert(1, 2); + map.insert(3, 4); + map.insert(5, 6); + assert(map.len() == 3); + + // 3 was already present as a key in the hash map, so the length is unchanged + map.insert(3, 7); + assert(map.len() == 3); + + map.remove(1); + assert(map.len() == 2); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L240-L255 + + +### capacity + +```rust title="capacity" showLineNumbers +pub fn capacity(_self: Self) -> u64 { +``` +> Source code: noir_stdlib/src/collections/map.nr#L271-L273 + + +Returns the maximum capacity of this hashmap. This is always equal to the capacity +specified in the hashmap's type. + +Unlike hashmaps in general purpose programming languages, hashmaps in Noir have a +static capacity that does not increase as the map grows larger. Thus, this capacity +is also the maximum possible element count that can be inserted into the hashmap. +Due to hash collisions (modulo the hashmap length), it is likely the actual maximum +element count will be lower than the full capacity. + +Example: + +```rust title="capacity_example" showLineNumbers +let empty_map: HashMap> = HashMap::default(); + assert(empty_map.len() == 0); + assert(empty_map.capacity() == 42); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L257-L261 + + +### clear + +```rust title="clear" showLineNumbers +pub fn clear(&mut self) { +``` +> Source code: noir_stdlib/src/collections/map.nr#L93-L95 + + +Clears the hashmap, removing all key-value pairs from it. + +Example: + +```rust title="clear_example" showLineNumbers +assert(!map.is_empty()); + map.clear(); + assert(map.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L263-L267 + + +### contains_key + +```rust title="contains_key" showLineNumbers +pub fn contains_key( + self, + key: K + ) -> bool + where + K: Hash + Eq, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L101-L110 + + +True if the hashmap contains the given key. Unlike `get`, this will not also return +the value associated with the key. + +Example: + +```rust title="contains_key_example" showLineNumbers +if map.contains_key(7) { + let value = map.get(7); + assert(value.is_some()); + } else { + println("No value for key 7!"); + } +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L269-L276 + + +### entries + +```rust title="entries" showLineNumbers +pub fn entries(self) -> BoundedVec<(K, V), N> { +``` +> Source code: noir_stdlib/src/collections/map.nr#L123-L125 + + +Returns a vector of each key-value pair present in the hashmap. + +The length of the returned vector is always equal to the length of the hashmap. + +Example: + +```rust title="entries_example" showLineNumbers +let entries = map.entries(); + + // The length of a hashmap may not be compile-time known, so we + // need to loop over its capacity instead + for i in 0..map.capacity() { + if i < entries.len() { + let (key, value) = entries.get(i); + println(f"{key} -> {value}"); + } + } +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L310-L321 + + +### keys + +```rust title="keys" showLineNumbers +pub fn keys(self) -> BoundedVec { +``` +> Source code: noir_stdlib/src/collections/map.nr#L144-L146 + + +Returns a vector of each key present in the hashmap. + +The length of the returned vector is always equal to the length of the hashmap. + +Example: + +```rust title="keys_example" showLineNumbers +let keys = map.keys(); + + for i in 0..keys.max_len() { + if i < keys.len() { + let key = keys.get_unchecked(i); + let value = map.get(key).unwrap_unchecked(); + println(f"{key} -> {value}"); + } + } +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L323-L333 + + +### values + +```rust title="values" showLineNumbers +pub fn values(self) -> BoundedVec { +``` +> Source code: noir_stdlib/src/collections/map.nr#L164-L166 + + +Returns a vector of each value present in the hashmap. + +The length of the returned vector is always equal to the length of the hashmap. + +Example: + +```rust title="values_example" showLineNumbers +let values = map.values(); + + for i in 0..values.max_len() { + if i < values.len() { + let value = values.get_unchecked(i); + println(f"Found value {value}"); + } + } +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L335-L344 + + +### iter_mut + +```rust title="iter_mut" showLineNumbers +pub fn iter_mut( + &mut self, + f: fn(K, V) -> (K, V) + ) + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L183-L192 + + +Iterates through each key-value pair of the HashMap, setting each key-value pair to the +result returned from the given function. + +Note that since keys can be mutated, the HashMap needs to be rebuilt as it is iterated +through. If this is not desired, use `iter_values_mut` if only values need to be mutated, +or `entries` if neither keys nor values need to be mutated. + +The iteration order is left unspecified. As a result, if two keys are mutated to become +equal, which of the two values that will be present for the key in the resulting map is also unspecified. + +Example: + +```rust title="iter_mut_example" showLineNumbers +// Add 1 to each key in the map, and double the value associated with that key. + map.iter_mut(|k, v| (k + 1, v * 2)); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L348-L351 + + +### iter_keys_mut + +```rust title="iter_keys_mut" showLineNumbers +pub fn iter_keys_mut( + &mut self, + f: fn(K) -> K + ) + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L208-L217 + + +Iterates through the HashMap, mutating each key to the result returned from +the given function. + +Note that since keys can be mutated, the HashMap needs to be rebuilt as it is iterated +through. If only iteration is desired and the keys are not intended to be mutated, +prefer using `entries` instead. + +The iteration order is left unspecified. As a result, if two keys are mutated to become +equal, which of the two values that will be present for the key in the resulting map is also unspecified. + +Example: + +```rust title="iter_keys_mut_example" showLineNumbers +// Double each key, leaving the value associated with that key untouched + map.iter_keys_mut(|k| k * 2); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L353-L356 + + +### iter_values_mut + +```rust title="iter_values_mut" showLineNumbers +pub fn iter_values_mut(&mut self, f: fn(V) -> V) { +``` +> Source code: noir_stdlib/src/collections/map.nr#L233-L235 + + +Iterates through the HashMap, applying the given function to each value and mutating the +value to equal the result. This function is more efficient than `iter_mut` and `iter_keys_mut` +because the keys are untouched and the underlying hashmap thus does not need to be reordered. + +Example: + +```rust title="iter_values_mut_example" showLineNumbers +// Halve each value + map.iter_values_mut(|v| v / 2); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L358-L361 + + +### retain + +```rust title="retain" showLineNumbers +pub fn retain(&mut self, f: fn(K, V) -> bool) { +``` +> Source code: noir_stdlib/src/collections/map.nr#L247-L249 + + +Retains only the key-value pairs for which the given function returns true. +Any key-value pairs for which the function returns false will be removed from the map. + +Example: + +```rust title="retain_example" showLineNumbers +map.retain(|k, v| (k != 0) & (v != 0)); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L281-L283 + + +## Trait Implementations + +### default + +```rust title="default" showLineNumbers +impl Default for HashMap +where + B: BuildHasher + Default, + H: Hasher + Default +{ + fn default() -> Self { +``` +> Source code: noir_stdlib/src/collections/map.nr#L462-L469 + + +Constructs an empty HashMap. + +Example: + +```rust title="default_example" showLineNumbers +let hashmap: HashMap> = HashMap::default(); + assert(hashmap.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L202-L205 + + +### eq + +```rust title="eq" showLineNumbers +impl Eq for HashMap +where + K: Eq + Hash, + V: Eq, + B: BuildHasher, + H: Hasher +{ + fn eq(self, other: HashMap) -> bool { +``` +> Source code: noir_stdlib/src/collections/map.nr#L426-L435 + + +Checks if two HashMaps are equal. + +Example: + +```rust title="eq_example" showLineNumbers +let mut map1: HashMap> = HashMap::default(); + let mut map2: HashMap> = HashMap::default(); + + map1.insert(1, 2); + map1.insert(3, 4); + + map2.insert(3, 4); + map2.insert(1, 2); + + assert(map1 == map2); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L285-L296 + diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/index.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/index.md new file mode 100644 index 00000000000..ea84c6d5c21 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/index.md @@ -0,0 +1,5 @@ +--- +title: Containers +description: Container types provided by Noir's standard library for storing and retrieving data +keywords: [containers, data types, vec, hashmap] +--- diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/vec.mdx b/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/vec.mdx new file mode 100644 index 00000000000..fcfd7e07aa0 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/containers/vec.mdx @@ -0,0 +1,151 @@ +--- +title: Vectors +description: Delve into the Vec data type in Noir. Learn about its methods, practical examples, and best practices for using Vectors in your Noir code. +keywords: [noir, vector type, methods, examples, dynamic arrays] +sidebar_position: 6 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A vector is a collection type similar to Rust's `Vec` type. In Noir, it is a convenient way to use slices as mutable arrays. + +Example: + +```rust +let mut vector: Vec = Vec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +``` + +## Methods + +### new + +Creates a new, empty vector. + +```rust +pub fn new() -> Self +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` + +### from_slice + +Creates a vector containing each element from a given slice. Mutations to the resulting vector will not affect the original slice. + +```rust +pub fn from_slice(slice: [T]) -> Self +``` + +Example: + +```rust +let slice: [Field] = &[1, 2, 3]; +let vector_from_slice = Vec::from_slice(slice); +assert(vector_from_slice.len() == 3); +``` + +### len + +Returns the number of elements in the vector. + +```rust +pub fn len(self) -> Field +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` + +### get + +Retrieves an element from the vector at a given index. Panics if the index points beyond the vector's end. + +```rust +pub fn get(self, index: Field) -> T +``` + +Example: + +```rust +let vector: Vec = Vec::from_slice(&[10, 20, 30]); +assert(vector.get(1) == 20); +``` + +### push + +Adds a new element to the vector's end, returning a new vector with a length one greater than the original unmodified vector. + +```rust +pub fn push(&mut self, elem: T) +``` + +Example: + +```rust +let mut vector: Vec = Vec::new(); +vector.push(10); +assert(vector.len() == 1); +``` + +### pop + +Removes an element from the vector's end, returning a new vector with a length one less than the original vector, along with the removed element. Panics if the vector's length is zero. + +```rust +pub fn pop(&mut self) -> T +``` + +Example: + +```rust +let mut vector = Vec::from_slice(&[10, 20]); +let popped_elem = vector.pop(); +assert(popped_elem == 20); +assert(vector.len() == 1); +``` + +### insert + +Inserts an element at a specified index, shifting subsequent elements to the right. + +```rust +pub fn insert(&mut self, index: Field, elem: T) +``` + +Example: + +```rust +let mut vector = Vec::from_slice(&[10, 30]); +vector.insert(1, 20); +assert(vector.get(1) == 20); +``` + +### remove + +Removes an element at a specified index, shifting subsequent elements to the left, and returns the removed element. + +```rust +pub fn remove(&mut self, index: Field) -> T +``` + +Example: + +```rust +let mut vector = Vec::from_slice(&[10, 20, 30]); +let removed_elem = vector.remove(1); +assert(removed_elem == 20); +assert(vector.len() == 2); +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/_category_.json b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/ec_primitives.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/ec_primitives.md new file mode 100644 index 00000000000..d2b42d67b7c --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/ec_primitives.md @@ -0,0 +1,102 @@ +--- +title: Elliptic Curve Primitives +keywords: [cryptographic primitives, Noir project] +sidebar_position: 4 +--- + +Data structures and methods on them that allow you to carry out computations involving elliptic +curves over the (mathematical) field corresponding to `Field`. For the field currently at our +disposal, applications would involve a curve embedded in BN254, e.g. the +[Baby Jubjub curve](https://eips.ethereum.org/EIPS/eip-2494). + +## Data structures + +### Elliptic curve configurations + +(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Curve`), i.e. the specific elliptic +curve you want to use, which would be specified using any one of the methods +`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::new` which take the coefficients in the +defining equation together with a generator point as parameters. You can find more detail in the +comments in +[`noir_stdlib/src/ec.nr`](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr), but +the gist of it is that the elliptic curves of interest are usually expressed in one of the standard +forms implemented here (Twisted Edwards, Montgomery and Short Weierstraß), and in addition to that, +you could choose to use `affine` coordinates (Cartesian coordinates - the usual (x,y) - possibly +together with a point at infinity) or `curvegroup` coordinates (some form of projective coordinates +requiring more coordinates but allowing for more efficient implementations of elliptic curve +operations). Conversions between all of these forms are provided, and under the hood these +conversions are done whenever an operation is more efficient in a different representation (or a +mixed coordinate representation is employed). + +### Points + +(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Point`), i.e. points lying on the +elliptic curve. For a curve configuration `c` and a point `p`, it may be checked that `p` +does indeed lie on `c` by calling `c.contains(p1)`. + +## Methods + +(given a choice of curve representation, e.g. use `std::ec::tecurve::affine::Curve` and use +`std::ec::tecurve::affine::Point`) + +- The **zero element** is given by `Point::zero()`, and we can verify whether a point `p: Point` is + zero by calling `p.is_zero()`. +- **Equality**: Points `p1: Point` and `p2: Point` may be checked for equality by calling + `p1.eq(p2)`. +- **Addition**: For `c: Curve` and points `p1: Point` and `p2: Point` on the curve, adding these two + points is accomplished by calling `c.add(p1,p2)`. +- **Negation**: For a point `p: Point`, `p.negate()` is its negation. +- **Subtraction**: For `c` and `p1`, `p2` as above, subtracting `p2` from `p1` is accomplished by + calling `c.subtract(p1,p2)`. +- **Scalar multiplication**: For `c` as above, `p: Point` a point on the curve and `n: Field`, + scalar multiplication is given by `c.mul(n,p)`. If instead `n :: [u1; N]`, i.e. `n` is a bit + array, the `bit_mul` method may be used instead: `c.bit_mul(n,p)` +- **Multi-scalar multiplication**: For `c` as above and arrays `n: [Field; N]` and `p: [Point; N]`, + multi-scalar multiplication is given by `c.msm(n,p)`. +- **Coordinate representation conversions**: The `into_group` method converts a point or curve + configuration in the affine representation to one in the CurveGroup representation, and + `into_affine` goes in the other direction. +- **Curve representation conversions**: `tecurve` and `montcurve` curves and points are equivalent + and may be converted between one another by calling `into_montcurve` or `into_tecurve` on their + configurations or points. `swcurve` is more general and a curve c of one of the other two types + may be converted to this representation by calling `c.into_swcurve()`, whereas a point `p` lying + on the curve given by `c` may be mapped to its corresponding `swcurve` point by calling + `c.map_into_swcurve(p)`. +- **Map-to-curve methods**: The Elligator 2 method of mapping a field element `n: Field` into a + `tecurve` or `montcurve` with configuration `c` may be called as `c.elligator2_map(n)`. For all of + the curve configurations, the SWU map-to-curve method may be called as `c.swu_map(z,n)`, where + `z: Field` depends on `Field` and `c` and must be chosen by the user (the conditions it needs to + satisfy are specified in the comments + [here](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr)). + +## Examples + +The +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) +illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more +interesting examples in Noir would be: + +Public-key cryptography: Given an elliptic curve and a 'base point' on it, determine the public key +from the private key. This is a matter of using scalar multiplication. In the case of Baby Jubjub, +for example, this code would do: + +```rust +use dep::std::ec::tecurve::affine::{Curve, Point}; + +fn bjj_pub_key(priv_key: Field) -> Point +{ + + let bjj = Curve::new(168700, 168696, G::new(995203441582195749578291179787384436505546430278305826713579947235728471134,5472060717959818805561601436314318772137091100104008585924551046643952123905)); + + let base_pt = Point::new(5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203); + + bjj.mul(priv_key,base_pt) +} +``` + +This would come in handy in a Merkle proof. + +- EdDSA signature verification: This is a matter of combining these primitives with a suitable hash + function. See + [feat(stdlib): EdDSA sig verification noir#1136](https://github.com/noir-lang/noir/pull/1136) for + the case of Baby Jubjub and the Poseidon hash function. diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx new file mode 100644 index 00000000000..4394b48f907 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx @@ -0,0 +1,98 @@ +--- +title: ECDSA Signature Verification +description: Learn about the cryptographic primitives regarding ECDSA over the secp256k1 and secp256r1 curves +keywords: [cryptographic primitives, Noir project, ecdsa, secp256k1, secp256r1, signatures] +sidebar_position: 3 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 curves. + +## ecdsa_secp256k1::verify_signature + +Verifier for ECDSA Secp256k1 signatures. +See ecdsa_secp256k1::verify_signature_slice for a version that accepts slices directly. + +```rust title="ecdsa_secp256k1" showLineNumbers +pub fn verify_signature( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8; N] +) -> bool +``` +> Source code: noir_stdlib/src/ecdsa_secp256k1.nr#L2-L9 + + +example: + +```rust +fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], signature : [u8;64]) { + let valid_signature = std::ecdsa_secp256k1::verify_signature(pub_key_x, pub_key_y, signature, hashed_message); + assert(valid_signature); +} +``` + + + +## ecdsa_secp256k1::verify_signature_slice + +Verifier for ECDSA Secp256k1 signatures where the message is a slice. + +```rust title="ecdsa_secp256k1_slice" showLineNumbers +pub fn verify_signature_slice( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8] +) -> bool +``` +> Source code: noir_stdlib/src/ecdsa_secp256k1.nr#L13-L20 + + + + +## ecdsa_secp256r1::verify_signature + +Verifier for ECDSA Secp256r1 signatures. +See ecdsa_secp256r1::verify_signature_slice for a version that accepts slices directly. + +```rust title="ecdsa_secp256r1" showLineNumbers +pub fn verify_signature( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8; N] +) -> bool +``` +> Source code: noir_stdlib/src/ecdsa_secp256r1.nr#L2-L9 + + +example: + +```rust +fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], signature : [u8;64]) { + let valid_signature = std::ecdsa_secp256r1::verify_signature(pub_key_x, pub_key_y, signature, hashed_message); + assert(valid_signature); +} +``` + + + +## ecdsa_secp256r1::verify_signature + +Verifier for ECDSA Secp256r1 signatures where the message is a slice. + +```rust title="ecdsa_secp256r1_slice" showLineNumbers +pub fn verify_signature_slice( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8] +) -> bool +``` +> Source code: noir_stdlib/src/ecdsa_secp256r1.nr#L13-L20 + + + diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/eddsa.mdx b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/eddsa.mdx new file mode 100644 index 00000000000..c2c0624dfad --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/eddsa.mdx @@ -0,0 +1,37 @@ +--- +title: EdDSA Verification +description: Learn about the cryptographic primitives regarding EdDSA +keywords: [cryptographic primitives, Noir project, eddsa, signatures] +sidebar_position: 5 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## eddsa::eddsa_poseidon_verify + +Verifier for EdDSA signatures + +```rust +fn eddsa_poseidon_verify(public_key_x : Field, public_key_y : Field, signature_s: Field, signature_r8_x: Field, signature_r8_y: Field, message: Field) -> bool +``` + +It is also possible to specify the hash algorithm used for the signature by using the `eddsa_verify_with_hasher` function with a parameter implementing the Hasher trait. For instance, if you want to use Poseidon2 instead, you can do the following: +```rust +use dep::std::hash::poseidon2::Poseidon2Hasher; + +let mut hasher = Poseidon2Hasher::default(); +eddsa_verify_with_hasher(pub_key_a.x, pub_key_a.y, s_a, r8_a.x, r8_a.y, msg, &mut hasher); +``` + + + +## eddsa::eddsa_to_pub + +Private to public key conversion. + +Returns `(pub_key_x, pub_key_y)` + +```rust +fn eddsa_to_pub(secret : Field) -> (Field, Field) +``` + diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/hashes.mdx b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/hashes.mdx new file mode 100644 index 00000000000..87e113b96cd --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -0,0 +1,250 @@ +--- +title: Hash methods +description: + Learn about the cryptographic primitives ready to use for any Noir project, including sha256, + blake2s, pedersen, mimc_bn254 and mimc +keywords: + [cryptographic primitives, Noir project, sha256, blake2s, pedersen, mimc_bn254, mimc, hash] +sidebar_position: 0 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## sha256 + +Given an array of bytes, returns the resulting sha256 hash. + +```rust title="sha256" showLineNumbers +pub fn sha256(input: [u8; N]) -> [u8; 32] +``` +> Source code: noir_stdlib/src/hash.nr#L9-L11 + + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::sha256(x); +} +``` + + + +## blake2s + +Given an array of bytes, returns an array with the Blake2 hash + +```rust title="blake2s" showLineNumbers +pub fn blake2s(input: [u8; N]) -> [u8; 32] +``` +> Source code: noir_stdlib/src/hash.nr#L15-L17 + + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::blake2s(x); +} +``` + + + +## blake3 + +Given an array of bytes, returns an array with the Blake3 hash + +```rust title="blake3" showLineNumbers +pub fn blake3(input: [u8; N]) -> [u8; 32] +``` +> Source code: noir_stdlib/src/hash.nr#L21-L23 + + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::blake3(x); +} +``` + + + +## pedersen_hash + +Given an array of Fields, returns the Pedersen hash. + +```rust title="pedersen_hash" showLineNumbers +pub fn pedersen_hash(input: [Field; N]) -> Field +``` +> Source code: noir_stdlib/src/hash.nr#L45-L47 + + +example: + +```rust title="pedersen-hash" showLineNumbers +use dep::std; + +fn main(x: Field, y: Field, expected_hash: Field) { + let hash = std::hash::pedersen_hash([x, y]); + assert_eq(hash, expected_hash); +} +``` +> Source code: test_programs/execution_success/pedersen_hash/src/main.nr#L1-L8 + + + + +## pedersen_commitment + +Given an array of Fields, returns the Pedersen commitment. + +```rust title="pedersen_commitment" showLineNumbers +struct PedersenPoint { + x : Field, + y : Field, +} + +pub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint { +``` +> Source code: noir_stdlib/src/hash.nr#L26-L33 + + +example: + +```rust title="pedersen-commitment" showLineNumbers +use dep::std; + +fn main(x: Field, y: Field, expected_commitment: std::hash::PedersenPoint) { + let commitment = std::hash::pedersen_commitment([x, y]); + assert_eq(commitment.x, expected_commitment.x); + assert_eq(commitment.y, expected_commitment.y); +} +``` +> Source code: test_programs/execution_success/pedersen_commitment/src/main.nr#L1-L9 + + + + +## keccak256 + +Given an array of bytes (`u8`), returns the resulting keccak hash as an array of +32 bytes (`[u8; 32]`). Specify a message_size to hash only the first +`message_size` bytes of the input. + +```rust title="keccak256" showLineNumbers +pub fn keccak256(input: [u8; N], message_size: u32) -> [u8; 32] +``` +> Source code: noir_stdlib/src/hash.nr#L67-L69 + + +example: + +```rust title="keccak256" showLineNumbers +use dep::std; + +fn main(x: Field, result: [u8; 32]) { + // We use the `as` keyword here to denote the fact that we want to take just the first byte from the x Field + // The padding is taken care of by the program + let digest = std::hash::keccak256([x as u8], 1); + assert(digest == result); + + //#1399: variable message size + let message_size = 4; + let hash_a = std::hash::keccak256([1, 2, 3, 4], message_size); + let hash_b = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size); + + assert(hash_a == hash_b); + + let message_size_big = 8; + let hash_c = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size_big); + + assert(hash_a != hash_c); +} +``` +> Source code: test_programs/execution_success/keccak256/src/main.nr#L1-L22 + + + + +## poseidon + +Given an array of Fields, returns a new Field with the Poseidon Hash. Mind that you need to specify +how many inputs are there to your Poseidon function. + +```rust +// example for hash_1, hash_2 accepts an array of length 2, etc +fn hash_1(input: [Field; 1]) -> Field +``` + +example: + +```rust title="poseidon" showLineNumbers +use dep::std::hash::poseidon; +use dep::std::hash::poseidon2; + +fn main(x1: [Field; 2], y1: pub Field, x2: [Field; 4], y2: pub Field, x3: [Field; 4], y3: Field) { + let hash1 = poseidon::bn254::hash_2(x1); + assert(hash1 == y1); + + let hash2 = poseidon::bn254::hash_4(x2); + assert(hash2 == y2); + + let hash3 = poseidon2::Poseidon2::hash(x3, x3.len()); + assert(hash3 == y3); +} +``` +> Source code: test_programs/execution_success/poseidon_bn254_hash/src/main.nr#L1-L15 + + +## poseidon 2 + +Given an array of Fields, returns a new Field with the Poseidon2 Hash. Contrary to the Poseidon +function, there is only one hash and you can specify a message_size to hash only the first +`message_size` bytes of the input, + +```rust +// example for hashing the first three elements of the input +Poseidon2::hash(input, 3); +``` + +The above example for Poseidon also includes Poseidon2. + +## mimc_bn254 and mimc + +`mimc_bn254` is `mimc`, but with hardcoded parameters for the BN254 curve. You can use it by +providing an array of Fields, and it returns a Field with the hash. You can use the `mimc` method if +you're willing to input your own constants: + +```rust +fn mimc(x: Field, k: Field, constants: [Field; N], exp : Field) -> Field +``` + +otherwise, use the `mimc_bn254` method: + +```rust +fn mimc_bn254(array: [Field; N]) -> Field +``` + +example: + +```rust + +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::mimc::mimc_bn254(x); +} +``` + +## hash_to_field + +```rust +fn hash_to_field(_input : [Field]) -> Field {} +``` + +Calculates the `blake2s` hash of the inputs and returns the hash modulo the field modulus to return +a value which can be represented as a `Field`. + diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/index.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/index.md new file mode 100644 index 00000000000..650f30165d5 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/index.md @@ -0,0 +1,14 @@ +--- +title: Cryptographic Primitives +description: + Learn about the cryptographic primitives ready to use for any Noir project +keywords: + [ + cryptographic primitives, + Noir project, + ] +--- + +The Noir team is progressively adding new cryptographic primitives to the standard library. Reach out for news or if you would be interested in adding more of these calculations in Noir. + +Some methods are available thanks to the Aztec backend, not being performed using Noir. When using other backends, these methods may or may not be supplied. diff --git a/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/scalar.mdx similarity index 64% rename from docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx rename to docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/scalar.mdx index c2946b2b73b..df411ca5443 100644 --- a/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/scalar.mdx @@ -12,7 +12,14 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Performs scalar multiplication over the embedded curve whose coordinates are defined by the configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. -#include_code fixed_base_embedded_curve noir_stdlib/src/scalar_mul.nr rust +```rust title="fixed_base_embedded_curve" showLineNumbers +pub fn fixed_base_embedded_curve( + low: Field, + high: Field +) -> [Field; 2] +``` +> Source code: noir_stdlib/src/scalar_mul.nr#L27-L32 + example diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/schnorr.mdx b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/schnorr.mdx new file mode 100644 index 00000000000..b59e69c8f07 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/cryptographic_primitives/schnorr.mdx @@ -0,0 +1,64 @@ +--- +title: Schnorr Signatures +description: Learn how you can verify Schnorr signatures using Noir +keywords: [cryptographic primitives, Noir project, schnorr, signatures] +sidebar_position: 2 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## schnorr::verify_signature + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). +See schnorr::verify_signature_slice for a version that works directly on slices. + +```rust title="schnorr_verify" showLineNumbers +pub fn verify_signature( + public_key_x: Field, + public_key_y: Field, + signature: [u8; 64], + message: [u8; N] +) -> bool +``` +> Source code: noir_stdlib/src/schnorr.nr#L2-L9 + + +where `_signature` can be generated like so using the npm package +[@noir-lang/barretenberg](https://www.npmjs.com/package/@noir-lang/barretenberg) + +```js +const { BarretenbergWasm } = require('@noir-lang/barretenberg/dest/wasm'); +const { Schnorr } = require('@noir-lang/barretenberg/dest/crypto/schnorr'); + +... + +const barretenberg = await BarretenbergWasm.new(); +const schnorr = new Schnorr(barretenberg); +const pubKey = schnorr.computePublicKey(privateKey); +const message = ... +const signature = Array.from( + schnorr.constructSignature(hash, privateKey).toBuffer() +); + +... +``` + + + +## schnorr::verify_signature_slice + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin) +where the message is a slice. + +```rust title="schnorr_verify_slice" showLineNumbers +pub fn verify_signature_slice( + public_key_x: Field, + public_key_y: Field, + signature: [u8; 64], + message: [u8] +) -> bool +``` +> Source code: noir_stdlib/src/schnorr.nr#L13-L20 + + + diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/logging.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/logging.md new file mode 100644 index 00000000000..db75ef9f86f --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/logging.md @@ -0,0 +1,78 @@ +--- +title: Logging +description: + Learn how to use the println statement for debugging in Noir with this tutorial. Understand the + basics of logging in Noir and how to implement it in your code. +keywords: + [ + noir logging, + println statement, + print statement, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +The standard library provides two familiar statements you can use: `println` and `print`. Despite being a limited implementation of rust's `println!` and `print!` macros, these constructs can be useful for debugging. + +You can print the output of both statements in your Noir code by using the `nargo execute` command or the `--show-output` flag when using `nargo test` (provided there are print statements in your tests). + +It is recommended to use `nargo execute` if you want to debug failing constraints with `println` or `print` statements. This is due to every input in a test being a constant rather than a witness, so we issue an error during compilation while we only print during execution (which comes after compilation). Neither `println`, nor `print` are callable for failed constraints caught at compile time. + +Both `print` and `println` are generic functions which can work on integers, fields, strings, and even structs or expressions. Note however, that slices are currently unsupported. For example: + +```rust +struct Person { + age: Field, + height: Field, +} + +fn main(age: Field, height: Field) { + let person = Person { + age: age, + height: height, + }; + println(person); + println(age + height); + println("Hello world!"); +} +``` + +You can print different types in the same statement (including strings) with a type called `fmtstr`. It can be specified in the same way as a normal string, just prepended with an "f" character: + +```rust + let fmt_str = f"i: {i}, j: {j}"; + println(fmt_str); + + let s = myStruct { y: x, x: y }; + println(s); + + println(f"i: {i}, s: {s}"); + + println(x); + println([x, y]); + + let foo = fooStruct { my_struct: s, foo: 15 }; + println(f"s: {s}, foo: {foo}"); + + println(15); // prints 0x0f, implicit Field + println(-1 as u8); // prints 255 + println(-1 as i8); // prints -1 +``` + +Examples shown above are interchangeable between the two `print` statements: + +```rust +let person = Person { age : age, height : height }; + +println(person); +print(person); + +println("Hello world!"); // Prints with a newline at the end of the input +print("Hello world!"); // Prints the input and keeps cursor on the same line +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/merkle_trees.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/merkle_trees.md new file mode 100644 index 00000000000..6a9ebf72ada --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/merkle_trees.md @@ -0,0 +1,58 @@ +--- +title: Merkle Trees +description: Learn about Merkle Trees in Noir with this tutorial. Explore the basics of computing a merkle root using a proof, with examples. +keywords: + [ + Merkle trees in Noir, + Noir programming language, + check membership, + computing root from leaf, + Noir Merkle tree implementation, + Merkle tree tutorial, + Merkle tree code examples, + Noir libraries, + pedersen hash., + ] +--- + +## compute_merkle_root + +Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](./cryptographic_primitives/hashes.mdx#pedersen_hash). + +```rust +fn compute_merkle_root(leaf : Field, index : Field, hash_path: [Field]) -> Field +``` + +example: + +```rust +/** + // these values are for this example only + index = "0" + priv_key = "0x000000000000000000000000000000000000000000000000000000616c696365" + secret = "0x1929ea3ab8d9106a899386883d9428f8256cfedb3c4f6b66bf4aa4d28a79988f" + note_hash_path = [ + "0x1e61bdae0f027b1b2159e1f9d3f8d00fa668a952dddd822fda80dc745d6f65cc", + "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", + "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" + ] + */ +fn main(index: Field, priv_key: Field, secret: Field, note_hash_path: [Field; 3]) { + + let pubkey = std::scalar_mul::fixed_base_embedded_curve(priv_key); + let pubkey_x = pubkey[0]; + let pubkey_y = pubkey[1]; + let note_commitment = std::hash::pedersen(&[pubkey_x, pubkey_y, secret]); + + let root = std::merkle::compute_merkle_root(note_commitment[0], index, note_hash_path.as_slice()); + println(root); +} +``` + +To check merkle tree membership: + +1. Include a merkle root as a program input. +2. Compute the merkle root of a given leaf, index and hash path. +3. Assert the merkle roots are equal. + +For more info about merkle trees, see the Wikipedia [page](https://en.wikipedia.org/wiki/Merkle_tree). diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/options.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/options.md new file mode 100644 index 00000000000..a1bd4e1de5f --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/options.md @@ -0,0 +1,101 @@ +--- +title: Option Type +--- + +The `Option` type is a way to express that a value might be present (`Some(T))` or absent (`None`). It's a safer way to handle potential absence of values, compared to using nulls in many other languages. + +```rust +struct Option { + None, + Some(T), +} +``` + +The `Option` type, already imported into your Noir program, can be used directly: + +```rust +fn main() { + let none = Option::none(); + let some = Option::some(3); +} +``` + +See [this test](https://github.com/noir-lang/noir/blob/5cbfb9c4a06c8865c98ff2b594464b037d821a5c/crates/nargo_cli/tests/test_data/option/src/main.nr) for a more comprehensive set of examples of each of the methods described below. + +## Methods + +### none + +Constructs a none value. + +### some + +Constructs a some wrapper around a given value. + +### is_none + +Returns true if the Option is None. + +### is_some + +Returns true of the Option is Some. + +### unwrap + +Asserts `self.is_some()` and returns the wrapped value. + +### unwrap_unchecked + +Returns the inner value without asserting `self.is_some()`. This method can be useful within an if condition when we already know that `option.is_some()`. If the option is None, there is no guarantee what value will be returned, only that it will be of type T for an `Option`. + +### unwrap_or + +Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value. + +### unwrap_or_else + +Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return a default value. + +### expect + +Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value. The custom message is expected to be a format string. + +### map + +If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`. + +### map_or + +If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value. + +### map_or_else + +If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`. + +### and + +Returns None if self is None. Otherwise, this returns `other`. + +### and_then + +If self is None, this returns None. Otherwise, this calls the given function with the Some value contained within self, and returns the result of that call. In some languages this function is called `flat_map` or `bind`. + +### or + +If self is Some, return self. Otherwise, return `other`. + +### or_else + +If self is Some, return self. Otherwise, return `default()`. + +### xor + +If only one of the two Options is Some, return that option. Otherwise, if both options are Some or both are None, None is returned. + +### filter + +Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true. Otherwise, this returns `None`. + +### flatten + +Flattens an `Option>` into a `Option`. This returns `None` if the outer Option is None. Otherwise, this returns the inner Option. diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/recursion.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/recursion.md new file mode 100644 index 00000000000..a93894043dc --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/recursion.md @@ -0,0 +1,88 @@ +--- +title: Recursive Proofs +description: Learn about how to write recursive proofs in Noir. +keywords: [recursion, recursive proofs, verification_key, verify_proof] +--- + +Noir supports recursively verifying proofs, meaning you verify the proof of a Noir program in another Noir program. This enables creating proofs of arbitrary size by doing step-wise verification of smaller components of a large proof. + +Read [the explainer on recursion](../../explainers/explainer-recursion.md) to know more about this function and the [guide on how to use it.](../../how_to/how-to-recursion.md) + +## The `#[recursive]` Attribute + +In Noir, the `#[recursive]` attribute is used to indicate that a circuit is designed for recursive proof generation. When applied, it informs the compiler and the tooling that the circuit should be compiled in a way that makes its proofs suitable for recursive verification. This attribute eliminates the need for manual flagging of recursion at the tooling level, streamlining the proof generation process for recursive circuits. + +### Example usage with `#[recursive]` + +```rust +#[recursive] +fn main(x: Field, y: pub Field) { + assert(x == y, "x and y are not equal"); +} + +// This marks the circuit as recursion-friendly and indicates that proofs generated from this circuit +// are intended for recursive verification. +``` + +By incorporating this attribute directly in the circuit's definition, tooling like Nargo and NoirJS can automatically execute recursive-specific duties for Noir programs (e.g. recursive-friendly proof artifact generation) without additional flags or configurations. + +## Verifying Recursive Proofs + +```rust +#[foreign(recursive_aggregation)] +pub fn verify_proof(verification_key: [Field], proof: [Field], public_inputs: [Field], key_hash: Field) {} +``` + +:::info + +This is a black box function. Read [this section](./black_box_fns) to learn more about black box functions in Noir. + +::: + +## Example usage + +```rust +use dep::std; + +fn main( + verification_key : [Field; 114], + proof : [Field; 93], + public_inputs : [Field; 1], + key_hash : Field, + proof_b : [Field; 93], +) { + std::verify_proof( + verification_key.as_slice(), + proof.as_slice(), + public_inputs.as_slice(), + key_hash + ); + + std::verify_proof( + verification_key.as_slice(), + proof_b.as_slice(), + public_inputs.as_slice(), + key_hash + ); +} +``` + +You can see a full example of recursive proofs in [this example recursion demo repo](https://github.com/noir-lang/noir-examples/tree/master/recursion). + +## Parameters + +### `verification_key` + +The verification key for the zk program that is being verified. + +### `proof` + +The proof for the zk program that is being verified. + +### `public_inputs` + +These represent the public inputs of the proof we are verifying. + +### `key_hash` + +A key hash is used to check the validity of the verification key. The circuit implementing this opcode can use this hash to ensure that the key provided to the circuit matches the key produced by the circuit creator. diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/traits.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/traits.md new file mode 100644 index 00000000000..94337e77a3e --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/traits.md @@ -0,0 +1,410 @@ +--- +title: Traits +description: Noir's stdlib provides a few commonly used traits. +keywords: [traits, trait, interface, protocol, default, add, eq] +--- + +## `std::default` + +### `std::default::Default` + +```rust title="default-trait" showLineNumbers +trait Default { + fn default() -> Self; +} +``` +> Source code: noir_stdlib/src/default.nr#L1-L5 + + +Constructs a default value of a type. + +Implementations: +```rust +impl Default for Field { .. } + +impl Default for i8 { .. } +impl Default for i16 { .. } +impl Default for i32 { .. } +impl Default for i64 { .. } + +impl Default for u8 { .. } +impl Default for u16 { .. } +impl Default for u32 { .. } +impl Default for u64 { .. } + +impl Default for () { .. } +impl Default for bool { .. } + +impl Default for [T; N] + where T: Default { .. } + +impl Default for [T] { .. } + +impl Default for (A, B) + where A: Default, B: Default { .. } + +impl Default for (A, B, C) + where A: Default, B: Default, C: Default { .. } + +impl Default for (A, B, C, D) + where A: Default, B: Default, C: Default, D: Default { .. } + +impl Default for (A, B, C, D, E) + where A: Default, B: Default, C: Default, D: Default, E: Default { .. } +``` + +For primitive integer types, the return value of `default` is `0`. Container +types such as arrays are filled with default values of their element type, +except slices whose length is unknown and thus defaulted to zero. + + +## `std::convert` + +### `std::convert::From` + +```rust title="from-trait" showLineNumbers +trait From { + fn from(input: T) -> Self; +} +``` +> Source code: noir_stdlib/src/convert.nr#L1-L5 + + +The `From` trait defines how to convert from a given type `T` to the type on which the trait is implemented. + +The Noir standard library provides a number of implementations of `From` between primitive types. +```rust title="from-impls" showLineNumbers +// Unsigned integers + +impl From for u32 { fn from(value: u8) -> u32 { value as u32 } } + +impl From for u64 { fn from(value: u8) -> u64 { value as u64 } } +impl From for u64 { fn from(value: u32) -> u64 { value as u64 } } + +impl From for Field { fn from(value: u8) -> Field { value as Field } } +impl From for Field { fn from(value: u32) -> Field { value as Field } } +impl From for Field { fn from(value: u64) -> Field { value as Field } } + +// Signed integers + +impl From for i32 { fn from(value: i8) -> i32 { value as i32 } } + +impl From for i64 { fn from(value: i8) -> i64 { value as i64 } } +impl From for i64 { fn from(value: i32) -> i64 { value as i64 } } + +// Booleans +impl From for u8 { fn from(value: bool) -> u8 { value as u8 } } +impl From for u32 { fn from(value: bool) -> u32 { value as u32 } } +impl From for u64 { fn from(value: bool) -> u64 { value as u64 } } +impl From for i8 { fn from(value: bool) -> i8 { value as i8 } } +impl From for i32 { fn from(value: bool) -> i32 { value as i32 } } +impl From for i64 { fn from(value: bool) -> i64 { value as i64 } } +impl From for Field { fn from(value: bool) -> Field { value as Field } } +``` +> Source code: noir_stdlib/src/convert.nr#L25-L52 + + +#### When to implement `From` + +As a general rule of thumb, `From` may be implemented in the [situations where it would be suitable in Rust](https://doc.rust-lang.org/std/convert/trait.From.html#when-to-implement-from): + +- The conversion is *infallible*: Noir does not provide an equivalent to Rust's `TryFrom`, if the conversion can fail then provide a named method instead. +- The conversion is *lossless*: semantically, it should not lose or discard information. For example, `u32: From` can losslessly convert any `u16` into a valid `u32` such that the original `u16` can be recovered. On the other hand, `u16: From` should not be implemented as `2**16` is a `u32` which cannot be losslessly converted into a `u16`. +- The conversion is *value-preserving*: the conceptual kind and meaning of the resulting value is the same, even though the Noir type and technical representation might be different. While it's possible to infallibly and losslessly convert a `u8` into a `str<2>` hex representation, `4u8` and `"04"` are too different for `str<2>: From` to be implemented. +- The conversion is *obvious*: it's the only reasonable conversion between the two types. If there's ambiguity on how to convert between them such that the same input could potentially map to two different values then a named method should be used. For instance rather than implementing `U128: From<[u8; 16]>`, the methods `U128::from_le_bytes` and `U128::from_be_bytes` are used as otherwise the endianness of the array would be ambiguous, resulting in two potential values of `U128` from the same byte array. + +One additional recommendation specific to Noir is: +- The conversion is *efficient*: it's relatively cheap to convert between the two types. Due to being a ZK DSL, it's more important to avoid unnecessary computation compared to Rust. If the implementation of `From` would encourage users to perform unnecessary conversion, resulting in additional proving time, then it may be preferable to expose functionality such that this conversion may be avoided. + +### `std::convert::Into` + +The `Into` trait is defined as the reciprocal of `From`. It should be easy to convince yourself that if we can convert to type `A` from type `B`, then it's possible to convert type `B` into type `A`. + +For this reason, implementing `From` on a type will automatically generate a matching `Into` implementation. One should always prefer implementing `From` over `Into` as implementing `Into` will not generate a matching `From` implementation. + +```rust title="into-trait" showLineNumbers +trait Into { + fn into(self) -> T; +} + +impl Into for U where T: From { + fn into(self) -> T { + T::from(self) + } +} +``` +> Source code: noir_stdlib/src/convert.nr#L13-L23 + + +`Into` is most useful when passing function arguments where the types don't quite match up with what the function expects. In this case, the compiler has enough type information to perform the necessary conversion by just appending `.into()` onto the arguments in question. + + +## `std::cmp` + +### `std::cmp::Eq` + +```rust title="eq-trait" showLineNumbers +trait Eq { + fn eq(self, other: Self) -> bool; +} +``` +> Source code: noir_stdlib/src/cmp.nr#L1-L5 + + +Returns `true` if `self` is equal to `other`. Implementing this trait on a type +allows the type to be used with `==` and `!=`. + +Implementations: +```rust +impl Eq for Field { .. } + +impl Eq for i8 { .. } +impl Eq for i16 { .. } +impl Eq for i32 { .. } +impl Eq for i64 { .. } + +impl Eq for u8 { .. } +impl Eq for u16 { .. } +impl Eq for u32 { .. } +impl Eq for u64 { .. } + +impl Eq for () { .. } +impl Eq for bool { .. } + +impl Eq for [T; N] + where T: Eq { .. } + +impl Eq for [T] + where T: Eq { .. } + +impl Eq for (A, B) + where A: Eq, B: Eq { .. } + +impl Eq for (A, B, C) + where A: Eq, B: Eq, C: Eq { .. } + +impl Eq for (A, B, C, D) + where A: Eq, B: Eq, C: Eq, D: Eq { .. } + +impl Eq for (A, B, C, D, E) + where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { .. } +``` + +### `std::cmp::Ord` + +```rust title="ord-trait" showLineNumbers +trait Ord { + fn cmp(self, other: Self) -> Ordering; +} +``` +> Source code: noir_stdlib/src/cmp.nr#L102-L106 + + +`a.cmp(b)` compares two values returning `Ordering::less()` if `a < b`, +`Ordering::equal()` if `a == b`, or `Ordering::greater()` if `a > b`. +Implementing this trait on a type allows `<`, `<=`, `>`, and `>=` to be +used on values of the type. + +`std::cmp` also provides `max` and `min` functions for any type which implements the `Ord` trait. + +Implementations: + +```rust +impl Ord for u8 { .. } +impl Ord for u16 { .. } +impl Ord for u32 { .. } +impl Ord for u64 { .. } + +impl Ord for i8 { .. } +impl Ord for i16 { .. } +impl Ord for i32 { .. } + +impl Ord for i64 { .. } + +impl Ord for () { .. } +impl Ord for bool { .. } + +impl Ord for [T; N] + where T: Ord { .. } + +impl Ord for [T] + where T: Ord { .. } + +impl Ord for (A, B) + where A: Ord, B: Ord { .. } + +impl Ord for (A, B, C) + where A: Ord, B: Ord, C: Ord { .. } + +impl Ord for (A, B, C, D) + where A: Ord, B: Ord, C: Ord, D: Ord { .. } + +impl Ord for (A, B, C, D, E) + where A: Ord, B: Ord, C: Ord, D: Ord, E: Ord { .. } +``` + +## `std::ops` + +### `std::ops::Add`, `std::ops::Sub`, `std::ops::Mul`, and `std::ops::Div` + +These traits abstract over addition, subtraction, multiplication, and division respectively. +Implementing these traits for a given type will also allow that type to be used with the corresponding operator +for that trait (`+` for Add, etc) in addition to the normal method names. + +```rust title="add-trait" showLineNumbers +trait Add { + fn add(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L1-L5 + +```rust title="sub-trait" showLineNumbers +trait Sub { + fn sub(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L17-L21 + +```rust title="mul-trait" showLineNumbers +trait Mul { + fn mul(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L33-L37 + +```rust title="div-trait" showLineNumbers +trait Div { + fn div(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L49-L53 + + +The implementations block below is given for the `Add` trait, but the same types that implement +`Add` also implement `Sub`, `Mul`, and `Div`. + +Implementations: +```rust +impl Add for Field { .. } + +impl Add for i8 { .. } +impl Add for i16 { .. } +impl Add for i32 { .. } +impl Add for i64 { .. } + +impl Add for u8 { .. } +impl Add for u16 { .. } +impl Add for u32 { .. } +impl Add for u64 { .. } +``` + +### `std::ops::Rem` + +```rust title="rem-trait" showLineNumbers +trait Rem{ + fn rem(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L65-L69 + + +`Rem::rem(a, b)` is the remainder function returning the result of what is +left after dividing `a` and `b`. Implementing `Rem` allows the `%` operator +to be used with the implementation type. + +Unlike other numeric traits, `Rem` is not implemented for `Field`. + +Implementations: +```rust +impl Rem for u8 { fn rem(self, other: u8) -> u8 { self % other } } +impl Rem for u16 { fn rem(self, other: u16) -> u16 { self % other } } +impl Rem for u32 { fn rem(self, other: u32) -> u32 { self % other } } +impl Rem for u64 { fn rem(self, other: u64) -> u64 { self % other } } + +impl Rem for i8 { fn rem(self, other: i8) -> i8 { self % other } } +impl Rem for i16 { fn rem(self, other: i16) -> i16 { self % other } } +impl Rem for i32 { fn rem(self, other: i32) -> i32 { self % other } } +impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } +``` + +### `std::ops::{ BitOr, BitAnd, BitXor }` + +```rust title="bitor-trait" showLineNumbers +trait BitOr { + fn bitor(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L79-L83 + +```rust title="bitand-trait" showLineNumbers +trait BitAnd { + fn bitand(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L95-L99 + +```rust title="bitxor-trait" showLineNumbers +trait BitXor { + fn bitxor(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L111-L115 + + +Traits for the bitwise operations `|`, `&`, and `^`. + +Implementing `BitOr`, `BitAnd` or `BitXor` for a type allows the `|`, `&`, or `^` operator respectively +to be used with the type. + +The implementations block below is given for the `BitOr` trait, but the same types that implement +`BitOr` also implement `BitAnd` and `BitXor`. + +Implementations: +```rust +impl BitOr for bool { fn bitor(self, other: bool) -> bool { self | other } } + +impl BitOr for u8 { fn bitor(self, other: u8) -> u8 { self | other } } +impl BitOr for u16 { fn bitor(self, other: u16) -> u16 { self | other } } +impl BitOr for u32 { fn bitor(self, other: u32) -> u32 { self | other } } +impl BitOr for u64 { fn bitor(self, other: u64) -> u64 { self | other } } + +impl BitOr for i8 { fn bitor(self, other: i8) -> i8 { self | other } } +impl BitOr for i16 { fn bitor(self, other: i16) -> i16 { self | other } } +impl BitOr for i32 { fn bitor(self, other: i32) -> i32 { self | other } } +impl BitOr for i64 { fn bitor(self, other: i64) -> i64 { self | other } } +``` + +### `std::ops::{ Shl, Shr }` + +```rust title="shl-trait" showLineNumbers +trait Shl { + fn shl(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L127-L131 + +```rust title="shr-trait" showLineNumbers +trait Shr { + fn shr(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L142-L146 + + +Traits for a bit shift left and bit shift right. + +Implementing `Shl` for a type allows the left shift operator (`<<`) to be used with the implementation type. +Similarly, implementing `Shr` allows the right shift operator (`>>`) to be used with the type. + +Note that bit shifting is not currently implemented for signed types. + +The implementations block below is given for the `Shl` trait, but the same types that implement +`Shl` also implement `Shr`. + +Implementations: +```rust +impl Shl for u8 { fn shl(self, other: u8) -> u8 { self << other } } +impl Shl for u16 { fn shl(self, other: u16) -> u16 { self << other } } +impl Shl for u32 { fn shl(self, other: u32) -> u32 { self << other } } +impl Shl for u64 { fn shl(self, other: u64) -> u64 { self << other } } +``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/standard_library/zeroed.md b/docs/versioned_docs/version-v0.28.0/noir/standard_library/zeroed.md new file mode 100644 index 00000000000..f450fecdd36 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/noir/standard_library/zeroed.md @@ -0,0 +1,26 @@ +--- +title: Zeroed Function +description: + The zeroed function returns a zeroed value of any type. +keywords: + [ + zeroed + ] +--- + +Implements `fn zeroed() -> T` to return a zeroed value of any type. This function is generally unsafe to use as the zeroed bit pattern is not guaranteed to be valid for all types. It can however, be useful in cases when the value is guaranteed not to be used such as in a BoundedVec library implementing a growable vector, up to a certain length, backed by an array. The array can be initialized with zeroed values which are guaranteed to be inaccessible until the vector is pushed to. Similarly, enumerations in noir can be implemented using this method by providing zeroed values for the unused variants. + +You can access the function at `std::unsafe::zeroed`. + +This function currently supports the following types: + +- Field +- Bool +- Uint +- Array +- Slice +- String +- Tuple +- Function + +Using it on other types could result in unexpected behavior. diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/.nojekyll b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md new file mode 100644 index 00000000000..d7249d24330 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md @@ -0,0 +1,160 @@ +# BarretenbergBackend + +## Extends + +- `BarretenbergVerifierBackend` + +## Implements + +- [`Backend`](../index.md#backend) + +## Constructors + +### new BarretenbergBackend(acirCircuit, options) + +```ts +new BarretenbergBackend(acirCircuit, options): BarretenbergBackend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `acirCircuit` | `CompiledCircuit` | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergBackend`](BarretenbergBackend.md) + +#### Inherited from + +BarretenbergVerifierBackend.constructor + +## Properties + +| Property | Type | Description | Inheritance | +| :------ | :------ | :------ | :------ | +| `acirComposer` | `any` | - | BarretenbergVerifierBackend.acirComposer | +| `acirUncompressedBytecode` | `Uint8Array` | - | BarretenbergVerifierBackend.acirUncompressedBytecode | +| `api` | `Barretenberg` | - | BarretenbergVerifierBackend.api | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | - | BarretenbergVerifierBackend.options | + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Inherited from + +BarretenbergVerifierBackend.destroy + +*** + +### generateProof() + +```ts +generateProof(compressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `compressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<`ProofData`\> + +#### Description + +Generates a proof + +*** + +### generateRecursiveProofArtifacts() + +```ts +generateRecursiveProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +Generates artifacts that will be passed to a circuit that will verify this proof. + +Instead of passing the proof and verification key as a byte array, we pass them +as fields which makes it cheaper to verify in a circuit. + +The proof that is passed here will have been created using a circuit +that has the #[recursive] attribute on its `main` method. + +The number of public inputs denotes how many public inputs are in the inner proof. + +#### Parameters + +| Parameter | Type | Default value | +| :------ | :------ | :------ | +| `proofData` | `ProofData` | `undefined` | +| `numOfPublicInputs` | `number` | `0` | + +#### Returns + +`Promise`\<`object`\> + +#### Example + +```typescript +const artifacts = await backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs); +``` + +*** + +### getVerificationKey() + +```ts +getVerificationKey(): Promise +``` + +#### Returns + +`Promise`\<`Uint8Array`\> + +#### Inherited from + +BarretenbergVerifierBackend.getVerificationKey + +*** + +### verifyProof() + +```ts +verifyProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | `ProofData` | + +#### Returns + +`Promise`\<`boolean`\> + +#### Inherited from + +BarretenbergVerifierBackend.verifyProof + +#### Description + +Verifies a proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier.md new file mode 100644 index 00000000000..500276ea748 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier.md @@ -0,0 +1,58 @@ +# BarretenbergVerifier + +## Constructors + +### new BarretenbergVerifier(options) + +```ts +new BarretenbergVerifier(options): BarretenbergVerifier +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergVerifier`](BarretenbergVerifier.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +*** + +### verifyProof() + +```ts +verifyProof(proofData, verificationKey): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | `ProofData` | +| `verificationKey` | `Uint8Array` | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/index.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/index.md new file mode 100644 index 00000000000..64971973196 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/index.md @@ -0,0 +1,59 @@ +# backend_barretenberg + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [BarretenbergBackend](classes/BarretenbergBackend.md) | - | +| [BarretenbergVerifier](classes/BarretenbergVerifier.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [BackendOptions](type-aliases/BackendOptions.md) | - | + +## References + +### CompiledCircuit + +Renames and re-exports [Backend](index.md#backend) + +*** + +### ProofData + +Renames and re-exports [Backend](index.md#backend) + +## Variables + +### Backend + +```ts +Backend: any; +``` + +## Functions + +### publicInputsToWitnessMap() + +```ts +publicInputsToWitnessMap(publicInputs, abi): Backend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `publicInputs` | `string`[] | +| `abi` | `Abi` | + +#### Returns + +[`Backend`](index.md#backend) + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md new file mode 100644 index 00000000000..b49a479f4f4 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md @@ -0,0 +1,21 @@ +# BackendOptions + +```ts +type BackendOptions: object; +``` + +## Description + +An options object, currently only used to specify the number of threads to use. + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `memory` | `object` | - | +| `memory.maximum` | `number` | - | +| `threads` | `number` | **Description**

Number of threads | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs new file mode 100644 index 00000000000..d7d5128f9e3 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend","label":"BarretenbergBackend"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier","label":"BarretenbergVerifier"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions","label":"BackendOptions"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/.nojekyll b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/classes/Noir.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/classes/Noir.md new file mode 100644 index 00000000000..45dd62ee57e --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/classes/Noir.md @@ -0,0 +1,132 @@ +# Noir + +## Constructors + +### new Noir(circuit, backend) + +```ts +new Noir(circuit, backend?): Noir +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `circuit` | `CompiledCircuit` | +| `backend`? | `any` | + +#### Returns + +[`Noir`](Noir.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the underlying backend instance. + +#### Example + +```typescript +await noir.destroy(); +``` + +*** + +### execute() + +```ts +execute(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | `InputMap` | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Allows to execute a circuit to get its witness and return value. + +#### Example + +```typescript +async execute(inputs) +``` + +*** + +### generateProof() + +```ts +generateProof(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | `InputMap` | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`ProofData`\> + +#### Description + +Generates a witness and a proof given an object as input. + +#### Example + +```typescript +async generateProof(input) +``` + +*** + +### verifyProof() + +```ts +verifyProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | `ProofData` | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Instantiates the verification key and verifies a proof. + +#### Example + +```typescript +async verifyProof(proof) +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/and.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/and.md new file mode 100644 index 00000000000..c783283e396 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/and.md @@ -0,0 +1,22 @@ +# and() + +```ts +and(lhs, rhs): string +``` + +Performs a bitwise AND operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/blake2s256.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/blake2s256.md new file mode 100644 index 00000000000..7882d0da8d5 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/blake2s256.md @@ -0,0 +1,21 @@ +# blake2s256() + +```ts +blake2s256(inputs): Uint8Array +``` + +Calculates the Blake2s256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md new file mode 100644 index 00000000000..5e3cd53e9d3 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256k1\_verify() + +```ts +ecdsa_secp256k1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256k1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md new file mode 100644 index 00000000000..0b20ff68957 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256r1\_verify() + +```ts +ecdsa_secp256r1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256r1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/keccak256.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/keccak256.md new file mode 100644 index 00000000000..d10f155ce86 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/keccak256.md @@ -0,0 +1,21 @@ +# keccak256() + +```ts +keccak256(inputs): Uint8Array +``` + +Calculates the Keccak256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/sha256.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/sha256.md new file mode 100644 index 00000000000..6ba4ecac022 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/sha256.md @@ -0,0 +1,21 @@ +# sha256() + +```ts +sha256(inputs): Uint8Array +``` + +Calculates the SHA256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/xor.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/xor.md new file mode 100644 index 00000000000..8d762b895d3 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/functions/xor.md @@ -0,0 +1,22 @@ +# xor() + +```ts +xor(lhs, rhs): string +``` + +Performs a bitwise XOR operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/index.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/index.md new file mode 100644 index 00000000000..cca6b3ace41 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/index.md @@ -0,0 +1,54 @@ +# noir_js + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [Noir](classes/Noir.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [ForeignCallHandler](type-aliases/ForeignCallHandler.md) | A callback which performs an foreign call and returns the response. | +| [ForeignCallInput](type-aliases/ForeignCallInput.md) | - | +| [ForeignCallOutput](type-aliases/ForeignCallOutput.md) | - | +| [WitnessMap](type-aliases/WitnessMap.md) | - | + +### Functions + +| Function | Description | +| :------ | :------ | +| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` | +| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes | +| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Verifies a ECDSA signature over the secp256k1 curve. | +| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. | +| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes | +| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes | +| [xor](functions/xor.md) | Performs a bitwise XOR operation between `lhs` and `rhs` | + +## References + +### CompiledCircuit + +Renames and re-exports [InputMap](index.md#inputmap) + +*** + +### ProofData + +Renames and re-exports [InputMap](index.md#inputmap) + +## Variables + +### InputMap + +```ts +InputMap: any; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md new file mode 100644 index 00000000000..812b8b16481 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md @@ -0,0 +1,24 @@ +# ForeignCallHandler + +```ts +type ForeignCallHandler: (name, inputs) => Promise; +``` + +A callback which performs an foreign call and returns the response. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | The identifier for the type of foreign call being performed. | +| `inputs` | [`ForeignCallInput`](ForeignCallInput.md)[] | An array of hex encoded inputs to the foreign call. | + +## Returns + +`Promise`\<[`ForeignCallOutput`](ForeignCallOutput.md)[]\> + +outputs - An array of hex encoded outputs containing the results of the foreign call. + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md new file mode 100644 index 00000000000..dd95809186a --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md @@ -0,0 +1,9 @@ +# ForeignCallInput + +```ts +type ForeignCallInput: string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md new file mode 100644 index 00000000000..b71fb78a946 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md @@ -0,0 +1,9 @@ +# ForeignCallOutput + +```ts +type ForeignCallOutput: string | string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md new file mode 100644 index 00000000000..258c46f9d0c --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md @@ -0,0 +1,9 @@ +# WitnessMap + +```ts +type WitnessMap: Map; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs new file mode 100644 index 00000000000..c6d8125eaad --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/noir_js/classes/Noir","label":"Noir"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallHandler","label":"ForeignCallHandler"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallInput","label":"ForeignCallInput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallOutput","label":"ForeignCallOutput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/WitnessMap","label":"WitnessMap"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_js/functions/and","label":"and"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/blake2s256","label":"blake2s256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify","label":"ecdsa_secp256k1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify","label":"ecdsa_secp256r1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/keccak256","label":"keccak256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/sha256","label":"sha256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/xor","label":"xor"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/.nojekyll b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/compile.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/compile.md new file mode 100644 index 00000000000..6faf763b37f --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/compile.md @@ -0,0 +1,51 @@ +# compile() + +```ts +compile( + fileManager, + projectPath?, + logFn?, +debugLogFn?): Promise +``` + +Compiles a Noir project + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `fileManager` | `FileManager` | The file manager to use | +| `projectPath`? | `string` | The path to the project inside the file manager. Defaults to the root of the file manager | +| `logFn`? | `LogFn` | A logging function. If not provided, console.log will be used | +| `debugLogFn`? | `LogFn` | A debug logging function. If not provided, logFn will be used | + +## Returns + +`Promise`\<[`ProgramCompilationArtifacts`](../index.md#programcompilationartifacts)\> + +## Example + +```typescript +// Node.js + +import { compile_program, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile_program(fm); +``` + +```typescript +// Browser + +import { compile_program, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile_program(fm); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/compile_contract.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/compile_contract.md new file mode 100644 index 00000000000..7d0b39a43ef --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/compile_contract.md @@ -0,0 +1,51 @@ +# compile\_contract() + +```ts +compile_contract( + fileManager, + projectPath?, + logFn?, +debugLogFn?): Promise +``` + +Compiles a Noir project + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `fileManager` | `FileManager` | The file manager to use | +| `projectPath`? | `string` | The path to the project inside the file manager. Defaults to the root of the file manager | +| `logFn`? | `LogFn` | A logging function. If not provided, console.log will be used | +| `debugLogFn`? | `LogFn` | A debug logging function. If not provided, logFn will be used | + +## Returns + +`Promise`\<[`ContractCompilationArtifacts`](../index.md#contractcompilationartifacts)\> + +## Example + +```typescript +// Node.js + +import { compile_contract, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile_contract(fm); +``` + +```typescript +// Browser + +import { compile_contract, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile_contract(fm); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/createFileManager.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/createFileManager.md new file mode 100644 index 00000000000..7e65c1d69c7 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/createFileManager.md @@ -0,0 +1,21 @@ +# createFileManager() + +```ts +createFileManager(dataDir): FileManager +``` + +Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `dataDir` | `string` | root of the file system | + +## Returns + +`FileManager` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md new file mode 100644 index 00000000000..fcea9275341 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md @@ -0,0 +1,21 @@ +# inflateDebugSymbols() + +```ts +inflateDebugSymbols(debugSymbols): any +``` + +Decompresses and decodes the debug symbols + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `debugSymbols` | `string` | The base64 encoded debug symbols | + +## Returns + +`any` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/index.md b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/index.md new file mode 100644 index 00000000000..b6e0f9d1bc0 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/index.md @@ -0,0 +1,49 @@ +# noir_wasm + +## Exports + +### Functions + +| Function | Description | +| :------ | :------ | +| [compile](functions/compile.md) | Compiles a Noir project | +| [compile\_contract](functions/compile_contract.md) | Compiles a Noir project | +| [createFileManager](functions/createFileManager.md) | Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) | +| [inflateDebugSymbols](functions/inflateDebugSymbols.md) | Decompresses and decodes the debug symbols | + +## References + +### compile\_program + +Renames and re-exports [compile](functions/compile.md) + +## Interfaces + +### ContractCompilationArtifacts + +The compilation artifacts of a given contract. + +#### Properties + +| Property | Type | Description | +| :------ | :------ | :------ | +| `contract` | `ContractArtifact` | The compiled contract. | +| `warnings` | `unknown`[] | Compilation warnings. | + +*** + +### ProgramCompilationArtifacts + +The compilation artifacts of a given program. + +#### Properties + +| Property | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | not part of the compilation output, injected later | +| `program` | `ProgramArtifact` | The compiled contract. | +| `warnings` | `unknown`[] | Compilation warnings. | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs new file mode 100644 index 00000000000..e0870710349 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"doc","id":"reference/NoirJS/noir_wasm/index","label":"API"},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/compile","label":"compile"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/compile_contract","label":"compile_contract"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/createFileManager","label":"createFileManager"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/inflateDebugSymbols","label":"inflateDebugSymbols"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/reference/_category_.json b/docs/versioned_docs/version-v0.28.0/reference/_category_.json new file mode 100644 index 00000000000..5b6a20a609a --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 4, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/reference/debugger/_category_.json b/docs/versioned_docs/version-v0.28.0/reference/debugger/_category_.json new file mode 100644 index 00000000000..27869205ad3 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/debugger/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Debugger", + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_known_limitations.md b/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_known_limitations.md new file mode 100644 index 00000000000..936d416ac4b --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_known_limitations.md @@ -0,0 +1,59 @@ +--- +title: Known limitations +description: + An overview of known limitations of the current version of the Noir debugger +keywords: + [ + Nargo, + Noir Debugger, + VS Code, + ] +sidebar_position: 2 +--- + +# Debugger Known Limitations + +There are currently some limits to what the debugger can observe. + +## Mutable references + +The debugger is currently blind to any state mutated via a mutable reference. For example, in: + +``` +let mut x = 1; +let y = &mut x; +*y = 2; +``` + +The update on `x` will not be observed by the debugger. That means, when running `vars` from the debugger REPL, or inspecting the _local variables_ pane in the VS Code debugger, `x` will appear with value 1 despite having executed `*y = 2;`. + +## Variables of type function or mutable references are opaque + +When inspecting variables, any variable of type `Function` or `MutableReference` will render its value as `<>` or `<>`. + +## Debugger instrumentation affects resulting ACIR + +In order to make the state of local variables observable, the debugger compiles Noir circuits interleaving foreign calls that track any mutations to them. While this works (except in the cases described above) and doesn't introduce any behavior changes, it does as a side effect produce bigger bytecode. In particular, when running the command `opcodes` on the REPL debugger, you will notice Unconstrained VM blocks that look like this: + +``` +... +5 BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [], q_c: 2 }), Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(2))], q_c: 0 })] + | outputs=[] + 5.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 5.1 | Mov { destination: RegisterIndex(3), source: RegisterIndex(1) } + 5.2 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 5.3 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 5.4 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 5.5 | Mov { destination: RegisterIndex(3), source: RegisterIndex(3) } + 5.6 | Call { location: 8 } + 5.7 | Stop + 5.8 | ForeignCall { function: "__debug_var_assign", destinations: [], inputs: [RegisterIndex(RegisterIndex(2)), RegisterIndex(RegisterIndex(3))] } +... +``` + +If you are interested in debugging/inspecting compiled ACIR without these synthetic changes, you can invoke the REPL debugger with the `--skip-instrumentation` flag or launch the VS Code debugger with the `skipConfiguration` property set to true in its launch configuration. You can find more details about those in the [Debugger REPL reference](debugger_repl.md) and the [VS Code Debugger reference](debugger_vscode.md). + +:::note +Skipping debugger instrumentation means you won't be able to inspect values of local variables. +::: + diff --git a/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_repl.md b/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_repl.md new file mode 100644 index 00000000000..46e2011304e --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_repl.md @@ -0,0 +1,360 @@ +--- +title: REPL Debugger +description: + Noir Debugger REPL options and commands. +keywords: + [ + Nargo, + Noir CLI, + Noir Debugger, + REPL, + ] +sidebar_position: 1 +--- + +## Running the REPL debugger + +`nargo debug [OPTIONS] [WITNESS_NAME]` + +Runs the Noir REPL debugger. If a `WITNESS_NAME` is provided the debugger writes the resulting execution witness to a `WITNESS_NAME` file. + +### Options + +| Option | Description | +| --------------------- | ------------------------------------------------------------ | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover]| +| `--package ` | The name of the package to debug | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +None of these options are required. + +:::note +Since the debugger starts by compiling the target package, all Noir compiler options are also available. Check out the [compiler reference](../nargo_commands.md#nargo-compile) to learn more about the compiler options. +::: + +## REPL commands + +Once the debugger is running, it accepts the following commands. + +#### `help` (h) + +Displays the menu of available commands. + +``` +> help +Available commands: + + opcodes display ACIR opcodes + into step into to the next opcode + next step until a new source location is reached + out step until a new source location is reached + and the current stack frame is finished + break LOCATION:OpcodeLocation add a breakpoint at an opcode location + over step until a new source location is reached + without diving into function calls + restart restart the debugging session + delete LOCATION:OpcodeLocation delete breakpoint at an opcode location + witness show witness map + witness index:u32 display a single witness from the witness map + witness index:u32 value:String update a witness with the given value + memset index:usize value:String update a memory cell with the given + value + continue continue execution until the end of the + program + vars show variable values available at this point + in execution + stacktrace display the current stack trace + memory show memory (valid when executing unconstrained code) value + step step to the next ACIR opcode + +Other commands: + + help Show this help message + quit Quit repl + +``` + +### Stepping through programs + +#### `next` (n) + +Step until the next Noir source code location. While other commands, such as [`into`](#into-i) and [`step`](#step-s), allow for finer grained control of the program's execution at the opcode level, `next` is source code centric. For example: + +``` +3 ... +4 fn main(x: u32) { +5 assert(entry_point(x) == 2); +6 swap_entry_point(x, x + 1); +7 -> assert(deep_entry_point(x) == 4); +8 multiple_values_entry_point(x); +9 } +``` + + +Using `next` here would cause the debugger to jump to the definition of `deep_entry_point` (if available). + +If you want to step over `deep_entry_point` and go straight to line 8, use [the `over` command](#over) instead. + +#### `over` + +Step until the next source code location, without diving into function calls. For example: + +``` +3 ... +4 fn main(x: u32) { +5 assert(entry_point(x) == 2); +6 swap_entry_point(x, x + 1); +7 -> assert(deep_entry_point(x) == 4); +8 multiple_values_entry_point(x); +9 } +``` + + +Using `over` here would cause the debugger to execute until line 8 (`multiple_values_entry_point(x);`). + +If you want to step into `deep_entry_point` instead, use [the `next` command](#next-n). + +#### `out` + +Step until the end of the current function call. For example: + +``` + 3 ... + 4 fn main(x: u32) { + 5 assert(entry_point(x) == 2); + 6 swap_entry_point(x, x + 1); + 7 -> assert(deep_entry_point(x) == 4); + 8 multiple_values_entry_point(x); + 9 } + 10 + 11 unconstrained fn returns_multiple_values(x: u32) -> (u32, u32, u32, u32) { + 12 ... + ... + 55 + 56 unconstrained fn deep_entry_point(x: u32) -> u32 { + 57 -> level_1(x + 1) + 58 } + +``` + +Running `out` here will resume execution until line 8. + +#### `step` (s) + +Skips to the next ACIR code. A compiled Noir program is a sequence of ACIR opcodes. However, an unconstrained VM opcode denotes the start of an unconstrained code block, to be executed by the unconstrained VM. For example (redacted for brevity): + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +The `->` here shows the debugger paused at an ACIR opcode: `BRILLIG`, at index 1, which denotes an unconstrained code block is about to start. + +Using the `step` command at this point would result in the debugger stopping at ACIR opcode 2, `EXPR`, skipping unconstrained computation steps. + +Use [the `into` command](#into-i) instead if you want to follow unconstrained computation step by step. + +#### `into` (i) + +Steps into the next opcode. A compiled Noir program is a sequence of ACIR opcodes. However, a BRILLIG opcode denotes the start of an unconstrained code block, to be executed by the unconstrained VM. For example (redacted for brevity): + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +The `->` here shows the debugger paused at an ACIR opcode: `BRILLIG`, at index 1, which denotes an unconstrained code block is about to start. + +Using the `into` command at this point would result in the debugger stopping at opcode 1.0, `Mov ...`, allowing the debugger user to follow unconstrained computation step by step. + +Use [the `step` command](#step-s) instead if you want to skip to the next ACIR code directly. + +#### `continue` (c) + +Continues execution until the next breakpoint, or the end of the program. + +#### `restart` (res) + +Interrupts execution, and restarts a new debugging session from scratch. + +#### `opcodes` (o) + +Display the program's ACIR opcode sequence. For example: + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +### Breakpoints + +#### `break [Opcode]` (or shorthand `b [Opcode]`) + +Sets a breakpoint on the specified opcode index. To get a list of the program opcode numbers, see [the `opcode` command](#opcodes-o). For example: + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +In this example, issuing a `break 1.2` command adds break on opcode 1.2, as denoted by the `*` character: + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | * Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +Running [the `continue` command](#continue-c) at this point would cause the debugger to execute the program until opcode 1.2. + +#### `delete [Opcode]` (or shorthand `d [Opcode]`) + +Deletes a breakpoint at an opcode location. Usage is analogous to [the `break` command](#). + +### Variable inspection + +#### vars + +Show variable values available at this point in execution. + +:::note +The ability to inspect variable values from the debugger depends on compilation to be run in a special debug instrumentation mode. This instrumentation weaves variable tracing code with the original source code. + +So variable value inspection comes at the expense of making the resulting ACIR bytecode bigger and harder to understand and optimize. + +If you find this compromise unacceptable, you can run the debugger with the flag `--skip-debug-instrumentation`. This will compile your circuit without any additional debug information, so the resulting ACIR bytecode will be identical to the one produced by standard Noir compilation. However, if you opt for this, the `vars` command will not be available while debugging. +::: + + +### Stacktrace + +#### `stacktrace` + +Displays the current stack trace. + + +### Witness map + +#### `witness` (w) + +Show witness map. For example: + +``` +_0 = 0 +_1 = 2 +_2 = 1 +``` + +#### `witness [Witness Index]` + +Display a single witness from the witness map. For example: + +``` +> witness 1 +_1 = 2 +``` + +#### `witness [Witness Index] [New value]` + +Overwrite the given index with a new value. For example: + +``` +> witness 1 3 +_1 = 3 +``` + + +### Unconstrained VM memory + +#### `memory` + +Show unconstrained VM memory state. For example: + +``` +> memory +At opcode 1.13: Store { destination_pointer: RegisterIndex(0), source: RegisterIndex(3) } +... +> registers +0 = 0 +1 = 10 +2 = 0 +3 = 1 +4 = 1 +5 = 2³² +6 = 1 +> into +At opcode 1.14: Const { destination: RegisterIndex(5), value: Value { inner: 1 } } +... +> memory +0 = 1 +> +``` + +In the example above: we start with clean memory, then step through a `Store` opcode which stores the value of register 3 (1) into the memory address stored in register 0 (0). Thus now `memory` shows memory address 0 contains value 1. + +:::note +This command is only functional while the debugger is executing unconstrained code. +::: + +#### `memset [Memory address] [New value]` + +Update a memory cell with the given value. For example: + +``` +> memory +0 = 1 +> memset 0 2 +> memory +0 = 2 +> memset 1 4 +> memory +0 = 2 +1 = 4 +> +``` + +:::note +This command is only functional while the debugger is executing unconstrained code. +::: \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_vscode.md b/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_vscode.md new file mode 100644 index 00000000000..c027332b3b0 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/debugger/debugger_vscode.md @@ -0,0 +1,82 @@ +--- +title: VS Code Debugger +description: + VS Code Debugger configuration and features. +keywords: + [ + Nargo, + Noir CLI, + Noir Debugger, + VS Code, + IDE, + ] +sidebar_position: 0 +--- + +# VS Code Noir Debugger Reference + +The Noir debugger enabled by the vscode-noir extension ships with default settings such that the most common scenario should run without any additional configuration steps. + +These defaults can nevertheless be overridden by defining a launch configuration file. This page provides a reference for the properties you can override via a launch configuration file, as well as documenting the Nargo `dap` command, which is a dependency of the VS Code Noir debugger. + + +## Creating and editing launch configuration files + +To create a launch configuration file from VS Code, open the _debug pane_, and click on _create a launch.json file_. + +![Creating a launch configuration file](@site/static/img/debugger/ref1-create-launch.png) + +A `launch.json` file will be created, populated with basic defaults. + +### Noir Debugger launch.json properties + +#### projectFolder + +_String, optional._ + +Absolute path to the Nargo project to debug. By default, it is dynamically determined by looking for the nearest `Nargo.toml` file to the active file at the moment of launching the debugger. + +#### proverName + +_String, optional._ + +Name of the prover input to use. Defaults to `Prover`, which looks for a file named `Prover.toml` at the `projectFolder`. + +#### generateAcir + +_Boolean, optional._ + +If true, generate ACIR opcodes instead of unconstrained opcodes which will be closer to release binaries but less convenient for debugging. Defaults to `false`. + +#### skipInstrumentation + +_Boolean, optional._ + +Skips variables debugging instrumentation of code, making debugging less convenient but the resulting binary smaller and closer to production. Defaults to `false`. + +:::note +Skipping instrumentation causes the debugger to be unable to inspect local variables. +::: + +## `nargo dap [OPTIONS]` + +When run without any option flags, it starts the Nargo Debug Adapter Protocol server, which acts as the debugging backend for the VS Code Noir Debugger. + +All option flags are related to preflight checks. The Debug Adapter Protocol specifies how errors are to be informed from a running DAP server, but it doesn't specify mechanisms to communicate server initialization errors between the DAP server and its client IDE. + +Thus `nargo dap` ships with a _preflight check_ mode. If flag `--preflight-check` and the rest of the `--preflight-*` flags are provided, Nargo will run the same initialization routine except it will not start the DAP server. + +`vscode-noir` will then run `nargo dap` in preflight check mode first before a debugging session starts. If the preflight check ends in error, vscode-noir will present stderr and stdout output from this process through its own Output pane in VS Code. This makes it possible for users to diagnose what pieces of configuration might be wrong or missing in case of initialization errors. + +If the preflight check succeeds, `vscode-noir` proceeds to start the DAP server normally but running `nargo dap` without any additional flags. + +### Options + +| Option | Description | +| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `--preflight-check` | If present, dap runs in preflight check mode. | +| `--preflight-project-folder ` | Absolute path to the project to debug for preflight check. | +| `--preflight-prover-name ` | Name of prover file to use for preflight check | +| `--preflight-generate-acir` | Optional. If present, compile in ACIR mode while running preflight check. | +| `--preflight-skip-instrumentation` | Optional. If present, compile without introducing debug instrumentation while running preflight check. | +| `-h, --help` | Print help. | diff --git a/docs/versioned_docs/version-v0.28.0/reference/nargo_commands.md b/docs/versioned_docs/version-v0.28.0/reference/nargo_commands.md new file mode 100644 index 00000000000..218fcfb0c8c --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/reference/nargo_commands.md @@ -0,0 +1,381 @@ +--- +title: Nargo +description: + Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, + generate Solidity verifier smart contract and compile into JSON file containing ACIR + representation and ABI of circuit. +keywords: + [ + Nargo, + Noir CLI, + Noir Prover, + Noir Verifier, + generate Solidity verifier, + compile JSON file, + ACIR representation, + ABI of circuit, + TypeScript, + ] +sidebar_position: 0 +--- + +# Command-Line Help for `nargo` + +This document contains the help content for the `nargo` command-line program. + +**Command Overview:** + +* [`nargo`↴](#nargo) +* [`nargo backend`↴](#nargo-backend) +* [`nargo backend current`↴](#nargo-backend-current) +* [`nargo backend ls`↴](#nargo-backend-ls) +* [`nargo backend use`↴](#nargo-backend-use) +* [`nargo backend install`↴](#nargo-backend-install) +* [`nargo backend uninstall`↴](#nargo-backend-uninstall) +* [`nargo check`↴](#nargo-check) +* [`nargo fmt`↴](#nargo-fmt) +* [`nargo codegen-verifier`↴](#nargo-codegen-verifier) +* [`nargo compile`↴](#nargo-compile) +* [`nargo new`↴](#nargo-new) +* [`nargo init`↴](#nargo-init) +* [`nargo execute`↴](#nargo-execute) +* [`nargo prove`↴](#nargo-prove) +* [`nargo verify`↴](#nargo-verify) +* [`nargo test`↴](#nargo-test) +* [`nargo info`↴](#nargo-info) +* [`nargo lsp`↴](#nargo-lsp) + +## `nargo` + +Noir's package manager + +**Usage:** `nargo ` + +###### **Subcommands:** + +* `backend` — Install and select custom backends used to generate and verify proofs +* `check` — Checks the constraint system for errors +* `fmt` — Format the Noir files in a workspace +* `codegen-verifier` — Generates a Solidity verifier smart contract for the program +* `compile` — Compile the program and its secret execution trace into ACIR format +* `new` — Create a Noir project in a new directory +* `init` — Create a Noir project in the current directory +* `execute` — Executes a circuit to calculate its return value +* `prove` — Create proof for this program. The proof is returned as a hex encoded string +* `verify` — Given a proof and a program, verify whether the proof is valid +* `test` — Run the tests for this program +* `info` — Provides detailed information on each of a program's function (represented by a single circuit) +* `lsp` — Starts the Noir LSP server + +###### **Options:** + + + + +## `nargo backend` + +Install and select custom backends used to generate and verify proofs + +**Usage:** `nargo backend ` + +###### **Subcommands:** + +* `current` — Prints the name of the currently active backend +* `ls` — Prints the list of currently installed backends +* `use` — Select the backend to use +* `install` — Install a new backend from a URL +* `uninstall` — Uninstalls a backend + + + +## `nargo backend current` + +Prints the name of the currently active backend + +**Usage:** `nargo backend current` + + + +## `nargo backend ls` + +Prints the list of currently installed backends + +**Usage:** `nargo backend ls` + + + +## `nargo backend use` + +Select the backend to use + +**Usage:** `nargo backend use ` + +###### **Arguments:** + +* `` + + + +## `nargo backend install` + +Install a new backend from a URL + +**Usage:** `nargo backend install ` + +###### **Arguments:** + +* `` — The name of the backend to install +* `` — The URL from which to download the backend + + + +## `nargo backend uninstall` + +Uninstalls a backend + +**Usage:** `nargo backend uninstall ` + +###### **Arguments:** + +* `` — The name of the backend to uninstall + + + +## `nargo check` + +Checks the constraint system for errors + +**Usage:** `nargo check [OPTIONS]` + +###### **Options:** + +* `--package ` — The name of the package to check +* `--workspace` — Check all packages in the workspace +* `--overwrite` — Force overwrite of existing files +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo fmt` + +Format the Noir files in a workspace + +**Usage:** `nargo fmt [OPTIONS]` + +###### **Options:** + +* `--check` — Run noirfmt in check mode + + + +## `nargo codegen-verifier` + +Generates a Solidity verifier smart contract for the program + +**Usage:** `nargo codegen-verifier [OPTIONS]` + +###### **Options:** + +* `--package ` — The name of the package to codegen +* `--workspace` — Codegen all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo compile` + +Compile the program and its secret execution trace into ACIR format + +**Usage:** `nargo compile [OPTIONS]` + +###### **Options:** + +* `--package ` — The name of the package to compile +* `--workspace` — Compile all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo new` + +Create a Noir project in a new directory + +**Usage:** `nargo new [OPTIONS] ` + +###### **Arguments:** + +* `` — The path to save the new project + +###### **Options:** + +* `--name ` — Name of the package [default: package directory name] +* `--lib` — Use a library template +* `--bin` — Use a binary template [default] +* `--contract` — Use a contract template + + + +## `nargo init` + +Create a Noir project in the current directory + +**Usage:** `nargo init [OPTIONS]` + +###### **Options:** + +* `--name ` — Name of the package [default: current directory name] +* `--lib` — Use a library template +* `--bin` — Use a binary template [default] +* `--contract` — Use a contract template + + + +## `nargo execute` + +Executes a circuit to calculate its return value + +**Usage:** `nargo execute [OPTIONS] [WITNESS_NAME]` + +###### **Arguments:** + +* `` — Write the execution witness to named file + +###### **Options:** + +* `-p`, `--prover-name ` — The name of the toml file which contains the inputs for the prover + + Default value: `Prover` +* `--package ` — The name of the package to execute +* `--workspace` — Execute all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings +* `--oracle-resolver ` — JSON RPC url to solve oracle calls + + + +## `nargo prove` + +Create proof for this program. The proof is returned as a hex encoded string + +**Usage:** `nargo prove [OPTIONS]` + +###### **Options:** + +* `-p`, `--prover-name ` — The name of the toml file which contains the inputs for the prover + + Default value: `Prover` +* `-v`, `--verifier-name ` — The name of the toml file which contains the inputs for the verifier + + Default value: `Verifier` +* `--verify` — Verify proof after proving +* `--package ` — The name of the package to prove +* `--workspace` — Prove all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings +* `--oracle-resolver ` — JSON RPC url to solve oracle calls + + + +## `nargo verify` + +Given a proof and a program, verify whether the proof is valid + +**Usage:** `nargo verify [OPTIONS]` + +###### **Options:** + +* `-v`, `--verifier-name ` — The name of the toml file which contains the inputs for the verifier + + Default value: `Verifier` +* `--package ` — The name of the package verify +* `--workspace` — Verify all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo test` + +Run the tests for this program + +**Usage:** `nargo test [OPTIONS] [TEST_NAME]` + +###### **Arguments:** + +* `` — If given, only tests with names containing this string will be run + +###### **Options:** + +* `--show-output` — Display output of `println` statements +* `--exact` — Only run tests that match exactly +* `--package ` — The name of the package to test +* `--workspace` — Test all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings +* `--oracle-resolver ` — JSON RPC url to solve oracle calls + + + +## `nargo info` + +Provides detailed information on each of a program's function (represented by a single circuit) + +Current information provided per circuit: 1. The number of ACIR opcodes 2. Counts the final number gates in the circuit used by a backend + +**Usage:** `nargo info [OPTIONS]` + +###### **Options:** + +* `--package ` — The name of the package to detail +* `--workspace` — Detail all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo lsp` + +Starts the Noir LSP server + +Starts an LSP server which allows IDEs such as VS Code to display diagnostics in Noir source. + +VS Code Noir Language Support: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir + +**Usage:** `nargo lsp` + + + +
+ + + This document was generated automatically by + clap-markdown. + + diff --git a/docs/versioned_docs/version-v0.28.0/tooling/debugger.md b/docs/versioned_docs/version-v0.28.0/tooling/debugger.md new file mode 100644 index 00000000000..184c436068f --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/tooling/debugger.md @@ -0,0 +1,27 @@ +--- +title: Debugger +description: Learn about the Noir Debugger, in its REPL or VS Code versions. +keywords: [Nargo, VSCode, Visual Studio Code, REPL, Debugger] +sidebar_position: 2 +--- + +# Noir Debugger + +There are currently two ways of debugging Noir programs: + +1. From VS Code, via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). +2. Via the REPL debugger, which ships with Nargo. + +In order to use either version of the debugger, you will need to install recent enough versions of Noir, [Nargo](../getting_started/installation) and vscode-noir: + +- Noir 0.xx +- Nargo 0.xx +- vscode-noir 0.xx + +:::info +At the moment, the debugger supports debugging binary projects, but not contracts. +::: + +We cover the VS Code Noir debugger more in depth in [its VS Code debugger how-to guide](../how_to/debugger/debugging_with_vs_code.md) and [the reference](../reference/debugger/debugger_vscode.md). + +The REPL debugger is discussed at length in [the REPL debugger how-to guide](../how_to/debugger/debugging_with_the_repl.md) and [the reference](../reference/debugger/debugger_repl.md). diff --git a/docs/versioned_docs/version-v0.28.0/tooling/language_server.md b/docs/versioned_docs/version-v0.28.0/tooling/language_server.md new file mode 100644 index 00000000000..81e0356ef8a --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/tooling/language_server.md @@ -0,0 +1,43 @@ +--- +title: Language Server +description: Learn about the Noir Language Server, how to install the components, and configuration that may be required. +keywords: [Nargo, Language Server, LSP, VSCode, Visual Studio Code] +sidebar_position: 0 +--- + +This section helps you install and configure the Noir Language Server. + +The Language Server Protocol (LSP) has two components, the [Server](#language-server) and the [Client](#language-client). Below we describe each in the context of Noir. + +## Language Server + +The Server component is provided by the Nargo command line tool that you installed at the beginning of this guide. +As long as Nargo is installed and you've used it to run other commands in this guide, it should be good to go! + +If you'd like to verify that the `nargo lsp` command is available, you can run `nargo --help` and look for `lsp` in the list of commands. If you see it, you're using a version of Noir with LSP support. + +## Language Client + +The Client component is usually an editor plugin that launches the Server. It communicates LSP messages between the editor and the Server. For example, when you save a file, the Client will alert the Server, so it can try to compile the project and report any errors. + +Currently, Noir provides a Language Client for Visual Studio Code via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). + +> **Note:** Noir's Language Server Protocol support currently assumes users' VSCode workspace root to be the same as users' Noir project root (i.e. where Nargo.toml lies). +> +> If LSP features seem to be missing / malfunctioning, make sure you are opening your Noir project directly (instead of as a sub-folder) in your VSCode instance. + +When your language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, measuring circuit size, execution, and tests: + +![Compile and Execute](@site/static/img/codelens_compile_execute.png) +![Run test](@site/static/img/codelens_run_test.png) + +You should also see your tests in the `testing` panel: + +![Testing panel](@site/static/img/codelens_testing_panel.png) + +### Configuration + +- **Noir: Enable LSP** - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. +- **Noir: Nargo Flags** - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. +- **Noir: Nargo Path** - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. +- **Noir > Trace: Server** - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. diff --git a/docs/versioned_docs/version-v0.28.0/tooling/testing.md b/docs/versioned_docs/version-v0.28.0/tooling/testing.md new file mode 100644 index 00000000000..d3e0c522473 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/tooling/testing.md @@ -0,0 +1,62 @@ +--- +title: Testing in Noir +description: Learn how to use Nargo to test your Noir program in a quick and easy way +keywords: [Nargo, testing, Noir, compile, test] +sidebar_position: 1 +--- + +You can test your Noir programs using Noir circuits. + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. + +For example if you have a program like: + +```rust +fn add(x: u64, y: u64) -> u64 { + x + y +} +#[test] +fn test_add() { + assert(add(2,2) == 4); + assert(add(0,1) == 1); + assert(add(1,0) == 1); +} +``` + +Running `nargo test` will test that the `test_add` function can be executed while satisfying all +the constraints which allows you to test that add returns the expected values. Test functions can't +have any arguments currently. + +### Test fail + +You can write tests that are expected to fail by using the decorator `#[test(should_fail)]`. For example: + +```rust +fn add(x: u64, y: u64) -> u64 { + x + y +} +#[test(should_fail)] +fn test_add() { + assert(add(2,2) == 5); +} +``` + +You can be more specific and make it fail with a specific reason by using `should_fail_with = "`: + +```rust +fn main(african_swallow_avg_speed : Field) { + assert(african_swallow_avg_speed == 65, "What is the airspeed velocity of an unladen swallow"); +} + +#[test] +fn test_king_arthur() { + main(65); +} + +#[test(should_fail_with = "What is the airspeed velocity of an unladen swallow")] +fn test_bridgekeeper() { + main(32); +} + +``` diff --git a/docs/versioned_docs/version-v0.28.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.28.0/tutorials/noirjs_app.md new file mode 100644 index 00000000000..6446e0b2a76 --- /dev/null +++ b/docs/versioned_docs/version-v0.28.0/tutorials/noirjs_app.md @@ -0,0 +1,326 @@ +--- +title: Building a web app with NoirJS +description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment. +keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs, app] +sidebar_position: 0 +pagination_next: noir/concepts/data_types/index +--- + +NoirJS is a set of packages meant to work both in a browser and a server environment. In this tutorial, we will build a simple web app using them. From here, you should get an idea on how to proceed with your own Noir projects! + +You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). + +## Setup + +:::note + +Feel free to use whatever versions, just keep in mind that Nargo and the NoirJS packages are meant to be in sync. For example, Nargo 0.27.x matches `noir_js@0.27.x`, etc. + +In this guide, we will be pinned to 0.27.0. + +::: + +Before we start, we want to make sure we have Node and Nargo installed. + +We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). + +As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: + +```sh +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Easy enough. Onwards! + +## Our project + +ZK is a powerful technology. An app that doesn't reveal one of the inputs to _anyone_ is almost unbelievable, yet Noir makes it as easy as a single line of code. + +In fact, it's so simple that it comes nicely packaged in `nargo`. Let's do that! + +### Nargo + +Run: + +`nargo new circuit` + +And... That's about it. Your program is ready to be compiled and run. + +To compile, let's `cd` into the `circuit` folder to enter our project, and call: + +`nargo compile` + +This compiles our circuit into `json` format and add it to a new `target` folder. + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit <---- our working directory + ├── Nargo.toml + ├── src + │ └── main.nr + └── target + └── circuit.json +``` + +::: + +### Node and Vite + +If you want to explore Nargo, feel free to go on a side-quest now and follow the steps in the +[getting started](../getting_started/hello_noir/index.md) guide. However, we want our app to run on the browser, so we need Vite. + +Vite is a powerful tool to generate static websites. While it provides all kinds of features, let's just go barebones with some good old vanilla JS. + +To do this this, go back to the previous folder (`cd ..`) and create a new vite project by running `npm create vite` and choosing "Vanilla" and "Javascript". + +A wild `vite-project` directory should now appear in your root folder! Let's not waste any time and dive right in: + +```bash +cd vite-project +``` + +### Setting Up Vite and Configuring the Project + +Before we proceed with any coding, let's get our environment tailored for Noir. We'll start by laying down the foundations with a `vite.config.js` file. This little piece of configuration is our secret sauce for making sure everything meshes well with the NoirJS libraries and other special setups we might need, like handling WebAssembly modules. Here’s how you get that going: + +#### Creating the vite.config.js + +In your freshly minted `vite-project` folder, create a new file named `vite.config.js` and open it in your code editor. Paste the following to set the stage: + +```javascript +import { defineConfig } from "vite"; +import copy from "rollup-plugin-copy"; + +export default defineConfig({ + esbuild: { + target: "esnext", + }, + optimizeDeps: { + esbuildOptions: { + target: "esnext", + }, + }, + plugins: [ + copy({ + targets: [ + { src: "node_modules/**/*.wasm", dest: "node_modules/.vite/dist" }, + ], + copySync: true, + hook: "buildStart", + }), + ], + server: { + port: 3000, + }, +}); +``` + +#### Install Dependencies + +Now that our stage is set, install the necessary NoirJS packages along with our other dependencies: + +```bash +npm install && npm install @noir-lang/backend_barretenberg@0.27.0 @noir-lang/noir_js@0.27.0 +npm install rollup-plugin-copy --save-dev +``` + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit + └── ...etc... +└── vite-project <---- our working directory + └── ...etc... +``` + +::: + +#### Some cleanup + +`npx create vite` is amazing but it creates a bunch of files we don't really need for our simple example. Actually, let's just delete everything except for `vite.config.js`, `index.html`, `main.js` and `package.json`. I feel lighter already. + +![my heart is ready for you, noir.js](@site/static/img/memes/titanic.jpeg) + +## HTML + +Our app won't run like this, of course. We need some working HTML, at least. Let's open our broken-hearted `index.html` and replace everything with this code snippet: + +```html + + + + + + +

Noir app

+
+ + +
+
+

Logs

+

Proof

+
+ + +``` + +It _could_ be a beautiful UI... Depending on which universe you live in. + +## Some good old vanilla Javascript + +Our love for Noir needs undivided attention, so let's just open `main.js` and delete everything (this is where the romantic scenery becomes a bit creepy). + +Start by pasting in this boilerplate code: + +```js +const setup = async () => { + await Promise.all([ + import('@noir-lang/noirc_abi').then((module) => + module.default(new URL('@noir-lang/noirc_abi/web/noirc_abi_wasm_bg.wasm', import.meta.url).toString()), + ), + import('@noir-lang/acvm_js').then((module) => + module.default(new URL('@noir-lang/acvm_js/web/acvm_js_bg.wasm', import.meta.url).toString()), + ), + ]); +}; + +function display(container, msg) { + const c = document.getElementById(container); + const p = document.createElement('p'); + p.textContent = msg; + c.appendChild(p); +} + +document.getElementById('submitGuess').addEventListener('click', async () => { + try { + // here's where love happens + } catch (err) { + display('logs', 'Oh 💔 Wrong guess'); + } +}); +``` + +The display function doesn't do much. We're simply manipulating our website to see stuff happening. For example, if the proof fails, it will simply log a broken heart 😢 + +As for the `setup` function, it's just a sad reminder that dealing with `wasm` on the browser is not as easy as it should. Just copy, paste, and forget. + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit + └── ...same as above +└── vite-project + ├── vite.config.js + ├── main.js + ├── package.json + └── index.html +``` + +You'll see other files and folders showing up (like `package-lock.json`, `node_modules`) but you shouldn't have to care about those. + +::: + +## Some NoirJS + +We're starting with the good stuff now. If you've compiled the circuit as described above, you should have a `json` file we want to import at the very top of our `main.js` file: + +```ts +import circuit from '../circuit/target/circuit.json'; +``` + +[Noir is backend-agnostic](../index.mdx#whats-new-about-noir). We write Noir, but we also need a proving backend. That's why we need to import and instantiate the two dependencies we installed above: `BarretenbergBackend` and `Noir`. Let's import them right below: + +```js +import { BarretenbergBackend, BarretenbergVerifier as Verifier } from '@noir-lang/backend_barretenberg'; +import { Noir } from '@noir-lang/noir_js'; +``` + +And instantiate them inside our try-catch block: + +```ts +// try { +const backend = new BarretenbergBackend(circuit); +const noir = new Noir(circuit, backend); +// } +``` + +:::note + +For the remainder of the tutorial, everything will be happening inside the `try` block + +::: + +## Our app + +Now for the app itself. We're capturing whatever is in the input when people press the submit button. Just add this: + +```js +const x = parseInt(document.getElementById('guessInput').value); +const input = { x, y: 2 }; +``` + +Now we're ready to prove stuff! Let's feed some inputs to our circuit and calculate the proof: + +```js +await setup(); // let's squeeze our wasm inits here + +display('logs', 'Generating proof... ⌛'); +const proof = await noir.generateProof(input); +display('logs', 'Generating proof... ✅'); +display('results', proof.proof); +``` + +You're probably eager to see stuff happening, so go and run your app now! + +From your terminal, run `npm run dev`. If it doesn't open a browser for you, just visit `localhost:5173`. You should now see the worst UI ever, with an ugly input. + +![Getting Started 0](@site/static/img/noir_getting_started_1.png) + +Now, our circuit says `fn main(x: Field, y: pub Field)`. This means only the `y` value is public, and it's hardcoded above: `input = { x, y: 2 }`. In other words, you won't need to send your secret`x` to the verifier! + +By inputting any number other than 2 in the input box and clicking "submit", you should get a valid proof. Otherwise the proof won't even generate correctly. By the way, if you're human, you shouldn't be able to understand anything on the "proof" box. That's OK. We like you, human ❤️. + +## Verifying + +Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add these lines to see our proof being verified: + +```js +display('logs', 'Verifying proof... ⌛'); +const verificationKey = await backend.getVerificationKey(); +const verifier = new Verifier(); +const isValid = await verifier.verifyProof(proof, verificationKey); +if (isValid) display('logs', 'Verifying proof... ✅'); +``` + +You have successfully generated a client-side Noir web app! + +![coded app without math knowledge](@site/static/img/memes/flextape.jpeg) + +## Further Reading + +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. + +You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/docs/versioned_docs/version-v0.29.0/explainers/explainer-oracle.md b/docs/versioned_docs/version-v0.29.0/explainers/explainer-oracle.md new file mode 100644 index 00000000000..b84ca5dd986 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/explainers/explainer-oracle.md @@ -0,0 +1,57 @@ +--- +title: Oracles +description: This guide provides an in-depth understanding of how Oracles work in Noir programming. Learn how to use outside calculations in your programs, constrain oracles, and understand their uses and limitations. +keywords: + - Noir Programming + - Oracles + - JSON-RPC + - Foreign Call Handlers + - Constrained Functions + - Blockchain Programming +sidebar_position: 1 +--- + +If you've seen "The Matrix" you may recall "The Oracle" as Gloria Foster smoking cigarettes and baking cookies. While she appears to "know things", she is actually providing a calculation of a pre-determined future. Noir Oracles are similar, in a way. They don't calculate the future (yet), but they allow you to use outside calculations in your programs. + +![matrix oracle prediction](@site/static/img/memes/matrix_oracle.jpeg) + +A Noir program is usually self-contained. You can pass certain inputs to it, and it will generate a deterministic output for those inputs. But what if you wanted to defer some calculation to an outside process or source? + +Oracles are functions that provide this feature. + +## Use cases + +An example usage for Oracles is proving something on-chain. For example, proving that the ETH-USDC quote was below a certain target at a certain block time. Or even making more complex proofs like proving the ownership of an NFT as an anonymous login method. + +Another interesting use case is to defer expensive calculations to be made outside of the Noir program, and then constraining the result; similar to the use of [unconstrained functions](../noir/concepts//unconstrained.md). + +In short, anything that can be constrained in a Noir program but needs to be fetched from an external source is a great candidate to be used in oracles. + +## Constraining oracles + +Just like in The Matrix, Oracles are powerful. But with great power, comes great responsibility. Just because you're using them in a Noir program doesn't mean they're true. Noir has no superpowers. If you want to prove that Portugal won the Euro Cup 2016, you're still relying on potentially untrusted information. + +To give a concrete example, Alice wants to login to the [NounsDAO](https://nouns.wtf/) forum with her username "noir_nouner" by proving she owns a noun without revealing her ethereum address. Her Noir program could have a oracle call like this: + +```rust +#[oracle(getNoun)] +unconstrained fn get_noun(address: Field) -> Field +``` + +This oracle could naively resolve with the number of Nouns she possesses. However, it is useless as a trusted source, as the oracle could resolve to anything Alice wants. In order to make this oracle call actually useful, Alice would need to constrain the response from the oracle, by proving her address and the noun count belongs to the state tree of the contract. + +In short, **Oracles don't prove anything. Your Noir program does.** + +:::danger + +If you don't constrain the return of your oracle, you could be clearly opening an attack vector on your Noir program. Make double-triple sure that the return of an oracle call is constrained! + +::: + +## How to use Oracles + +On CLI, Nargo resolves oracles by making JSON RPC calls, which means it would require an RPC node to be running. + +In JavaScript, NoirJS accepts and resolves arbitrary call handlers (that is, not limited to JSON) as long as they matches the expected types the developer defines. Refer to [Foreign Call Handler](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) to learn more about NoirJS's call handling. + +If you want to build using oracles, follow through to the [oracle guide](../how_to/how-to-oracles.md) for a simple example on how to do that. diff --git a/docs/versioned_docs/version-v0.29.0/explainers/explainer-recursion.md b/docs/versioned_docs/version-v0.29.0/explainers/explainer-recursion.md new file mode 100644 index 00000000000..18846176ca7 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/explainers/explainer-recursion.md @@ -0,0 +1,176 @@ +--- +title: Recursive proofs +description: Explore the concept of recursive proofs in Zero-Knowledge programming. Understand how recursion works in Noir, a language for writing smart contracts on the EVM blockchain. Learn through practical examples like Alice and Bob's guessing game, Charlie's recursive merkle tree, and Daniel's reusable components. Discover how to use recursive proofs to optimize computational resources and improve efficiency. + +keywords: + [ + "Recursive Proofs", + "Zero-Knowledge Programming", + "Noir", + "EVM Blockchain", + "Smart Contracts", + "Recursion in Noir", + "Alice and Bob Guessing Game", + "Recursive Merkle Tree", + "Reusable Components", + "Optimizing Computational Resources", + "Improving Efficiency", + "Verification Key", + "Aggregation", + "Recursive zkSNARK schemes", + "PLONK", + "Proving and Verification Keys" + ] +sidebar_position: 1 +pagination_next: how_to/how-to-recursion +--- + +In programming, we tend to think of recursion as something calling itself. A classic example would be the calculation of the factorial of a number: + +```js +function factorial(n) { + if (n === 0 || n === 1) { + return 1; + } else { + return n * factorial(n - 1); + } +} +``` + +In this case, while `n` is not `1`, this function will keep calling itself until it hits the base case, bubbling up the result on the call stack: + +```md + Is `n` 1? <--------- + /\ / + / \ n = n -1 + / \ / + Yes No -------- +``` + +In Zero-Knowledge, recursion has some similarities. + +It is not a Noir function calling itself, but a proof being used as an input to another circuit. In short, you verify one proof *inside* another proof, returning the proof that both proofs are valid. + +This means that, given enough computational resources, you can prove the correctness of any arbitrary number of proofs in a single proof. This could be useful to design state channels (for which a common example would be [Bitcoin's Lightning Network](https://en.wikipedia.org/wiki/Lightning_Network)), to save on gas costs by settling one proof on-chain, or simply to make business logic less dependent on a consensus mechanism. + +## Examples + +Let us look at some of these examples + +### Alice and Bob - Guessing game + +Alice and Bob are friends, and they like guessing games. They want to play a guessing game online, but for that, they need a trusted third-party that knows both of their secrets and finishes the game once someone wins. + +So, they use zero-knowledge proofs. Alice tries to guess Bob's number, and Bob will generate a ZK proof stating whether she succeeded or failed. + +This ZK proof can go on a smart contract, revealing the winner and even giving prizes. However, this means every turn needs to be verified on-chain. This incurs some cost and waiting time that may simply make the game too expensive or time-consuming to be worth it. + +As a solution, Alice proposes the following: "what if Bob generates his proof, and instead of sending it on-chain, I verify it *within* my own proof before playing my own turn?". + +She can then generate a proof that she verified his proof, and so on. + +```md + Did you fail? <-------------------------- + / \ / + / \ n = n -1 + / \ / + Yes No / + | | / + | | / + | You win / + | / + | / +Generate proof of that / + + / + my own guess ---------------- +``` + +### Charlie - Recursive merkle tree + +Charlie is a concerned citizen, and wants to be sure his vote in an election is accounted for. He votes with a ZK proof, but he has no way of knowing that his ZK proof was included in the total vote count! + +If the vote collector puts all of the votes into a [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree), everyone can prove the verification of two proofs within one proof, as such: + +```md + abcd + __________|______________ + | | + ab cd + _____|_____ ______|______ + | | | | + alice bob charlie daniel +``` + +Doing this recursively allows us to arrive on a final proof `abcd` which if true, verifies the correctness of all the votes. + +### Daniel - Reusable components + +Daniel has a big circuit and a big headache. A part of his circuit is a setup phase that finishes with some assertions that need to be made. But that section alone takes most of the proving time, and is largely independent of the rest of the circuit. + +He might find it more efficient to generate a proof for that setup phase separately, and verify that proof recursively in the actual business logic section of his circuit. This will allow for parallelization of both proofs, which results in a considerable speedup. + +## What params do I need + +As you can see in the [recursion reference](noir/standard_library/recursion.md), a simple recursive proof requires: + +- The proof to verify +- The Verification Key of the circuit that generated the proof +- A hash of this verification key, as it's needed for some backends +- The public inputs for the proof + +:::info + +Recursive zkSNARK schemes do not necessarily "verify a proof" in the sense that you expect a true or false to be spit out by the verifier. Rather an aggregation object is built over the public inputs. + +So, taking the example of Alice and Bob and their guessing game: + +- Alice makes her guess. Her proof is *not* recursive: it doesn't verify any proof within it! It's just a standard `assert(x != y)` circuit +- Bob verifies Alice's proof and makes his own guess. In this circuit, he doesn't exactly *prove* the verification of Alice's proof. Instead, he *aggregates* his proof to Alice's proof. The actual verification is done when the full proof is verified, for example when using `nargo verify` or through the verifier smart contract. + +We can imagine recursive proofs a [relay race](https://en.wikipedia.org/wiki/Relay_race). The first runner doesn't have to receive the baton from anyone else, as he/she already starts with it. But when his/her turn is over, the next runner needs to receive it, run a bit more, and pass it along. Even though every runner could theoretically verify the baton mid-run (why not? 🏃🔍), only at the end of the race does the referee verify that the whole race is valid. + +::: + +## Some architecture + +As with everything in computer science, there's no one-size-fits all. But there are some patterns that could help understanding and implementing them. To give three examples: + +### Adding some logic to a proof verification + +This would be an approach for something like our guessing game, where proofs are sent back and forth and are verified by each opponent. This circuit would be divided in two sections: + +- A `recursive verification` section, which would be just the call to `std::verify_proof`, and that would be skipped on the first move (since there's no proof to verify) +- A `guessing` section, which is basically the logic part where the actual guessing happens + +In such a situation, and assuming Alice is first, she would skip the first part and try to guess Bob's number. Bob would then verify her proof on the first section of his run, and try to guess Alice's number on the second part, and so on. + +### Aggregating proofs + +In some one-way interaction situations, recursion would allow for aggregation of simple proofs that don't need to be immediately verified on-chain or elsewhere. + +To give a practical example, a barman wouldn't need to verify a "proof-of-age" on-chain every time he serves alcohol to a customer. Instead, the architecture would comprise two circuits: + +- A `main`, non-recursive circuit with some logic +- A `recursive` circuit meant to verify two proofs in one proof + +The customer's proofs would be intermediate, and made on their phones, and the barman could just verify them locally. He would then aggregate them into a final proof sent on-chain (or elsewhere) at the end of the day. + +### Recursively verifying different circuits + +Nothing prevents you from verifying different circuits in a recursive proof, for example: + +- A `circuit1` circuit +- A `circuit2` circuit +- A `recursive` circuit + +In this example, a regulator could verify that taxes were paid for a specific purchase by aggregating both a `payer` circuit (proving that a purchase was made and taxes were paid), and a `receipt` circuit (proving that the payment was received) + +## How fast is it + +At the time of writing, verifying recursive proofs is surprisingly fast. This is because most of the time is spent on generating the verification key that will be used to generate the next proof. So you are able to cache the verification key and reuse it later. + +Currently, Noir JS packages don't expose the functionality of loading proving and verification keys, but that feature exists in the underlying `bb.js` package. + +## How can I try it + +Learn more about using recursion in Nargo and NoirJS in the [how-to guide](../how_to/how-to-recursion.md) and see a full example in [noir-examples](https://github.com/noir-lang/noir-examples). diff --git a/docs/versioned_docs/version-v0.29.0/getting_started/_category_.json b/docs/versioned_docs/version-v0.29.0/getting_started/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/getting_started/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/_category_.json b/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/index.md b/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/index.md new file mode 100644 index 00000000000..743c4d8d634 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/index.md @@ -0,0 +1,142 @@ +--- +title: Creating a Project +description: + Learn how to create and verify your first Noir program using Nargo, a programming language for + zero-knowledge proofs. +keywords: + [ + Nargo, + Noir, + zero-knowledge proofs, + programming language, + create Noir program, + verify Noir program, + step-by-step guide, + ] +sidebar_position: 1 + +--- + +Now that we have installed Nargo, it is time to make our first hello world program! + +## Create a Project Directory + +Noir code can live anywhere on your computer. Let us create a _projects_ folder in the home +directory to house our Noir programs. + +For Linux, macOS, and Windows PowerShell, create the directory and change directory into it by +running: + +```sh +mkdir ~/projects +cd ~/projects +``` + +## Create Our First Nargo Project + +Now that we are in the projects directory, create a new Nargo project by running: + +```sh +nargo new hello_world +``` + +> **Note:** `hello_world` can be any arbitrary project name, we are simply using `hello_world` for +> demonstration. +> +> In production, the common practice is to name the project folder as `circuits` for better +> identifiability when sitting alongside other folders in the codebase (e.g. `contracts`, `scripts`, +> `test`). + +A `hello_world` folder would be created. Similar to Rust, the folder houses _src/main.nr_ and +_Nargo.toml_ which contain the source code and environmental options of your Noir program +respectively. + +### Intro to Noir Syntax + +Let us take a closer look at _main.nr_. The default _main.nr_ generated should look like this: + +```rust +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` + +The first line of the program specifies the program's inputs: + +```rust +x : Field, y : pub Field +``` + +Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the +keyword `pub` (e.g. `y`). To learn more about private and public values, check the +[Data Types](../../noir/concepts/data_types/index.md) section. + +The next line of the program specifies its body: + +```rust +assert(x != y); +``` + +The Noir syntax `assert` can be interpreted as something similar to constraints in other zk-contract languages. + +For more Noir syntax, check the [Language Concepts](../../noir/concepts/comments.md) chapter. + +## Build In/Output Files + +Change directory into _hello_world_ and build in/output files for your Noir program by running: + +```sh +cd hello_world +nargo check +``` + +Two additional files would be generated in your project directory: + +_Prover.toml_ houses input values, and _Verifier.toml_ houses public values. + +## Prove Our Noir Program + +Now that the project is set up, we can create a proof of correct execution of our Noir program. + +Fill in input values for execution in the _Prover.toml_ file. For example: + +```toml +x = "1" +y = "2" +``` + +Prove the valid execution of your Noir program: + +```sh +nargo prove +``` + +A new folder _proofs_ would then be generated in your project directory, containing the proof file +`.proof`, where the project name is defined in Nargo.toml. + +The _Verifier.toml_ file would also be updated with the public values computed from program +execution (in this case the value of `y`): + +```toml +y = "0x0000000000000000000000000000000000000000000000000000000000000002" +``` + +> **Note:** Values in _Verifier.toml_ are computed as 32-byte hex values. + +## Verify Our Noir Program + +Once a proof is generated, we can verify correct execution of our Noir program by verifying the +proof file. + +Verify your proof by running: + +```sh +nargo verify +``` + +The verification will complete in silence if it is successful. If it fails, it will log the +corresponding error instead. + +Congratulations, you have now created and verified a proof for your very first Noir program! + +In the [next section](./project_breakdown.md), we will go into more detail on each step performed. diff --git a/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/project_breakdown.md b/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/project_breakdown.md new file mode 100644 index 00000000000..6160a102c6c --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/getting_started/hello_noir/project_breakdown.md @@ -0,0 +1,199 @@ +--- +title: Project Breakdown +description: + Learn about the anatomy of a Nargo project, including the purpose of the Prover and Verifier TOML + files, and how to prove and verify your program. +keywords: + [Nargo, Nargo project, Prover.toml, Verifier.toml, proof verification, private asset transfer] +sidebar_position: 2 +--- + +This section breaks down our hello world program from the previous section. We elaborate on the project +structure and what the `prove` and `verify` commands did. + +## Anatomy of a Nargo Project + +Upon creating a new project with `nargo new` and building the in/output files with `nargo check` +commands, you would get a minimal Nargo project of the following structure: + + - src + - Prover.toml + - Verifier.toml + - Nargo.toml + +The source directory _src_ holds the source code for your Noir program. By default only a _main.nr_ +file will be generated within it. + +### Prover.toml + +_Prover.toml_ is used for specifying the input values for executing and proving the program. You can specify `toml` files with different names by using the `--prover-name` or `-p` flags, see the [Prover](#provertoml) section below. Optionally you may specify expected output values for prove-time checking as well. + +### Verifier.toml + +_Verifier.toml_ contains public in/output values computed when executing the Noir program. + +### Nargo.toml + +_Nargo.toml_ contains the environmental options of your project. It contains a "package" section and a "dependencies" section. + +Example Nargo.toml: + +```toml +[package] +name = "noir_starter" +type = "bin" +authors = ["Alice"] +compiler_version = "0.9.0" +description = "Getting started with Noir" +entry = "circuit/main.nr" +license = "MIT" + +[dependencies] +ecrecover = {tag = "v0.9.0", git = "https://github.com/colinnielsen/ecrecover-noir.git"} +``` + +Nargo.toml for a [workspace](../../noir/modules_packages_crates/workspaces.md) will look a bit different. For example: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +#### Package section + +The package section defines a number of fields including: + +- `name` (**required**) - the name of the package +- `type` (**required**) - can be "bin", "lib", or "contract" to specify whether its a binary, library or Aztec contract +- `authors` (optional) - authors of the project +- `compiler_version` - specifies the version of the compiler to use. This is enforced by the compiler and follow's [Rust's versioning](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field), so a `compiler_version = 0.18.0` will enforce Nargo version 0.18.0, `compiler_version = ^0.18.0` will enforce anything above 0.18.0 but below 0.19.0, etc. For more information, see how [Rust handles these operators](https://docs.rs/semver/latest/semver/enum.Op.html) +- `description` (optional) +- `entry` (optional) - a relative filepath to use as the entry point into your package (overrides the default of `src/lib.nr` or `src/main.nr`) +- `backend` (optional) +- `license` (optional) + +#### Dependencies section + +This is where you will specify any dependencies for your project. See the [Dependencies page](../../noir/modules_packages_crates/dependencies.md) for more info. + +`./proofs/` and `./contract/` directories will not be immediately visible until you create a proof or +verifier contract respectively. + +### main.nr + +The _main.nr_ file contains a `main` method, this method is the entry point into your Noir program. + +In our sample program, _main.nr_ looks like this: + +```rust +fn main(x : Field, y : Field) { + assert(x != y); +} +``` + +The parameters `x` and `y` can be seen as the API for the program and must be supplied by the +prover. Since neither `x` nor `y` is marked as public, the verifier does not supply any inputs, when +verifying the proof. + +The prover supplies the values for `x` and `y` in the _Prover.toml_ file. + +As for the program body, `assert` ensures that the condition to be satisfied (e.g. `x != y`) is +constrained by the proof of the execution of said program (i.e. if the condition was not met, the +verifier would reject the proof as an invalid proof). + +### Prover.toml + +The _Prover.toml_ file is a file which the prover uses to supply his witness values(both private and +public). + +In our hello world program the _Prover.toml_ file looks like this: + +```toml +x = "1" +y = "2" +``` + +When the command `nargo prove` is executed, two processes happen: + +1. Noir creates a proof that `x`, which holds the value of `1`, and `y`, which holds the value of `2`, + is not equal. This inequality constraint is due to the line `assert(x != y)`. + +2. Noir creates and stores the proof of this statement in the _proofs_ directory in a file called your-project.proof. So if your project is named "private_voting" (defined in the project Nargo.toml), the proof will be saved at `./proofs/private_voting.proof`. Opening this file will display the proof in hex format. + +#### Arrays of Structs + +The following code shows how to pass an array of structs to a Noir program to generate a proof. + +```rust +// main.nr +struct Foo { + bar: Field, + baz: Field, +} + +fn main(foos: [Foo; 3]) -> pub Field { + foos[2].bar + foos[2].baz +} +``` + +Prover.toml: + +```toml +[[foos]] # foos[0] +bar = 0 +baz = 0 + +[[foos]] # foos[1] +bar = 0 +baz = 0 + +[[foos]] # foos[2] +bar = 1 +baz = 2 +``` + +#### Custom toml files + +You can specify a `toml` file with a different name to use for proving by using the `--prover-name` or `-p` flags. + +This command looks for proof inputs in the default **Prover.toml** and generates the proof and saves it at `./proofs/.proof`: + +```bash +nargo prove +``` + +This command looks for proof inputs in the custom **OtherProver.toml** and generates proof and saves it at `./proofs/.proof`: + +```bash +nargo prove -p OtherProver +``` + +## Verifying a Proof + +When the command `nargo verify` is executed, two processes happen: + +1. Noir checks in the _proofs_ directory for a proof file with the project name (eg. test_project.proof) + +2. If that file is found, the proof's validity is checked + +> **Note:** The validity of the proof is linked to the current Noir program; if the program is +> changed and the verifier verifies the proof, it will fail because the proof is not valid for the +> _modified_ Noir program. + +In production, the prover and the verifier are usually two separate entities. A prover would +retrieve the necessary inputs, execute the Noir program, generate a proof and pass it to the +verifier. The verifier would then retrieve the public inputs, usually from external sources, and +verify the validity of the proof against it. + +Take a private asset transfer as an example: + +A person using a browser as the prover would retrieve private inputs locally (e.g. the user's private key) and +public inputs (e.g. the user's encrypted balance on-chain), compute the transfer, generate a proof +and submit it to the verifier smart contract. + +The verifier contract would then draw the user's encrypted balance directly from the blockchain and +verify the proof submitted against it. If the verification passes, additional functions in the +verifier contract could trigger (e.g. approve the asset transfer). + +Now that you understand the concepts, you'll probably want some editor feedback while you are writing more complex code. diff --git a/docs/versioned_docs/version-v0.29.0/getting_started/installation/_category_.json b/docs/versioned_docs/version-v0.29.0/getting_started/installation/_category_.json new file mode 100644 index 00000000000..0c02fb5d4d7 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/getting_started/installation/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 0, + "label": "Install Nargo", + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/getting_started/installation/index.md b/docs/versioned_docs/version-v0.29.0/getting_started/installation/index.md new file mode 100644 index 00000000000..4ef86aa5914 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/getting_started/installation/index.md @@ -0,0 +1,48 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs. This page is a quick guide on how to install Nargo through the most common and easy method, noirup +keywords: [ + Nargo + Noir + Rust + Cargo + Noirup + Installation + Terminal Commands + Version Check + Nightlies + Specific Versions + Branches + Noirup Repository +] +pagination_next: getting_started/hello_noir/index +--- + +`nargo` is the one-stop-shop for almost everything related with Noir. The name comes from our love for Rust and its package manager `cargo`. + +With `nargo`, you can start new projects, compile, execute, prove, verify, test, generate solidity contracts, and do pretty much all that is available in Noir. + +Similarly to `rustup`, we also maintain an easy installation method that covers most machines: `noirup`. + +## Installing Noirup + +Open a terminal on your machine, and write: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done. That's it. You should have the latest version working. You can check with `nargo --version`. + +You can also install nightlies, specific versions +or branches. Check out the [noirup repository](https://github.com/noir-lang/noirup) for more +information. + +Now we're ready to start working on [our first Noir program!](../hello_noir/index.md) diff --git a/docs/versioned_docs/version-v0.29.0/getting_started/installation/other_install_methods.md b/docs/versioned_docs/version-v0.29.0/getting_started/installation/other_install_methods.md new file mode 100644 index 00000000000..3634723562b --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/getting_started/installation/other_install_methods.md @@ -0,0 +1,102 @@ +--- +title: Alternative Installations +description: There are different ways to install Nargo, the one-stop shop and command-line tool for developing Noir programs. This guide explains how to specify which version to install when using noirup, and using WSL for windows. +keywords: [ + Installation + Nargo + Noirup + Binaries + Compiling from Source + WSL for Windows + macOS + Linux + Nix + Direnv + Uninstalling Nargo + ] +sidebar_position: 1 +--- + +## Encouraged Installation Method: Noirup + +Noirup is the endorsed method for installing Nargo, streamlining the process of fetching binaries or compiling from source. It supports a range of options to cater to your specific needs, from nightly builds and specific versions to compiling from various sources. + +### Installing Noirup + +First, ensure you have `noirup` installed: + +```sh +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +### Fetching Binaries + +With `noirup`, you can easily switch between different Nargo versions, including nightly builds: + +- **Nightly Version**: Install the latest nightly build. + + ```sh + noirup --version nightly + ``` + +- **Specific Version**: Install a specific version of Nargo. + ```sh + noirup --version + ``` + +### Compiling from Source + +`noirup` also enables compiling Nargo from various sources: + +- **From a Specific Branch**: Install from the latest commit on a branch. + + ```sh + noirup --branch + ``` + +- **From a Fork**: Install from the main branch of a fork. + + ```sh + noirup --repo + ``` + +- **From a Specific Branch in a Fork**: Install from a specific branch in a fork. + + ```sh + noirup --repo --branch + ``` + +- **From a Specific Pull Request**: Install from a specific PR. + + ```sh + noirup --pr + ``` + +- **From a Specific Commit**: Install from a specific commit. + + ```sh + noirup -C + ``` + +- **From Local Source**: Compile and install from a local directory. + ```sh + noirup --path ./path/to/local/source + ``` + +## Installation on Windows + +The default backend for Noir (Barretenberg) doesn't provide Windows binaries at this time. For that reason, Noir cannot be installed natively. However, it is available by using Windows Subsystem for Linux (WSL). + +Step 1: Follow the instructions [here](https://learn.microsoft.com/en-us/windows/wsl/install) to install and run WSL. + +step 2: Follow the [Noirup instructions](#encouraged-installation-method-noirup). + +## Uninstalling Nargo + +If you installed Nargo with `noirup`, you can uninstall Nargo by removing the files in `~/.nargo`, `~/nargo`, and `~/noir_cache`. This ensures that all installed binaries, configurations, and cache related to Nargo are fully removed from your system. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` diff --git a/docs/versioned_docs/version-v0.29.0/getting_started/tooling/noir_codegen.md b/docs/versioned_docs/version-v0.29.0/getting_started/tooling/noir_codegen.md new file mode 100644 index 00000000000..d65151da0ab --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/getting_started/tooling/noir_codegen.md @@ -0,0 +1,113 @@ +--- +title: Noir Codegen for TypeScript +description: Learn how to use Noir codegen to generate TypeScript bindings +keywords: [Nargo, Noir, compile, TypeScript] +sidebar_position: 2 +--- + +When using TypeScript, it is extra work to interpret Noir program outputs in a type-safe way. Third party libraries may exist for popular Noir programs, but they are either hard to find or unmaintained. + +Now you can generate TypeScript bindings for your Noir programs in two steps: +1. Exporting Noir functions using `nargo export` +2. Using the TypeScript module `noir_codegen` to generate TypeScript binding + +**Note:** you can only export functions from a Noir *library* (not binary or contract program types). + +## Installation + +### Your TypeScript project + +If you don't already have a TypeScript project you can add the module with `yarn` (or `npm`), then initialize it: + +```bash +yarn add typescript -D +npx tsc --init +``` + +### Add TypeScript module - `noir_codegen` + +The following command will add the module to your project's devDependencies: + +```bash +yarn add @noir-lang/noir_codegen -D +``` + +### Nargo library +Make sure you have Nargo, v0.25.0 or greater, installed. If you don't, follow the [installation guide](../installation/index.md). + +If you're in a new project, make a `circuits` folder and create a new Noir library: + +```bash +mkdir circuits && cd circuits +nargo new --lib myNoirLib +``` + +## Usage + +### Export ABI of specified functions + +First go to the `.nr` files in your Noir library, and add the `#[export]` macro to each function that you want to use in TypeScript. + +```rust +#[export] +fn your_function(... +``` + +From your Noir library (where `Nargo.toml` is), run the following command: + +```bash +nargo export +``` + +You will now have an `export` directory with a .json file per exported function. + +You can also specify the directory of Noir programs using `--program-dir`, for example: + +```bash +nargo export --program-dir=./circuits/myNoirLib +``` + +### Generate TypeScript bindings from exported functions + +To use the `noir-codegen` package we added to the TypeScript project: + +```bash +yarn noir-codegen ./export/your_function.json +``` + +This creates an `exports` directory with an `index.ts` file containing all exported functions. + +**Note:** adding `--out-dir` allows you to specify an output dir for your TypeScript bindings to go. Eg: + +```bash +yarn noir-codegen ./export/*.json --out-dir ./path/to/output/dir +``` + +## Example .nr function to .ts output + +Consider a Noir library with this function: + +```rust +#[export] +fn not_equal(x: Field, y: Field) -> bool { + x != y +} +``` + +After the export and codegen steps, you should have an `index.ts` like: + +```typescript +export type Field = string; + + +export const is_equal_circuit: CompiledCircuit = {"abi":{"parameters":[{"name":"x","type":{"kind":"field"},"visibility":"private"},{"name":"y","type":{"kind":"field"},"visibility":"private"}],"param_witnesses":{"x":[{"start":0,"end":1}],"y":[{"start":1,"end":2}]},"return_type":{"abi_type":{"kind":"boolean"},"visibility":"private"},"return_witnesses":[4]},"bytecode":"H4sIAAAAAAAA/7WUMQ7DIAxFQ0Krrr2JjSGYLVcpKrn/CaqqDQN12WK+hPBgmWd/wEyHbF1SS923uhOs3pfoChI+wKXMAXzIKyNj4PB0TFTYc0w5RUjoqeAeEu1wqK0F54RGkWvW44LPzExnlkbMEs4JNZmN8PxS42uHv82T8a3Jeyn2Ks+VLPcO558HmyLMCDOXAXXtpPt4R/Rt9T36ss6dS9HGPx/eG17nGegKBQAA"}; + +export async function is_equal(x: Field, y: Field, foreignCallHandler?: ForeignCallHandler): Promise { + const program = new Noir(is_equal_circuit); + const args: InputMap = { x, y }; + const { returnValue } = await program.execute(args, foreignCallHandler); + return returnValue as boolean; +} +``` + +Now the `is_equal()` function and relevant types are readily available for use in TypeScript. diff --git a/docs/versioned_docs/version-v0.29.0/how_to/_category_.json b/docs/versioned_docs/version-v0.29.0/how_to/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/how_to/debugger/_category_.json b/docs/versioned_docs/version-v0.29.0/how_to/debugger/_category_.json new file mode 100644 index 00000000000..cc2cbb1c253 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/debugger/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Debugging", + "position": 5, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/how_to/debugger/debugging_with_the_repl.md b/docs/versioned_docs/version-v0.29.0/how_to/debugger/debugging_with_the_repl.md new file mode 100644 index 00000000000..09e5bae68ad --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/debugger/debugging_with_the_repl.md @@ -0,0 +1,164 @@ +--- +title: Using the REPL Debugger +description: + Step by step guide on how to debug your Noir circuits with the REPL Debugger. +keywords: + [ + Nargo, + Noir CLI, + Noir Debugger, + REPL, + ] +sidebar_position: 1 +--- + +#### Pre-requisites + +In order to use the REPL debugger, first you need to install recent enough versions of Nargo and vscode-noir. + +## Debugging a simple circuit + +Let's debug a simple circuit: + +```rust +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` + +To start the REPL debugger, using a terminal, go to a Noir circuit's home directory. Then: + +`$ nargo debug` + +You should be seeing this in your terminal: + +``` +[main] Starting debugger +At ~/noir-examples/recursion/circuits/main/src/main.nr:1:9 + 1 -> fn main(x : Field, y : pub Field) { + 2 assert(x != y); + 3 } +> +``` + +The debugger displays the current Noir code location, and it is now waiting for us to drive it. + +Let's first take a look at the available commands. For that we'll use the `help` command. + +``` +> help +Available commands: + + opcodes display ACIR opcodes + into step into to the next opcode + next step until a new source location is reached + out step until a new source location is reached + and the current stack frame is finished + break LOCATION:OpcodeLocation add a breakpoint at an opcode location + over step until a new source location is reached + without diving into function calls + restart restart the debugging session + delete LOCATION:OpcodeLocation delete breakpoint at an opcode location + witness show witness map + witness index:u32 display a single witness from the witness map + witness index:u32 value:String update a witness with the given value + memset index:usize value:String update a memory cell with the given + value + continue continue execution until the end of the + program + vars show variable values available at this point + in execution + stacktrace display the current stack trace + memory show memory (valid when executing unconstrained code) + step step to the next ACIR opcode + +Other commands: + + help Show this help message + quit Quit repl + +``` + +Some commands operate only for unconstrained functions, such as `memory` and `memset`. If you try to use them while execution is paused at an ACIR opcode, the debugger will simply inform you that you are not executing unconstrained code: + +``` +> memory +Unconstrained VM memory not available +> +``` + +Before continuing, we can take a look at the initial witness map: + +``` +> witness +_0 = 1 +_1 = 2 +> +``` + +Cool, since `x==1`, `y==2`, and we want to check that `x != y`, our circuit should succeed. At this point we could intervene and use the witness setter command to change one of the witnesses. Let's set `y=3`, then back to 2, so we don't affect the expected result: + +``` +> witness +_0 = 1 +_1 = 2 +> witness 1 3 +_1 = 3 +> witness +_0 = 1 +_1 = 3 +> witness 1 2 +_1 = 2 +> witness +_0 = 1 +_1 = 2 +> +``` + +Now we can inspect the current state of local variables. For that we use the `vars` command. + +``` +> vars +> +``` + +We currently have no vars in context, since we are at the entry point of the program. Let's use `next` to execute until the next point in the program. + +``` +> vars +> next +At ~/noir-examples/recursion/circuits/main/src/main.nr:1:20 + 1 -> fn main(x : Field, y : pub Field) { + 2 assert(x != y); + 3 } +> vars +x:Field = 0x01 +``` + +As a result of stepping, the variable `x`, whose initial value comes from the witness map, is now in context and returned by `vars`. + +``` +> next + 1 fn main(x : Field, y : pub Field) { + 2 -> assert(x != y); + 3 } +> vars +y:Field = 0x02 +x:Field = 0x01 +``` + +Stepping again we can finally see both variables and their values. And now we can see that the next assertion should succeed. + +Let's continue to the end: + +``` +> continue +(Continuing execution...) +Finished execution +> q +[main] Circuit witness successfully solved +``` + +Upon quitting the debugger after a solved circuit, the resulting circuit witness gets saved, equivalent to what would happen if we had run the same circuit with `nargo execute`. + +We just went through the basics of debugging using Noir REPL debugger. For a comprehensive reference, check out [the reference page](../../reference/debugger/debugger_repl.md). diff --git a/docs/versioned_docs/version-v0.29.0/how_to/debugger/debugging_with_vs_code.md b/docs/versioned_docs/version-v0.29.0/how_to/debugger/debugging_with_vs_code.md new file mode 100644 index 00000000000..a5858c1a5eb --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/debugger/debugging_with_vs_code.md @@ -0,0 +1,68 @@ +--- +title: Using the VS Code Debugger +description: + Step by step guide on how to debug your Noir circuits with the VS Code Debugger configuration and features. +keywords: + [ + Nargo, + Noir CLI, + Noir Debugger, + VS Code, + IDE, + ] +sidebar_position: 0 +--- + +This guide will show you how to use VS Code with the vscode-noir extension to debug a Noir project. + +#### Pre-requisites + +- Nargo +- vscode-noir +- A Noir project with a `Nargo.toml`, `Prover.toml` and at least one Noir (`.nr`) containing an entry point function (typically `main`). + +## Running the debugger + +The easiest way to start debugging is to open the file you want to debug, and press `F5`. This will cause the debugger to launch, using your `Prover.toml` file as input. + +You should see something like this: + +![Debugger launched](@site/static/img/debugger/1-started.png) + +Let's inspect the state of the program. For that, we open VS Code's _Debug pane_. Look for this icon: + +![Debug pane icon](@site/static/img/debugger/2-icon.png) + +You will now see two categories of variables: Locals and Witness Map. + +![Debug pane expanded](@site/static/img/debugger/3-debug-pane.png) + +1. **Locals**: variables of your program. At this point in execution this section is empty, but as we step through the code it will get populated by `x`, `result`, `digest`, etc. + +2. **Witness map**: these are initially populated from your project's `Prover.toml` file. In this example, they will be used to populate `x` and `result` at the beginning of the `main` function. + +Most of the time you will probably be focusing mostly on locals, as they represent the high level state of your program. + +You might be interested in inspecting the witness map in case you are trying to solve a really low level issue in the compiler or runtime itself, so this concerns mostly advanced or niche users. + +Let's step through the program, by using the debugger buttons or their corresponding keyboard shortcuts. + +![Debugger buttons](@site/static/img/debugger/4-debugger-buttons.png) + +Now we can see in the variables pane that there's values for `digest`, `result` and `x`. + +![Inspecting locals](@site/static/img/debugger/5-assert.png) + +We can also inspect the values of variables by directly hovering on them on the code. + +![Hover locals](@site/static/img/debugger/6-hover.png) + +Let's set a break point at the `keccak256` function, so we can continue execution up to the point when it's first invoked without having to go one step at a time. + +We just need to click the to the right of the line number 18. Once the breakpoint appears, we can click the `continue` button or use its corresponding keyboard shortcut (`F5` by default). + +![Breakpoint](@site/static/img/debugger/7-break.png) + +Now we are debugging the `keccak256` function, notice the _Call Stack pane_ at the lower right. This lets us inspect the current call stack of our process. + +That covers most of the current debugger functionalities. Check out [the reference](../../reference/debugger/debugger_vscode.md) for more details on how to configure the debugger. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/how_to/how-to-oracles.md b/docs/versioned_docs/version-v0.29.0/how_to/how-to-oracles.md new file mode 100644 index 00000000000..8cf8035a5c4 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/how-to-oracles.md @@ -0,0 +1,276 @@ +--- +title: How to use Oracles +description: Learn how to use oracles in your Noir program with examples in both Nargo and NoirJS. This guide also covers writing a JSON RPC server and providing custom foreign call handlers for NoirJS. +keywords: + - Noir Programming + - Oracles + - Nargo + - NoirJS + - JSON RPC Server + - Foreign Call Handlers +sidebar_position: 1 +--- + +This guide shows you how to use oracles in your Noir program. For the sake of clarity, it assumes that: + +- You have read the [explainer on Oracles](../explainers/explainer-oracle.md) and are comfortable with the concept. +- You have a Noir program to add oracles to. You can create one using the [vite-hardhat starter](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) as a boilerplate. +- You understand the concept of a JSON-RPC server. Visit the [JSON-RPC website](https://www.jsonrpc.org/) if you need a refresher. +- You are comfortable with server-side JavaScript (e.g. Node.js, managing packages, etc.). + +For reference, you can find the snippets used in this tutorial on the [Aztec DevRel Repository](https://github.com/AztecProtocol/dev-rel/tree/main/code-snippets/how-to-oracles). + +## Rundown + +This guide has 3 major steps: + +1. How to modify our Noir program to make use of oracle calls as unconstrained functions +2. How to write a JSON RPC Server to resolve these oracle calls with Nargo +3. How to use them in Nargo and how to provide a custom resolver in NoirJS + +## Step 1 - Modify your Noir program + +An oracle is defined in a Noir program by defining two methods: + +- An unconstrained method - This tells the compiler that it is executing an [unconstrained functions](../noir/concepts//unconstrained.md). +- A decorated oracle method - This tells the compiler that this method is an RPC call. + +An example of an oracle that returns a `Field` would be: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt(number: Field) -> Field { } + +unconstrained fn get_sqrt(number: Field) -> Field { + sqrt(number) +} +``` + +In this example, we're wrapping our oracle function in a unconstrained method, and decorating it with `oracle(getSqrt)`. We can then call the unconstrained function as we would call any other function: + +```rust +fn main(input: Field) { + let sqrt = get_sqrt(input); +} +``` + +In the next section, we will make this `getSqrt` (defined on the `sqrt` decorator) be a method of the RPC server Noir will use. + +:::danger + +As explained in the [Oracle Explainer](../explainers/explainer-oracle.md), this `main` function is unsafe unless you constrain its return value. For example: + +```rust +fn main(input: Field) { + let sqrt = get_sqrt(input); + assert(sqrt.pow_32(2) as u64 == input as u64); // <---- constrain the return of an oracle! +} +``` + +::: + +:::info + +Currently, oracles only work with single params or array params. For example: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt([Field; 2]) -> [Field; 2] { } +``` + +::: + +## Step 2 - Write an RPC server + +Brillig will call *one* RPC server. Most likely you will have to write your own, and you can do it in whatever language you prefer. In this guide, we will do it in Javascript. + +Let's use the above example of an oracle that consumes an array with two `Field` and returns their square roots: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt(input: [Field; 2]) -> [Field; 2] { } + +unconstrained fn get_sqrt(input: [Field; 2]) -> [Field; 2] { + sqrt(input) +} + +fn main(input: [Field; 2]) { + let sqrt = get_sqrt(input); + assert(sqrt[0].pow_32(2) as u64 == input[0] as u64); + assert(sqrt[1].pow_32(2) as u64 == input[1] as u64); +} +``` + +:::info + +Why square root? + +In general, computing square roots is computationally more expensive than multiplications, which takes a toll when speaking about ZK applications. In this case, instead of calculating the square root in Noir, we are using our oracle to offload that computation to be made in plain. In our circuit we can simply multiply the two values. + +::: + +Now, we should write the correspondent RPC server, starting with the [default JSON-RPC 2.0 boilerplate](https://www.npmjs.com/package/json-rpc-2.0#example): + +```js +import { JSONRPCServer } from "json-rpc-2.0"; +import express from "express"; +import bodyParser from "body-parser"; + +const app = express(); +app.use(bodyParser.json()); + +const server = new JSONRPCServer(); +app.post("/", (req, res) => { + const jsonRPCRequest = req.body; + server.receive(jsonRPCRequest).then((jsonRPCResponse) => { + if (jsonRPCResponse) { + res.json(jsonRPCResponse); + } else { + res.sendStatus(204); + } + }); +}); + +app.listen(5555); +``` + +Now, we will add our `getSqrt` method, as expected by the `#[oracle(getSqrt)]` decorator in our Noir code. It maps through the params array and returns their square roots: + +```js +server.addMethod("getSqrt", async (params) => { + const values = params[0].Array.map((field) => { + return `${Math.sqrt(parseInt(field, 16))}`; + }); + return { values: [{ Array: values }] }; +}); +``` + +:::tip + +Brillig expects an object with an array of values. Each value is an object declaring to be `Single` or `Array` and returning a field element *as a string*. For example: + +```json +{ "values": [{ "Array": ["1", "2"] }]} +{ "values": [{ "Single": "1" }]} +{ "values": [{ "Single": "1" }, { "Array": ["1", "2"] }]} +``` + +If you're using Typescript, the following types may be helpful in understanding the expected return value and making sure they're easy to follow: + +```js +interface SingleForeignCallParam { + Single: string, +} + +interface ArrayForeignCallParam { + Array: string[], +} + +type ForeignCallParam = SingleForeignCallParam | ArrayForeignCallParam; + +interface ForeignCallResult { + values: ForeignCallParam[], +} +``` + +::: + +## Step 3 - Usage with Nargo + +Using the [`nargo` CLI tool](../getting_started/installation/index.md), you can use oracles in the `nargo test`, `nargo execute` and `nargo prove` commands by passing a value to `--oracle-resolver`. For example: + +```bash +nargo test --oracle-resolver http://localhost:5555 +``` + +This tells `nargo` to use your RPC Server URL whenever it finds an oracle decorator. + +## Step 4 - Usage with NoirJS + +In a JS environment, an RPC server is not strictly necessary, as you may want to resolve your oracles without needing any JSON call at all. NoirJS simply expects that you pass a callback function when you generate proofs, and that callback function can be anything. + +For example, if your Noir program expects the host machine to provide CPU pseudo-randomness, you could simply pass it as the `foreignCallHandler`. You don't strictly need to create an RPC server to serve pseudo-randomness, as you may as well get it directly in your app: + +```js +const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc + +await noir.generateProof(inputs, foreignCallHandler) +``` + +As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. + +:::tip + +Does this mean you don't have to write an RPC server like in [Step #2](#step-2---write-an-rpc-server)? + +You don't technically have to, but then how would you run `nargo test` or `nargo prove`? To use both `Nargo` and `NoirJS` in your development flow, you will have to write a JSON RPC server. + +::: + +In this case, let's make `foreignCallHandler` call the JSON RPC Server we created in [Step #2](#step-2---write-an-rpc-server), by making it a JSON RPC Client. + +For example, using the same `getSqrt` program in [Step #1](#step-1---modify-your-noir-program) (comments in the code): + +```js +import { JSONRPCClient } from "json-rpc-2.0"; + +// declaring the JSONRPCClient +const client = new JSONRPCClient((jsonRPCRequest) => { +// hitting the same JSON RPC Server we coded above + return fetch("http://localhost:5555", { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify(jsonRPCRequest), + }).then((response) => { + if (response.status === 200) { + return response + .json() + .then((jsonRPCResponse) => client.receive(jsonRPCResponse)); + } else if (jsonRPCRequest.id !== undefined) { + return Promise.reject(new Error(response.statusText)); + } + }); +}); + +// declaring a function that takes the name of the foreign call (getSqrt) and the inputs +const foreignCallHandler = async (name, input) => { + // notice that the "inputs" parameter contains *all* the inputs + // in this case we to make the RPC request with the first parameter "numbers", which would be input[0] + const oracleReturn = await client.request(name, [ + { Array: input[0].map((i) => i.toString("hex")) }, + ]); + return [oracleReturn.values[0].Array]; +}; + +// the rest of your NoirJS code +const input = { input: [4, 16] }; +const { witness } = await noir.execute(numbers, foreignCallHandler); +``` + +:::tip + +If you're in a NoirJS environment running your RPC server together with a frontend app, you'll probably hit a familiar problem in full-stack development: requests being blocked by [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) policy. For development only, you can simply install and use the [`cors` npm package](https://www.npmjs.com/package/cors) to get around the problem: + +```bash +yarn add cors +``` + +and use it as a middleware: + +```js +import cors from "cors"; + +const app = express(); +app.use(cors()) +``` + +::: + +## Conclusion + +Hopefully by the end of this guide, you should be able to: + +- Write your own logic around Oracles and how to write a JSON RPC server to make them work with your Nargo commands. +- Provide custom foreign call handlers for NoirJS. diff --git a/docs/versioned_docs/version-v0.29.0/how_to/how-to-recursion.md b/docs/versioned_docs/version-v0.29.0/how_to/how-to-recursion.md new file mode 100644 index 00000000000..4c45bb87ae2 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/how-to-recursion.md @@ -0,0 +1,179 @@ +--- +title: How to use recursion on NoirJS +description: Learn how to implement recursion with NoirJS, a powerful tool for creating smart contracts on the EVM blockchain. This guide assumes familiarity with NoirJS, solidity verifiers, and the Barretenberg proving backend. Discover how to generate both final and intermediate proofs using `noir_js` and `backend_barretenberg`. +keywords: + [ + "NoirJS", + "EVM blockchain", + "smart contracts", + "recursion", + "solidity verifiers", + "Barretenberg backend", + "noir_js", + "backend_barretenberg", + "intermediate proofs", + "final proofs", + "nargo compile", + "json import", + "recursive circuit", + "recursive app" + ] +sidebar_position: 1 +--- + +This guide shows you how to use recursive proofs in your NoirJS app. For the sake of clarity, it is assumed that: + +- You already have a NoirJS app. If you don't, please visit the [NoirJS tutorial](../tutorials/noirjs_app.md) and the [reference](../reference/NoirJS/noir_js/index.md). +- You are familiar with what are recursive proofs and you have read the [recursion explainer](../explainers/explainer-recursion.md) +- You already built a recursive circuit following [the reference](../noir/standard_library/recursion.md), and understand how it works. + +It is also assumed that you're not using `noir_wasm` for compilation, and instead you've used [`nargo compile`](../reference/nargo_commands.md) to generate the `json` you're now importing into your project. However, the guide should work just the same if you're using `noir_wasm`. + +:::info + +As you've read in the [explainer](../explainers/explainer-recursion.md), a recursive proof is an intermediate proof. This means that it doesn't necessarily generate the final step that makes it verifiable in a smart contract. However, it is easy to verify within another circuit. + +While "standard" usage of NoirJS packages abstracts final proofs, it currently lacks the necessary interface to abstract away intermediate proofs. This means that these proofs need to be created by using the backend directly. + +In short: + +- `noir_js` generates *only* final proofs +- `backend_barretenberg` generates both types of proofs + +::: + +In a standard recursive app, you're also dealing with at least two circuits. For the purpose of this guide, we will assume the following: + +- `main`: a circuit of type `assert(x != y)`, where `main` is marked with a `#[recursive]` attribute. This attribute states that the backend should generate proofs that are friendly for verification within another circuit. +- `recursive`: a circuit that verifies `main` + +For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir-lang/noir-examples) repository. We will *not* be using it as a reference for this guide. + +## Step 1: Setup + +In a common NoirJS app, you need to instantiate a backend with something like `const backend = new Backend(circuit)`. Then you feed it to the `noir_js` interface. + +For recursion, this doesn't happen, and the only need for `noir_js` is only to `execute` a circuit and get its witness and return value. Everything else is not interfaced, so it needs to happen on the `backend` object. + +It is also recommended that you instantiate the backend with as many threads as possible, to allow for maximum concurrency: + +```js +const backend = new Backend(circuit, { threads: 8 }) +``` + +:::tip +You can use the [`os.cpus()`](https://nodejs.org/api/os.html#oscpus) object in `nodejs` or [`navigator.hardwareConcurrency`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/hardwareConcurrency) on the browser to make the most out of those glorious cpu cores +::: + +## Step 2: Generating the witness and the proof for `main` + +After instantiating the backend, you should also instantiate `noir_js`. We will use it to execute the circuit and get the witness. + +```js +const noir = new Noir(circuit, backend) +const { witness } = noir.execute(input) +``` + +With this witness, you are now able to generate the intermediate proof for the main circuit: + +```js +const { proof, publicInputs } = await backend.generateProof(witness) +``` + +:::warning + +Always keep in mind what is actually happening on your development process, otherwise you'll quickly become confused about what circuit we are actually running and why! + +In this case, you can imagine that Alice (running the `main` circuit) is proving something to Bob (running the `recursive` circuit), and Bob is verifying her proof within his proof. + +With this in mind, it becomes clear that our intermediate proof is the one *meant to be verified within another circuit*, so it must be Alice's. Actually, the only final proof in this theoretical scenario would be the last one, sent on-chain. + +::: + +## Step 3 - Verification and proof artifacts + +Optionally, you are able to verify the intermediate proof: + +```js +const verified = await backend.verifyProof({ proof, publicInputs }) +``` + +This can be useful to make sure our intermediate proof was correctly generated. But the real goal is to do it within another circuit. For that, we need to generate recursive proof artifacts that will be passed to the circuit that is verifying the proof we just generated. Instead of passing the proof and verification key as a byte array, we pass them as fields which makes it cheaper to verify in a circuit: + +```js +const { proofAsFields, vkAsFields, vkHash } = await backend.generateRecursiveProofArtifacts( { publicInputs, proof }, publicInputsCount) +``` + +This call takes the public inputs and the proof, but also the public inputs count. While this is easily retrievable by simply counting the `publicInputs` length, the backend interface doesn't currently abstract it away. + +:::info + +The `proofAsFields` has a constant size `[Field; 93]` and verification keys in Barretenberg are always `[Field; 114]`. + +::: + +:::warning + +One common mistake is to forget *who* makes this call. + +In a situation where Alice is generating the `main` proof, if she generates the proof artifacts and sends them to Bob, which gladly takes them as true, this would mean Alice could prove anything! + +Instead, Bob needs to make sure *he* extracts the proof artifacts, using his own instance of the `main` circuit backend. This way, Alice has to provide a valid proof for the correct `main` circuit. + +::: + +## Step 4 - Recursive proof generation + +With the artifacts, generating a recursive proof is no different from a normal proof. You simply use the `backend` (with the recursive circuit) to generate it: + +```js +const recursiveInputs = { + verification_key: vkAsFields, // array of length 114 + proof: proofAsFields, // array of length 93 + size of public inputs + publicInputs: [mainInput.y], // using the example above, where `y` is the only public input + key_hash: vkHash, +} + +const { witness, returnValue } = noir.execute(recursiveInputs) // we're executing the recursive circuit now! +const { proof, publicInputs } = backend.generateProof(witness) +const verified = backend.verifyProof({ proof, publicInputs }) +``` + +You can obviously chain this proof into another proof. In fact, if you're using recursive proofs, you're probably interested of using them this way! + +:::tip + +Managing circuits and "who does what" can be confusing. To make sure your naming is consistent, you can keep them in an object. For example: + +```js +const circuits = { + main: mainJSON, + recursive: recursiveJSON +} +const backends = { + main: new BarretenbergBackend(circuits.main), + recursive: new BarretenbergBackend(circuits.recursive) +} +const noir_programs = { + main: new Noir(circuits.main, backends.main), + recursive: new Noir(circuits.recursive, backends.recursive) +} +``` + +This allows you to neatly call exactly the method you want without conflicting names: + +```js +// Alice runs this 👇 +const { witness: mainWitness } = await noir_programs.main.execute(input) +const proof = await backends.main.generateProof(mainWitness) + +// Bob runs this 👇 +const verified = await backends.main.verifyProof(proof) +const { proofAsFields, vkAsFields, vkHash } = await backends.main.generateRecursiveProofArtifacts( + proof, + numPublicInputs, +); +const recursiveProof = await noir_programs.recursive.generateProof(recursiveInputs) +``` + +::: diff --git a/docs/versioned_docs/version-v0.29.0/how_to/how-to-solidity-verifier.md b/docs/versioned_docs/version-v0.29.0/how_to/how-to-solidity-verifier.md new file mode 100644 index 00000000000..e3c7c1065da --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/how-to-solidity-verifier.md @@ -0,0 +1,231 @@ +--- +title: Generate a Solidity Verifier +description: + Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier + contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart + contract. Read more to find out +keywords: + [ + solidity verifier, + smart contract, + blockchain, + compiler, + plonk_vk.sol, + EVM blockchain, + verifying Noir programs, + proving backend, + Barretenberg, + ] +sidebar_position: 0 +pagination_next: tutorials/noirjs_app +--- + +Noir has the ability to generate a verifier contract in Solidity, which can be deployed in many EVM-compatible blockchains such as Ethereum. + +This allows for a powerful feature set, as one can make use of the conciseness and the privacy provided by Noir in an immutable ledger. Applications can range from simple P2P guessing games, to complex private DeFi interactions. + +This guide shows you how to generate a Solidity Verifier and deploy it on the [Remix IDE](https://remix.ethereum.org/). It is assumed that: + +- You are comfortable with the Solidity programming language and understand how contracts are deployed on the Ethereum network +- You have Noir installed and you have a Noir program. If you don't, [get started](../getting_started/installation/index.md) with Nargo and the example Hello Noir circuit +- You are comfortable navigating RemixIDE. If you aren't or you need a refresher, you can find some video tutorials [here](https://www.youtube.com/channel/UCjTUPyFEr2xDGN6Cg8nKDaA) that could help you. + +## Rundown + +Generating a Solidity Verifier contract is actually a one-command process. However, compiling it and deploying it can have some caveats. Here's the rundown of this guide: + +1. How to generate a solidity smart contract +2. How to compile the smart contract in the RemixIDE +3. How to deploy it to a testnet + +## Step 1 - Generate a contract + +This is by far the most straight-forward step. Just run: + +```sh +nargo codegen-verifier +``` + +A new `contract` folder would then be generated in your project directory, containing the Solidity +file `plonk_vk.sol`. It can be deployed to any EVM blockchain acting as a verifier smart contract. + +:::info + +It is possible to generate verifier contracts of Noir programs for other smart contract platforms as long as the proving backend supplies an implementation. + +Barretenberg, the default proving backend for Nargo, supports generation of verifier contracts, for the time being these are only in Solidity. +::: + +## Step 2 - Compiling + +We will mostly skip the details of RemixIDE, as the UI can change from version to version. For now, we can just open +Remix and create a blank workspace. + +![Create Workspace](@site/static/img/how-tos/solidity_verifier_1.png) + +We will create a new file to contain the contract Nargo generated, and copy-paste its content. + +:::warning + +You'll likely see a warning advising you to not trust pasted code. While it is an important warning, it is irrelevant in the context of this guide and can be ignored. We will not be deploying anywhere near a mainnet. + +::: + +To compile our the verifier, we can navigate to the compilation tab: + +![Compilation Tab](@site/static/img/how-tos/solidity_verifier_2.png) + +Remix should automatically match a suitable compiler version. However, hitting the "Compile" button will most likely generate a "Stack too deep" error: + +![Stack too deep](@site/static/img/how-tos/solidity_verifier_3.png) + +This is due to the verify function needing to put many variables on the stack, but enabling the optimizer resolves the issue. To do this, let's open the "Advanced Configurations" tab and enable optimization. The default 200 runs will suffice. + +:::info + +This time we will see a warning about an unused function parameter. This is expected, as the `verify` function doesn't use the `_proof` parameter inside a solidity block, it is loaded from calldata and used in assembly. + +::: + +![Compilation success](@site/static/img/how-tos/solidity_verifier_4.png) + +## Step 3 - Deploying + +At this point we should have a compiled contract read to deploy. If we navigate to the deploy section in Remix, we will see many different environments we can deploy to. The steps to deploy on each environment would be out-of-scope for this guide, so we will just use the default Remix VM. + +Looking closely, we will notice that our "Solidity Verifier" is actually three contracts working together: + +- An `UltraVerificationKey` library which simply stores the verification key for our circuit. +- An abstract contract `BaseUltraVerifier` containing most of the verifying logic. +- A main `UltraVerifier` contract that inherits from the Base and uses the Key contract. + +Remix will take care of the dependencies for us so we can simply deploy the UltraVerifier contract by selecting it and hitting "deploy": + +![Deploying UltraVerifier](@site/static/img/how-tos/solidity_verifier_5.png) + +A contract will show up in the "Deployed Contracts" section, where we can retrieve the Verification Key Hash. This is particularly useful for double-checking the deployer contract is the correct one. + +:::note + +Why "UltraVerifier"? + +To be precise, the Noir compiler (`nargo`) doesn't generate the verifier contract directly. It compiles the Noir code into an intermediate language (ACIR), which is then executed by the backend. So it is the backend that returns the verifier smart contract, not Noir. + +In this case, the Barretenberg Backend uses the UltraPlonk proving system, hence the "UltraVerifier" name. + +::: + +## Step 4 - Verifying + +To verify a proof using the Solidity verifier contract, we call the `verify` function in this extended contract: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +When using the default example in the [Hello Noir](../getting_started/hello_noir/index.md) guide, the easiest way to confirm that the verifier contract is doing its job is by calling the `verify` function via remix with the required parameters. For `_proof`, run `nargo prove` and use the string in `proof/.proof` (adding the hex `0x` prefix). We can also copy the public input from `Verifier.toml`, as it will be properly formatted as 32-byte strings: + +``` +0x...... , [0x0000.....02] +``` + +A programmatic example of how the `verify` function is called can be seen in the example zk voting application [here](https://github.com/noir-lang/noir-examples/blob/33e598c257e2402ea3a6b68dd4c5ad492bce1b0a/foundry-voting/src/zkVote.sol#L35): + +```solidity +function castVote(bytes calldata proof, uint proposalId, uint vote, bytes32 nullifierHash) public returns (bool) { + // ... + bytes32[] memory publicInputs = new bytes32[](4); + publicInputs[0] = merkleRoot; + publicInputs[1] = bytes32(proposalId); + publicInputs[2] = bytes32(vote); + publicInputs[3] = nullifierHash; + require(verifier.verify(proof, publicInputs), "Invalid proof"); +``` + +:::info[Return Values] + +A circuit doesn't have the concept of a return value. Return values are just syntactic sugar in +Noir. + +Under the hood, the return value is passed as an input to the circuit and is checked at the end of +the circuit program. + +For example, if you have Noir program like this: + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +the `verify` function will expect the public inputs array (second function parameter) to be of length 3, the two inputs and the return value. Like before, these values are populated in Verifier.toml after running `nargo prove`. + +Passing only two inputs will result in an error such as `PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case, the inputs parameter to `verify` would be an array ordered as `[pubkey_x, pubkey_y, return]`. + +::: + +:::tip[Structs] + +You can pass structs to the verifier contract. They will be flattened so that the array of inputs is 1-dimensional array. + +For example, consider the following program: + +```rust +struct Type1 { + val1: Field, + val2: Field, +} + +struct Nested { + t1: Type1, + is_true: bool, +} + +fn main(x: pub Field, nested: pub Nested, y: pub Field) { + //... +} +``` + +The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +::: + +The other function you can call is our entrypoint `verify` function, as defined above. + +:::tip + +It's worth noticing that the `verify` function is actually a `view` function. A `view` function does not alter the blockchain state, so it doesn't need to be distributed (i.e. it will run only on the executing node), and therefore doesn't cost any gas. + +This can be particularly useful in some situations. If Alice generated a proof and wants Bob to verify its correctness, Bob doesn't need to run Nargo, NoirJS, or any Noir specific infrastructure. He can simply make a call to the blockchain with the proof and verify it is correct without paying any gas. + +It would be incorrect to say that a Noir proof verification costs any gas at all. However, most of the time the result of `verify` is used to modify state (for example, to update a balance, a game state, etc). In that case the whole network needs to execute it, which does incur gas costs (calldata and execution, but not storage). + +::: + +## A Note on EVM chains + +ZK-SNARK verification depends on some precompiled cryptographic primitives such as Elliptic Curve Pairings (if you like complex math, you can read about EC Pairings [here](https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627)). Not all EVM chains support EC Pairings, notably some of the ZK-EVMs. This means that you won't be able to use the verifier contract in all of them. + +For example, chains like `zkSync ERA` and `Polygon zkEVM` do not currently support these precompiles, so proof verification via Solidity verifier contracts won't work. Here's a quick list of EVM chains that have been tested and are known to work: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. + +## What's next + +Now that you know how to call a Noir Solidity Verifier on a smart contract using Remix, you should be comfortable with using it with some programmatic frameworks, such as [hardhat](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) and [foundry](https://github.com/noir-lang/noir-starter/tree/main/with-foundry). + +You can find other tools, examples, boilerplates and libraries in the [awesome-noir](https://github.com/noir-lang/awesome-noir) repository. + +You should also be ready to write and deploy your first NoirJS app and start generating proofs on websites, phones, and NodeJS environments! Head on to the [NoirJS tutorial](../tutorials/noirjs_app.md) to learn how to do that. diff --git a/docs/versioned_docs/version-v0.29.0/how_to/merkle-proof.mdx b/docs/versioned_docs/version-v0.29.0/how_to/merkle-proof.mdx new file mode 100644 index 00000000000..16c425bed76 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/merkle-proof.mdx @@ -0,0 +1,49 @@ +--- +title: Prove Merkle Tree Membership +description: + Learn how to use merkle membership proof in Noir to prove that a given leaf is a member of a + merkle tree with a specified root, at a given index. +keywords: + [merkle proof, merkle membership proof, Noir, rust, hash function, Pedersen, sha256, merkle tree] +sidebar_position: 4 +--- + +Let's walk through an example of a merkle membership proof in Noir that proves that a given leaf is +in a merkle tree. + +```rust +use dep::std; + +fn main(message : [Field; 62], index : Field, hashpath : [Field; 40], root : Field) { + let leaf = std::hash::hash_to_field(message.as_slice()); + let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); + assert(merkle_root == root); +} + +``` + +The message is hashed using `hash_to_field`. The specific hash function that is being used is chosen +by the backend. The only requirement is that this hash function can heuristically be used as a +random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen_hash` +instead. + +```rust +let leaf = std::hash::hash_to_field(message.as_slice()); +``` + +The leaf is then passed to a compute_merkle_root function with the root, index and hashpath. The returned root can then be asserted to be the same as the provided root. + +```rust +let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); +assert (merkle_root == root); +``` + +> **Note:** It is possible to re-implement the merkle tree implementation without standard library. +> However, for most usecases, it is enough. In general, the standard library will always opt to be +> as conservative as possible, while striking a balance with efficiency. + +An example, the merkle membership proof, only requires a hash function that has collision +resistance, hence a hash function like Pedersen is allowed, which in most cases is more efficient +than the even more conservative sha256. + +[View an example on the starter repo](https://github.com/noir-lang/noir-examples/blob/3ea09545cabfa464124ec2f3ea8e60c608abe6df/stealthdrop/circuits/src/main.nr#L20) diff --git a/docs/versioned_docs/version-v0.29.0/how_to/using-devcontainers.mdx b/docs/versioned_docs/version-v0.29.0/how_to/using-devcontainers.mdx new file mode 100644 index 00000000000..727ec6ca667 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/how_to/using-devcontainers.mdx @@ -0,0 +1,110 @@ +--- +title: Developer Containers and Codespaces +description: "Learn how to set up a devcontainer in your GitHub repository for a seamless coding experience with Codespaces. Follow our easy 8-step guide to create your own Noir environment without installing Nargo locally." +keywords: ["Devcontainer", "Codespaces", "GitHub", "Noir Environment", "Docker Image", "Development Environment", "Remote Coding", "GitHub Codespaces", "Noir Programming", "Nargo", "VSCode Extensions", "Noirup"] +sidebar_position: 1 +--- + +Adding a developer container configuration file to your Noir project is one of the easiest way to unlock coding in browser. + +## What's a devcontainer after all? + +A [Developer Container](https://containers.dev/) (devcontainer for short) is a Docker image that comes preloaded with tools, extensions, and other tools you need to quickly get started or continue a project, without having to install Nargo locally. Think of it as a development environment in a box. + +There are many advantages to this: + +- It's platform and architecture agnostic +- You don't need to have an IDE installed, or Nargo, or use a terminal at all +- It's safer for using on a public machine or public network + +One of the best ways of using devcontainers is... not using your machine at all, for maximum control, performance, and ease of use. +Enter Codespaces. + +## Codespaces + +If a devcontainer is just a Docker image, then what stops you from provisioning a `p3dn.24xlarge` AWS EC2 instance with 92 vCPUs and 768 GiB RAM and using it to prove your 10-gate SNARK proof? + +Nothing! Except perhaps the 30-40$ per hour it will cost you. + +The problem is that provisioning takes time, and I bet you don't want to see the AWS console every time you want to code something real quick. + +Fortunately, there's an easy and free way to get a decent remote machine ready and loaded in less than 2 minutes: Codespaces. [Codespaces is a Github feature](https://github.com/features/codespaces) that allows you to code in a remote machine by using devcontainers, and it's pretty cool: + +- You can start coding Noir in less than a minute +- It uses the resources of a remote machine, so you can code on your grandma's phone if needed be +- It makes it easy to share work with your frens +- It's fully reusable, you can stop and restart whenever you need to + +:::info + +Don't take out your wallet just yet. Free GitHub accounts get about [15-60 hours of coding](https://github.com/features/codespaces) for free per month, depending on the size of your provisioned machine. + +::: + +## Tell me it's _actually_ easy + +It is! + +Github comes with a default codespace and you can use it to code your own devcontainer. That's exactly what we will be doing in this guide. + + + +8 simple steps: + +#### 1. Create a new repository on GitHub. + +#### 2. Click "Start coding with Codespaces". This will use the default image. + +#### 3. Create a folder called `.devcontainer` in the root of your repository. + +#### 4. Create a Dockerfile in that folder, and paste the following code: + +```docker +FROM --platform=linux/amd64 node:lts-bookworm-slim +SHELL ["/bin/bash", "-c"] +RUN apt update && apt install -y curl bash git tar gzip libc++-dev +RUN curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +ENV PATH="/root/.nargo/bin:$PATH" +RUN noirup +ENTRYPOINT ["nargo"] +``` +#### 5. Create a file called `devcontainer.json` in the same folder, and paste the following code: + +```json +{ + "name": "Noir on Codespaces", + "build": { + "context": ".", + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "extensions": ["noir-lang.vscode-noir"] + } + } +} +``` +#### 6. Commit and push your changes + +This will pull the new image and build it, so it could take a minute or so + +#### 8. Done! +Just wait for the build to finish, and there's your easy Noir environment. + + +Refer to [noir-starter](https://github.com/noir-lang/noir-starter/) as an example of how devcontainers can be used together with codespaces. + + + +## How do I use it? + +Using the codespace is obviously much easier than setting it up. +Just navigate to your repository and click "Code" -> "Open with Codespaces". It should take a few seconds to load, and you're ready to go. + +:::info + +If you really like the experience, you can add a badge to your readme, links to existing codespaces, and more. +Check out the [official docs](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/setting-up-your-repository/facilitating-quick-creation-and-resumption-of-codespaces) for more info. diff --git a/docs/versioned_docs/version-v0.29.0/index.mdx b/docs/versioned_docs/version-v0.29.0/index.mdx new file mode 100644 index 00000000000..75086ddcdde --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/index.mdx @@ -0,0 +1,67 @@ +--- +title: Noir Lang +hide_title: true +description: + Learn about the public alpha release of Noir, a domain specific language heavily influenced by Rust that compiles to + an intermediate language which can be compiled to an arithmetic circuit or a rank-1 constraint system. +keywords: + [Noir, + Domain Specific Language, + Rust, + Intermediate Language, + Arithmetic Circuit, + Rank-1 Constraint System, + Ethereum Developers, + Protocol Developers, + Blockchain Developers, + Proving System, + Smart Contract Language] +sidebar_position: 0 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Noir Logo + +Noir is a Domain-Specific Language for SNARK proving systems developed by [Aztec Labs](https://aztec.network/). It allows you to generate complex Zero-Knowledge Programs (ZKP) by using simple and flexible syntax, requiring no previous knowledge on the underlying mathematics or cryptography. + +ZK programs are programs that can generate short proofs of a certain statement without revealing some details about it. You can read more about ZKPs [here](https://dev.to/spalladino/a-beginners-intro-to-coding-zero-knowledge-proofs-c56). + +## What's new about Noir? + +Noir works differently from most ZK languages by taking a two-pronged path. First, it compiles the program to an adaptable intermediate language known as ACIR. From there, depending on a given project's needs, ACIR can be further compiled into an arithmetic circuit for integration with the proving backend. + +:::info + +Noir is backend agnostic, which means it makes no assumptions on which proving backend powers the ZK proof. Being the language that powers [Aztec Contracts](https://docs.aztec.network/developers/contracts/main), it defaults to Aztec's Barretenberg proving backend. + +However, the ACIR output can be transformed to be compatible with other PLONK-based backends, or into a [rank-1 constraint system](https://www.rareskills.io/post/rank-1-constraint-system) suitable for backends such as Arkwork's Marlin. + +::: + +## Who is Noir for? + +Noir can be used both in complex cloud-based backends and in user's smartphones, requiring no knowledge on the underlying math or cryptography. From authorization systems that keep a password in the user's device, to complex on-chain verification of recursive proofs, Noir is designed to abstract away complexity without any significant overhead. Here are some examples of situations where Noir can be used: + + + + Noir Logo + + Aztec Contracts leverage Noir to allow for the storage and execution of private information. Writing an Aztec Contract is as easy as writing Noir, and Aztec developers can easily interact with the network storage and execution through the [Aztec.nr](https://docs.aztec.network/developers/contracts/main) library. + + + Soliditry Verifier Example + Noir can auto-generate Solidity verifier contracts that verify Noir proofs. This allows for non-interactive verification of proofs containing private information in an immutable system. This feature powers a multitude of use-case scenarios, from P2P chess tournaments, to [Aztec Layer-2 Blockchain](https://docs.aztec.network/) + + + Aztec Labs developed NoirJS, an easy interface to generate and verify Noir proofs in a Javascript environment. This allows for Noir to be used in webpages, mobile apps, games, and any other environment supporting JS execution in a standalone manner. + + + + +## Libraries + +Noir is meant to be easy to extend by simply importing Noir libraries just like in Rust. +The [awesome-noir repo](https://github.com/noir-lang/awesome-noir#libraries) is a collection of libraries developed by the Noir community. +Writing a new library is easy and makes code be composable and easy to reuse. See the section on [dependencies](noir/modules_packages_crates/dependencies.md) for more information. diff --git a/docs/versioned_docs/version-v0.29.0/migration_notes.md b/docs/versioned_docs/version-v0.29.0/migration_notes.md new file mode 100644 index 00000000000..6bd740024e5 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/migration_notes.md @@ -0,0 +1,105 @@ +--- +title: Migration notes +description: Read about migration notes from previous versions, which could solve problems while updating +keywords: [Noir, notes, migration, updating, upgrading] +--- + +Noir is in full-speed development. Things break fast, wild, and often. This page attempts to leave some notes on errors you might encounter when upgrading and how to resolve them until proper patches are built. + +### `backend encountered an error: libc++.so.1` + +Depending on your OS, you may encounter the following error when running `nargo prove` for the first time: + +```text +The backend encountered an error: "/home/codespace/.nargo/backends/acvm-backend-barretenberg/backend_binary: error while loading shared libraries: libc++.so.1: cannot open shared object file: No such file or directory\n" +``` + +Install the `libc++-dev` library with: + +```bash +sudo apt install libc++-dev +``` + +## ≥0.19 + +### Enforcing `compiler_version` + +From this version on, the compiler will check for the `compiler_version` field in `Nargo.toml`, and will error if it doesn't match the current Nargo version in use. + +To update, please make sure this field in `Nargo.toml` matches the output of `nargo --version`. + +## ≥0.14 + +The index of the [for loops](noir/concepts/control_flow.md#loops) is now of type `u64` instead of `Field`. An example refactor would be: + +```rust +for i in 0..10 { + let i = i as Field; +} +``` + +## ≥v0.11.0 and Nargo backend + +From this version onwards, Nargo starts managing backends through the `nargo backend` command. Upgrading to the versions per usual steps might lead to: + +### `backend encountered an error` + +This is likely due to the existing locally installed version of proving backend (e.g. barretenberg) is incompatible with the version of Nargo in use. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo prove +``` + +with your Noir program. + +This will trigger the download and installation of the latest version of barretenberg compatible with your Nargo in use. + +### `backend encountered an error: illegal instruction` + +On certain Intel-based systems, an `illegal instruction` error may arise due to incompatibility of barretenberg with certain CPU instructions. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/barretenberg-js-binary/raw/master/run-bb.tar.gz +``` + +This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. + +The gzipped file is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. + +Then run: + +``` +DESIRED_BINARY_VERSION=0.8.1 nargo info +``` + +This overrides the bb native binary with a bb.js node application instead, which should be compatible with most if not all hardware. This does come with the drawback of being generally slower than native binary. + +0.8.1 indicates bb.js version 0.8.1, so if you change that it will update to a different version or the default version in the script if none was supplied. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/_category_.json b/docs/versioned_docs/version-v0.29.0/noir/concepts/_category_.json new file mode 100644 index 00000000000..7da08f8a8c5 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Concepts", + "position": 0, + "collapsible": true, + "collapsed": true +} \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/assert.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/assert.md new file mode 100644 index 00000000000..bcff613a695 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/assert.md @@ -0,0 +1,45 @@ +--- +title: Assert Function +description: + Learn about the assert function in Noir, which can be used to explicitly constrain the predicate or + comparison expression that follows to be true, and what happens if the expression is false at + runtime. +keywords: [Noir programming language, assert statement, predicate expression, comparison expression] +sidebar_position: 4 +--- + +Noir includes a special `assert` function which will explicitly constrain the predicate/comparison +expression that follows to be true. If this expression is false at runtime, the program will fail to +be proven. Example: + +```rust +fn main(x : Field, y : Field) { + assert(x == y); +} +``` + +> Assertions only work for predicate operations, such as `==`. If there's any ambiguity on the operation, the program will fail to compile. For example, it is unclear if `assert(x + y)` would check for `x + y == 0` or simply would return `true`. + +You can optionally provide a message to be logged when the assertion fails: + +```rust +assert(x == y, "x and y are not equal"); +``` + +Aside string literals, the optional message can be a format string or any other type supported as input for Noir's [print](../standard_library/logging.md) functions. This feature lets you incorporate runtime variables into your failed assertion logs: + +```rust +assert(x == y, f"Expected x == y, but got {x} == {y}"); +``` + +Using a variable as an assertion message directly: + +```rust +struct myStruct { + myField: Field +} + +let s = myStruct { myField: y }; +assert(s.myField == x, s); +``` + diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/comments.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/comments.md new file mode 100644 index 00000000000..b51a85f5c94 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/comments.md @@ -0,0 +1,33 @@ +--- +title: Comments +description: + Learn how to write comments in Noir programming language. A comment is a line of code that is + ignored by the compiler, but it can be read by programmers. Single-line and multi-line comments + are supported in Noir. +keywords: [Noir programming language, comments, single-line comments, multi-line comments] +sidebar_position: 10 +--- + +A comment is a line in your codebase which the compiler ignores, however it can be read by +programmers. + +Here is a single line comment: + +```rust +// This is a comment and is ignored +``` + +`//` is used to tell the compiler to ignore the rest of the line. + +Noir also supports multi-line block comments. Start a block comment with `/*` and end the block with `*/`. + +Noir does not natively support doc comments. You may be able to use [Rust doc comments](https://doc.rust-lang.org/reference/comments.html) in your code to leverage some Rust documentation build tools with Noir code. + +```rust +/* + This is a block comment describing a complex function. +*/ +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/control_flow.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/control_flow.md new file mode 100644 index 00000000000..045d3c3a5f5 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/control_flow.md @@ -0,0 +1,77 @@ +--- +title: Control Flow +description: + Learn how to use loops and if expressions in the Noir programming language. Discover the syntax + and examples for for loops and if-else statements. +keywords: [Noir programming language, loops, for loop, if-else statements, Rust syntax] +sidebar_position: 2 +--- + +## If Expressions + +Noir supports `if-else` statements. The syntax is most similar to Rust's where it is not required +for the statement's conditional to be surrounded by parentheses. + +```rust +let a = 0; +let mut x: u32 = 0; + +if a == 0 { + if a != 0 { + x = 6; + } else { + x = 2; + } +} else { + x = 5; + assert(x == 5); +} +assert(x == 2); +``` + +## Loops + +Noir has one kind of loop: the `for` loop. `for` loops allow you to repeat a block of code multiple +times. + +The following block of code between the braces is run 10 times. + +```rust +for i in 0..10 { + // do something +} +``` + +The index for loops is of type `u64`. + +### Break and Continue + +In unconstrained code, `break` and `continue` are also allowed in `for` loops. These are only allowed +in unconstrained code since normal constrained code requires that Noir knows exactly how many iterations +a loop may have. `break` and `continue` can be used like so: + +```rust +for i in 0 .. 10 { + println("Iteration start") + + if i == 2 { + continue; + } + + if i == 5 { + break; + } + + println(i); +} +println("Loop end") +``` + +When used, `break` will end the current loop early and jump to the statement after the for loop. In the example +above, the `break` will stop the loop and jump to the `println("Loop end")`. + +`continue` will stop the current iteration of the loop, and jump to the start of the next iteration. In the example +above, `continue` will jump to `println("Iteration start")` when used. Note that the loop continues as normal after this. +The iteration variable `i` is still increased by one as normal when `continue` is used. + +`break` and `continue` cannot currently be used to jump out of more than a single loop at a time. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_bus.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_bus.md new file mode 100644 index 00000000000..e54fc861257 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_bus.md @@ -0,0 +1,21 @@ +--- +title: Data Bus +sidebar_position: 13 +--- +**Disclaimer** this feature is experimental, do not use it! + +The data bus is an optimization that the backend can use to make recursion more efficient. +In order to use it, you must define some inputs of the program entry points (usually the `main()` +function) with the `call_data` modifier, and the return values with the `return_data` modifier. +These modifiers are incompatible with `pub` and `mut` modifiers. + +## Example + +```rust +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { + let a = z[x]; + a+y +} +``` + +As a result, both call_data and return_data will be treated as private inputs and encapsulated into a read-only array each, for the backend to process. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/_category_.json b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/arrays.md new file mode 100644 index 00000000000..efce3e95d32 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/arrays.md @@ -0,0 +1,251 @@ +--- +title: Arrays +description: + Dive into the Array data type in Noir. Grasp its methods, practical examples, and best practices for efficiently using Arrays in your Noir code. +keywords: + [ + noir, + array type, + methods, + examples, + indexing, + ] +sidebar_position: 4 +--- + +An array is one way of grouping together values into one compound type. Array types can be inferred +or explicitly specified via the syntax `[; ]`: + +```rust +fn main(x : Field, y : Field) { + let my_arr = [x, y]; + let your_arr: [Field; 2] = [x, y]; +} +``` + +Here, both `my_arr` and `your_arr` are instantiated as an array containing two `Field` elements. + +Array elements can be accessed using indexing: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; + + let first = a[0]; + let second = a[1]; +} +``` + +All elements in an array must be of the same type (i.e. homogeneous). That is, an array cannot group +a `Field` value and a `u8` value together for example. + +You can write mutable arrays, like: + +```rust +fn main() { + let mut arr = [1, 2, 3, 4, 5]; + assert(arr[0] == 1); + + arr[0] = 42; + assert(arr[0] == 42); +} +``` + +You can instantiate a new array of a fixed size with the same value repeated for each element. The following example instantiates an array of length 32 where each element is of type Field and has the value 0. + +```rust +let array: [Field; 32] = [0; 32]; +``` + +Like in Rust, arrays in Noir are a fixed size. However, if you wish to convert an array to a [slice](./slices), you can just call `as_slice` on your array: + +```rust +let array: [Field; 32] = [0; 32]; +let sl = array.as_slice() +``` + +You can define multidimensional arrays: + +```rust +let array : [[Field; 2]; 2]; +let element = array[0][0]; +``` +However, multidimensional slices are not supported. For example, the following code will error at compile time: +```rust +let slice : [[Field]] = &[]; +``` + +## Types + +You can create arrays of primitive types or structs. There is not yet support for nested arrays +(arrays of arrays) or arrays of structs that contain arrays. + +## Methods + +For convenience, the STD provides some ready-to-use, common methods for arrays. +Each of these functions are located within the generic impl `impl [T; N] {`. +So anywhere `self` appears, it refers to the variable `self: [T; N]`. + +### len + +Returns the length of an array + +```rust +fn len(self) -> Field +``` + +example + +```rust +fn main() { + let array = [42, 42]; + assert(array.len() == 2); +} +``` + +### sort + +Returns a new sorted array. The original array remains untouched. Notice that this function will +only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting +logic it uses internally is optimized specifically for these values. If you need a sort function to +sort any type, you should use the function `sort_via` described below. + +```rust +fn sort(self) -> [T; N] +``` + +example + +```rust +fn main() { + let arr = [42, 32]; + let sorted = arr.sort(); + assert(sorted == [32, 42]); +} +``` + +### sort_via + +Sorts the array with a custom comparison function + +```rust +fn sort_via(self, ordering: fn(T, T) -> bool) -> [T; N] +``` + +example + +```rust +fn main() { + let arr = [42, 32] + let sorted_ascending = arr.sort_via(|a, b| a < b); + assert(sorted_ascending == [32, 42]); // verifies + + let sorted_descending = arr.sort_via(|a, b| a > b); + assert(sorted_descending == [32, 42]); // does not verify +} +``` + +### map + +Applies a function to each element of the array, returning a new array containing the mapped elements. + +```rust +fn map(self, f: fn(T) -> U) -> [U; N] +``` + +example + +```rust +let a = [1, 2, 3]; +let b = a.map(|a| a * 2); // b is now [2, 4, 6] +``` + +### fold + +Applies a function to each element of the array, returning the final accumulated value. The first +parameter is the initial value. + +```rust +fn fold(self, mut accumulator: U, f: fn(U, T) -> U) -> U +``` + +This is a left fold, so the given function will be applied to the accumulator and first element of +the array, then the second, and so on. For a given call the expected result would be equivalent to: + +```rust +let a1 = [1]; +let a2 = [1, 2]; +let a3 = [1, 2, 3]; + +let f = |a, b| a - b; +a1.fold(10, f) //=> f(10, 1) +a2.fold(10, f) //=> f(f(10, 1), 2) +a3.fold(10, f) //=> f(f(f(10, 1), 2), 3) +``` + +example: + +```rust + +fn main() { + let arr = [2, 2, 2, 2, 2]; + let folded = arr.fold(0, |a, b| a + b); + assert(folded == 10); +} + +``` + +### reduce + +Same as fold, but uses the first element as starting element. + +```rust +fn reduce(self, f: fn(T, T) -> T) -> T +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 2]; + let reduced = arr.reduce(|a, b| a + b); + assert(reduced == 10); +} +``` + +### all + +Returns true if all the elements satisfy the given predicate + +```rust +fn all(self, predicate: fn(T) -> bool) -> bool +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 2]; + let all = arr.all(|a| a == 2); + assert(all); +} +``` + +### any + +Returns true if any of the elements satisfy the given predicate + +```rust +fn any(self, predicate: fn(T) -> bool) -> bool +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 5]; + let any = arr.any(|a| a == 5); + assert(any); +} + +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/booleans.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/booleans.md new file mode 100644 index 00000000000..69826fcd724 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/booleans.md @@ -0,0 +1,31 @@ +--- +title: Booleans +description: + Delve into the Boolean data type in Noir. Understand its methods, practical examples, and best practices for using Booleans in your Noir programs. +keywords: + [ + noir, + boolean type, + methods, + examples, + logical operations, + ] +sidebar_position: 2 +--- + + +The `bool` type in Noir has two possible values: `true` and `false`: + +```rust +fn main() { + let t = true; + let f: bool = false; +} +``` + +> **Note:** When returning a boolean value, it will show up as a value of 1 for `true` and 0 for +> `false` in _Verifier.toml_. + +The boolean type is most commonly used in conditionals like `if` expressions and `assert` +statements. More about conditionals is covered in the [Control Flow](../control_flow) and +[Assert Function](../assert) sections. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/fields.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/fields.md new file mode 100644 index 00000000000..a10a4810788 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/fields.md @@ -0,0 +1,192 @@ +--- +title: Fields +description: + Dive deep into the Field data type in Noir. Understand its methods, practical examples, and best practices to effectively use Fields in your Noir programs. +keywords: + [ + noir, + field type, + methods, + examples, + best practices, + ] +sidebar_position: 0 +--- + +The field type corresponds to the native field type of the proving backend. + +The size of a Noir field depends on the elliptic curve's finite field for the proving backend +adopted. For example, a field would be a 254-bit integer when paired with the default backend that +spans the Grumpkin curve. + +Fields support integer arithmetic and are often used as the default numeric type in Noir: + +```rust +fn main(x : Field, y : Field) { + let z = x + y; +} +``` + +`x`, `y` and `z` are all private fields in this example. Using the `let` keyword we defined a new +private value `z` constrained to be equal to `x + y`. + +If proving efficiency is of priority, fields should be used as a default for solving problems. +Smaller integer types (e.g. `u64`) incur extra range constraints. + +## Methods + +After declaring a Field, you can use these common methods on it: + +### to_le_bits + +Transforms the field into an array of bits, Little Endian. + +```rust +fn to_le_bits(_x : Field, _bit_size: u32) -> [u1] +``` + +example: + +```rust +fn main() { + let field = 2; + let bits = field.to_le_bits(32); +} +``` + +### to_be_bits + +Transforms the field into an array of bits, Big Endian. + +```rust +fn to_be_bits(_x : Field, _bit_size: u32) -> [u1] +``` + +example: + +```rust +fn main() { + let field = 2; + let bits = field.to_be_bits(32); +} +``` + +### to_le_bytes + +Transforms into an array of bytes, Little Endian + +```rust +fn to_le_bytes(_x : Field, byte_size: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let bytes = field.to_le_bytes(4); +} +``` + +### to_be_bytes + +Transforms into an array of bytes, Big Endian + +```rust +fn to_be_bytes(_x : Field, byte_size: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let bytes = field.to_be_bytes(4); +} +``` + +### to_le_radix + +Decomposes into a vector over the specified base, Little Endian + +```rust +fn to_le_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let radix = field.to_le_radix(256, 4); +} +``` + +### to_be_radix + +Decomposes into a vector over the specified base, Big Endian + +```rust +fn to_be_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let radix = field.to_be_radix(256, 4); +} +``` + +### pow_32 + +Returns the value to the power of the specified exponent + +```rust +fn pow_32(self, exponent: Field) -> Field +``` + +example: + +```rust +fn main() { + let field = 2 + let pow = field.pow_32(4); + assert(pow == 16); +} +``` + +### assert_max_bit_size + +Adds a constraint to specify that the field can be represented with `bit_size` number of bits + +```rust +fn assert_max_bit_size(self, bit_size: u32) +``` + +example: + +```rust +fn main() { + let field = 2 + field.assert_max_bit_size(32); +} +``` + +### sgn0 + +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. + +```rust +fn sgn0(self) -> u1 +``` + + +### lt + +Returns true if the field is less than the other field + +```rust +pub fn lt(self, another: Field) -> bool +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/function_types.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/function_types.md new file mode 100644 index 00000000000..f6121af17e2 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/function_types.md @@ -0,0 +1,26 @@ +--- +title: Function types +sidebar_position: 10 +--- + +Noir supports higher-order functions. The syntax for a function type is as follows: + +```rust +fn(arg1_type, arg2_type, ...) -> return_type +``` + +Example: + +```rust +fn assert_returns_100(f: fn() -> Field) { // f takes no args and returns a Field + assert(f() == 100); +} + +fn main() { + assert_returns_100(|| 100); // ok + assert_returns_100(|| 150); // fails +} +``` + +A function type also has an optional capture environment - this is necessary to support closures. +See [Lambdas](../lambdas.md) for more details. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/index.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/index.md new file mode 100644 index 00000000000..357813c147a --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/index.md @@ -0,0 +1,110 @@ +--- +title: Data Types +description: + Get a clear understanding of the two categories of Noir data types - primitive types and compound + types. Learn about their characteristics, differences, and how to use them in your Noir + programming. +keywords: + [ + noir, + data types, + primitive types, + compound types, + private types, + public types, + ] +--- + +Every value in Noir has a type, which determines which operations are valid for it. + +All values in Noir are fundamentally composed of `Field` elements. For a more approachable +developing experience, abstractions are added on top to introduce different data types in Noir. + +Noir has two category of data types: primitive types (e.g. `Field`, integers, `bool`) and compound +types that group primitive types (e.g. arrays, tuples, structs). Each value can either be private or +public. + +## Private & Public Types + +A **private value** is known only to the Prover, while a **public value** is known by both the +Prover and Verifier. Mark values as `private` when the value should only be known to the prover. All +primitive types (including individual fields of compound types) in Noir are private by default, and +can be marked public when certain values are intended to be revealed to the Verifier. + +> **Note:** For public values defined in Noir programs paired with smart contract verifiers, once +> the proofs are verified on-chain the values can be considered known to everyone that has access to +> that blockchain. + +Public data types are treated no differently to private types apart from the fact that their values +will be revealed in proofs generated. Simply changing the value of a public type will not change the +circuit (where the same goes for changing values of private types as well). + +_Private values_ are also referred to as _witnesses_ sometimes. + +> **Note:** The terms private and public when applied to a type (e.g. `pub Field`) have a different +> meaning than when applied to a function (e.g. `pub fn foo() {}`). +> +> The former is a visibility modifier for the Prover to interpret if a value should be made known to +> the Verifier, while the latter is a visibility modifier for the compiler to interpret if a +> function should be made accessible to external Noir programs like in other languages. + +### pub Modifier + +All data types in Noir are private by default. Types are explicitly declared as public using the +`pub` modifier: + +```rust +fn main(x : Field, y : pub Field) -> pub Field { + x + y +} +``` + +In this example, `x` is **private** while `y` and `x + y` (the return value) are **public**. Note +that visibility is handled **per variable**, so it is perfectly valid to have one input that is +private and another that is public. + +> **Note:** Public types can only be declared through parameters on `main`. + +## Type Aliases + +A type alias is a new name for an existing type. Type aliases are declared with the keyword `type`: + +```rust +type Id = u8; + +fn main() { + let id: Id = 1; + let zero: u8 = 0; + assert(zero + 1 == id); +} +``` + +Type aliases can also be used with [generics](../generics.md): + +```rust +type Id = Size; + +fn main() { + let id: Id = 1; + let zero: u32 = 0; + assert(zero + 1 == id); +} +``` + +Type aliases can even refer to other aliases. An error will be issued if they form a cycle: + +```rust +// Ok! +type A = B; +type B = Field; + +type Bad1 = Bad2; + +// error: Dependency cycle found +type Bad2 = Bad1; +// ^^^^^^^^^^^ 'Bad2' recursively depends on itself: Bad2 -> Bad1 -> Bad2 +``` + +### BigInt + +You can achieve BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/integers.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/integers.md new file mode 100644 index 00000000000..1c6b375db49 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/integers.md @@ -0,0 +1,155 @@ +--- +title: Integers +description: Explore the Integer data type in Noir. Learn about its methods, see real-world examples, and grasp how to efficiently use Integers in your Noir code. +keywords: [noir, integer types, methods, examples, arithmetic] +sidebar_position: 1 +--- + +An integer type is a range constrained field type. The Noir frontend supports both unsigned and signed integer types. The allowed sizes are 1, 8, 32 and 64 bits. + +:::info + +When an integer is defined in Noir without a specific type, it will default to `Field`. + +The one exception is for loop indices which default to `u64` since comparisons on `Field`s are not possible. + +::: + +## Unsigned Integers + +An unsigned integer type is specified first with the letter `u` (indicating its unsigned nature) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: u8 = 1; + let y: u8 = 1; + let z = x + y; + assert (z == 2); +} +``` + +The bit size determines the maximum value the integer type can store. For example, a `u8` variable can store a value in the range of 0 to 255 (i.e. $\\2^{8}-1\\$). + +## Signed Integers + +A signed integer type is specified first with the letter `i` (which stands for integer) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: i8 = -1; + let y: i8 = -1; + let z = x + y; + assert (z == -2); +} +``` + +The bit size determines the maximum and minimum range of value the integer type can store. For example, an `i8` variable can store a value in the range of -128 to 127 (i.e. $\\-2^{7}\\$ to $\\2^{7}-1\\$). + +## 128 bits Unsigned Integers + +The built-in structure `U128` allows you to use 128-bit unsigned integers almost like a native integer type. However, there are some differences to keep in mind: +- You cannot cast between a native integer and `U128` +- There is a higher performance cost when using `U128`, compared to a native type. + +Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. `from_integer` also accepts the `Field` type as input. + +```rust +fn main() { + let x = U128::from_integer(23); + let y = U128::from_hex("0x7"); + let z = x + y; + assert(z.to_integer() == 30); +} +``` + +`U128` is implemented with two 64 bits limbs, representing the low and high bits, which explains the performance cost. You should expect `U128` to be twice more costly for addition and four times more costly for multiplication. +You can construct a U128 from its limbs: +```rust +fn main(x: u64, y: u64) { + let x = U128::from_u64s_be(x,y); + assert(z.hi == x as Field); + assert(z.lo == y as Field); +} +``` + +Note that the limbs are stored as Field elements in order to avoid unnecessary conversions. +Apart from this, most operations will work as usual: + +```rust +fn main(x: U128, y: U128) { + // multiplication + let c = x * y; + // addition and subtraction + let c = c - x + y; + // division + let c = x / y; + // bit operation; + let c = x & y | y; + // bit shift + let c = x << y; + // comparisons; + let c = x < y; + let c = x == y; +} +``` + +## Overflows + +Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: + +```rust +fn main(x: u8, y: u8) { + let z = x + y; +} +``` + +With: + +```toml +x = "255" +y = "1" +``` + +Would result in: + +``` +$ nargo prove +error: Assertion failed: 'attempt to add with overflow' +┌─ ~/src/main.nr:9:13 +│ +│ let z = x + y; +│ ----- +│ += Call stack: + ... +``` + +A similar error would happen with signed integers: + +```rust +fn main() { + let x: i8 = -118; + let y: i8 = -11; + let z = x + y; +} +``` + +### Wrapping methods + +Although integer overflow is expected to error, some use-cases rely on wrapping. For these use-cases, the standard library provides `wrapping` variants of certain common operations: + +```rust +fn wrapping_add(x: T, y: T) -> T; +fn wrapping_sub(x: T, y: T) -> T; +fn wrapping_mul(x: T, y: T) -> T; +``` + +Example of how it is used: + +```rust +use dep::std; + +fn main(x: u8, y: u8) -> pub u8 { + std::wrapping_add(x, y) +} +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/references.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/references.md new file mode 100644 index 00000000000..a5293d11cfb --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/references.md @@ -0,0 +1,23 @@ +--- +title: References +sidebar_position: 9 +--- + +Noir supports first-class references. References are a bit like pointers: they point to a specific address that can be followed to access the data stored at that address. You can use Rust-like syntax to use pointers in Noir: the `&` operator references the variable, the `*` operator dereferences it. + +Example: + +```rust +fn main() { + let mut x = 2; + + // you can reference x as &mut and pass it to multiplyBy2 + multiplyBy2(&mut x); +} + +// you can access &mut here +fn multiplyBy2(x: &mut Field) { + // and dereference it with * + *x = *x * 2; +} +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/slices.mdx b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/slices.mdx new file mode 100644 index 00000000000..4eccc677b80 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/slices.mdx @@ -0,0 +1,195 @@ +--- +title: Slices +description: Explore the Slice data type in Noir. Understand its methods, see real-world examples, and learn how to effectively use Slices in your Noir programs. +keywords: [noir, slice type, methods, examples, subarrays] +sidebar_position: 5 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A slice is a dynamically-sized view into a sequence of elements. They can be resized at runtime, but because they don't own the data, they cannot be returned from a circuit. You can treat slices as arrays without a constrained size. + +```rust +use dep::std::slice; + +fn main() -> pub Field { + let mut slice: [Field] = &[0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice.len() +} +``` + +To write a slice literal, use a preceeding ampersand as in: `&[0; 2]` or +`&[1, 2, 3]`. + +It is important to note that slices are not references to arrays. In Noir, +`&[..]` is more similar to an immutable, growable vector. + +View the corresponding test file [here][test-file]. + +[test-file]: https://github.com/noir-lang/noir/blob/f387ec1475129732f72ba294877efdf6857135ac/crates/nargo_cli/tests/test_data_ssa_refactor/slices/src/main.nr + +## Methods + +For convenience, the STD provides some ready-to-use, common methods for slices: + +### push_back + +Pushes a new element to the end of the slice, returning a new slice with a length one greater than the original unmodified slice. + +```rust +fn push_back(_self: [T], _elem: T) -> [T] +``` + +example: + +```rust +fn main() -> pub Field { + let mut slice: [Field] = &[0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice.len() +} +``` + +View the corresponding test file [here][test-file]. + +### push_front + +Returns a new array with the specified element inserted at index 0. The existing elements indexes are incremented by 1. + +```rust +fn push_front(_self: Self, _elem: T) -> Self +``` + +Example: + +```rust +let mut new_slice: [Field] = &[]; +new_slice = new_slice.push_front(20); +assert(new_slice[0] == 20); // returns true +``` + +View the corresponding test file [here][test-file]. + +### pop_front + +Returns a tuple of two items, the first element of the array and the rest of the array. + +```rust +fn pop_front(_self: Self) -> (T, Self) +``` + +Example: + +```rust +let (first_elem, rest_of_slice) = slice.pop_front(); +``` + +View the corresponding test file [here][test-file]. + +### pop_back + +Returns a tuple of two items, the beginning of the array with the last element omitted and the last element. + +```rust +fn pop_back(_self: Self) -> (Self, T) +``` + +Example: + +```rust +let (popped_slice, last_elem) = slice.pop_back(); +``` + +View the corresponding test file [here][test-file]. + +### append + +Loops over a slice and adds it to the end of another. + +```rust +fn append(mut self, other: Self) -> Self +``` + +Example: + +```rust +let append = &[1, 2].append(&[3, 4, 5]); +``` + +### insert + +Inserts an element at a specified index and shifts all following elements by 1. + +```rust +fn insert(_self: Self, _index: Field, _elem: T) -> Self +``` + +Example: + +```rust +new_slice = rest_of_slice.insert(2, 100); +assert(new_slice[2] == 100); +``` + +View the corresponding test file [here][test-file]. + +### remove + +Remove an element at a specified index, shifting all elements after it to the left, returning the altered slice and the removed element. + +```rust +fn remove(_self: Self, _index: Field) -> (Self, T) +``` + +Example: + +```rust +let (remove_slice, removed_elem) = slice.remove(3); +``` + +### len + +Returns the length of a slice + +```rust +fn len(self) -> Field +``` + +Example: + +```rust +fn main() { + let slice = &[42, 42]; + assert(slice.len() == 2); +} +``` + +### as_array + +Converts this slice into an array. + +Make sure to specify the size of the resulting array. +Panics if the resulting array length is different than the slice's length. + +```rust +fn as_array(self) -> [T; N] +``` + +Example: + +```rust +fn main() { + let slice = &[5, 6]; + + // Always specify the length of the resulting array! + let array: [Field; 2] = slice.as_array(); + + assert(array[0] == slice[0]); + assert(array[1] == slice[1]); +} +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/strings.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/strings.md new file mode 100644 index 00000000000..311dfd64416 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/strings.md @@ -0,0 +1,80 @@ +--- +title: Strings +description: + Discover the String data type in Noir. Learn about its methods, see real-world examples, and understand how to effectively manipulate and use Strings in Noir. +keywords: + [ + noir, + string type, + methods, + examples, + concatenation, + ] +sidebar_position: 3 +--- + + +The string type is a fixed length value defined with `str`. + +You can use strings in `assert()` functions or print them with +`println()`. See more about [Logging](../../standard_library/logging). + +```rust +use dep::std; + +fn main(message : pub str<11>, hex_as_string : str<4>) { + println(message); + assert(message == "hello world"); + assert(hex_as_string == "0x41"); +} +``` + +You can convert a `str` to a byte array by calling `as_bytes()` +or a vector by calling `as_bytes_vec()`. + +```rust +fn main() { + let message = "hello world"; + let message_bytes = message.as_bytes(); + let mut message_vec = message.as_bytes_vec(); + assert(message_bytes.len() == 11); + assert(message_bytes[0] == 104); + assert(message_bytes[0] == message_vec.get(0)); +} +``` + +## Escape characters + +You can use escape characters for your strings: + +| Escape Sequence | Description | +|-----------------|-----------------| +| `\r` | Carriage Return | +| `\n` | Newline | +| `\t` | Tab | +| `\0` | Null Character | +| `\"` | Double Quote | +| `\\` | Backslash | + +Example: + +```rust +let s = "Hello \"world" // prints "Hello "world" +let s = "hey \tyou"; // prints "hey you" +``` + +## Raw strings + +A raw string begins with the letter `r` and is optionally delimited by a number of hashes `#`. + +Escape characters are *not* processed within raw strings. All contents are interpreted literally. + +Example: + +```rust +let s = r"Hello world"; +let s = r#"Simon says "hello world""#; + +// Any number of hashes may be used (>= 1) as long as the string also terminates with the same number of hashes +let s = r#####"One "#, Two "##, Three "###, Four "####, Five will end the string."#####; +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/structs.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/structs.md new file mode 100644 index 00000000000..dbf68c99813 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/structs.md @@ -0,0 +1,70 @@ +--- +title: Structs +description: + Explore the Struct data type in Noir. Learn about its methods, see real-world examples, and grasp how to effectively define and use Structs in your Noir programs. +keywords: + [ + noir, + struct type, + methods, + examples, + data structures, + ] +sidebar_position: 8 +--- + +A struct also allows for grouping multiple values of different types. Unlike tuples, we can also +name each field. + +> **Note:** The usage of _field_ here refers to each element of the struct and is unrelated to the +> field type of Noir. + +Defining a struct requires giving it a name and listing each field within as `: ` pairs: + +```rust +struct Animal { + hands: Field, + legs: Field, + eyes: u8, +} +``` + +An instance of a struct can then be created with actual values in `: ` pairs in any +order. Struct fields are accessible using their given names: + +```rust +fn main() { + let legs = 4; + + let dog = Animal { + eyes: 2, + hands: 0, + legs, + }; + + let zero = dog.hands; +} +``` + +Structs can also be destructured in a pattern, binding each field to a new variable: + +```rust +fn main() { + let Animal { hands, legs: feet, eyes } = get_octopus(); + + let ten = hands + feet + eyes as u8; +} + +fn get_octopus() -> Animal { + let octopus = Animal { + hands: 0, + legs: 8, + eyes: 2, + }; + + octopus +} +``` + +The new variables can be bound with names different from the original struct field names, as +showcased in the `legs --> feet` binding in the example above. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/tuples.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/tuples.md new file mode 100644 index 00000000000..2ec5c9c4113 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/tuples.md @@ -0,0 +1,48 @@ +--- +title: Tuples +description: + Dive into the Tuple data type in Noir. Understand its methods, practical examples, and best practices for efficiently using Tuples in your Noir code. +keywords: + [ + noir, + tuple type, + methods, + examples, + multi-value containers, + ] +sidebar_position: 7 +--- + +A tuple collects multiple values like an array, but with the added ability to collect values of +different types: + +```rust +fn main() { + let tup: (u8, u64, Field) = (255, 500, 1000); +} +``` + +One way to access tuple elements is via destructuring using pattern matching: + +```rust +fn main() { + let tup = (1, 2); + + let (one, two) = tup; + + let three = one + two; +} +``` + +Another way to access tuple elements is via direct member access, using a period (`.`) followed by +the index of the element we want to access. Index `0` corresponds to the first tuple element, `1` to +the second and so on: + +```rust +fn main() { + let tup = (5, 6, 7, 8); + + let five = tup.0; + let eight = tup.3; +} +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/functions.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/functions.md new file mode 100644 index 00000000000..f656cdfd97a --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/functions.md @@ -0,0 +1,226 @@ +--- +title: Functions +description: + Learn how to declare functions and methods in Noir, a programming language with Rust semantics. + This guide covers parameter declaration, return types, call expressions, and more. +keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] +sidebar_position: 1 +--- + +Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. + +To declare a function the `fn` keyword is used. + +```rust +fn foo() {} +``` + +By default, functions are visible only within the package they are defined. To make them visible outside of that package (for example, as part of a [library](../modules_packages_crates/crates_and_packages.md#libraries)), you should mark them as `pub`: + +```rust +pub fn foo() {} +``` + +You can also restrict the visibility of the function to only the crate it was defined in, by specifying `pub(crate)`: + +```rust +pub(crate) fn foo() {} //foo can only be called within its crate +``` + +All parameters in a function must have a type and all types are known at compile time. The parameter +is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. + +```rust +fn foo(x : Field, y : Field){} +``` + +The return type of a function can be stated by using the `->` arrow notation. The function below +states that the foo function must return a `Field`. If the function returns no value, then the arrow +is omitted. + +```rust +fn foo(x : Field, y : Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## Main function + +If you're writing a binary, the `main` function is the starting point of your program. You can pass all types of expressions to it, as long as they have a fixed size at compile time: + +```rust +fn main(x : Field) // this is fine: passing a Field +fn main(x : [Field; 2]) // this is also fine: passing a Field with known size at compile-time +fn main(x : (Field, bool)) // 👌: passing a (Field, bool) tuple means size 2 +fn main(x : str<5>) // this is fine, as long as you pass a string of size 5 + +fn main(x : Vec) // can't compile, has variable size +fn main(x : [Field]) // can't compile, has variable size +fn main(....// i think you got it by now +``` + +Keep in mind [tests](../../tooling/testing.md) don't differentiate between `main` and any other function. The following snippet passes tests, but won't compile or prove: + +```rust +fn main(x : [Field]) { + assert(x[0] == 1); +} + +#[test] +fn test_one() { + main(&[1, 2]); +} +``` + +```bash +$ nargo test +[testing] Running 1 test functions +[testing] Testing test_one... ok +[testing] All tests passed + +$ nargo check +The application panicked (crashed). +Message: Cannot have variable sized arrays as a parameter to main +``` + +## Call Expressions + +Calling a function in Noir is executed by using the function name and passing in the necessary +arguments. + +Below we show how to call the `foo` function from the `main` function using a call expression: + +```rust +fn main(x : Field, y : Field) { + let z = foo(x); +} + +fn foo(x : Field) -> Field { + x + x +} +``` + +## Methods + +You can define methods in Noir on any struct type in scope. + +```rust +struct MyStruct { + foo: Field, + bar: Field, +} + +impl MyStruct { + fn new(foo: Field) -> MyStruct { + MyStruct { + foo, + bar: 2, + } + } + + fn sum(self) -> Field { + self.foo + self.bar + } +} + +fn main() { + let s = MyStruct::new(40); + assert(s.sum() == 42); +} +``` + +Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as +follows: + +```rust +assert(MyStruct::sum(s) == 42); +``` + +It is also possible to specialize which method is chosen depending on the [generic](./generics.md) type that is used. In this example, the `foo` function returns different values depending on its type: + +```rust +struct Foo {} + +impl Foo { + fn foo(self) -> Field { 1 } +} + +impl Foo { + fn foo(self) -> Field { 2 } +} + +fn main() { + let f1: Foo = Foo{}; + let f2: Foo = Foo{}; + assert(f1.foo() + f2.foo() == 3); +} +``` + +Also note that impls with the same method name defined in them cannot overlap. For example, if we already have `foo` defined for `Foo` and `Foo` like we do above, we cannot also define `foo` in an `impl Foo` since it would be ambiguous which version of `foo` to choose. + +```rust +// Including this impl in the same project as the above snippet would +// cause an overlapping impls error +impl Foo { + fn foo(self) -> Field { 3 } +} +``` + +## Lambdas + +Lambdas are anonymous functions. They follow the syntax of Rust - `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +See [Lambdas](./lambdas.md) for more details. + +## Attributes + +Attributes are metadata that can be applied to a function, using the following syntax: `#[attribute(value)]`. + +Supported attributes include: + +- **builtin**: the function is implemented by the compiler, for efficiency purposes. +- **deprecated**: mark the function as _deprecated_. Calling the function will generate a warning: `warning: use of deprecated function` +- **field**: Used to enable conditional compilation of code depending on the field size. See below for more details +- **oracle**: mark the function as _oracle_; meaning it is an external unconstrained function, implemented in noir_js. See [Unconstrained](./unconstrained.md) and [NoirJS](../../reference/NoirJS/noir_js/index.md) for more details. +- **test**: mark the function as unit tests. See [Tests](../../tooling/testing.md) for more details + +### Field Attribute + +The field attribute defines which field the function is compatible for. The function is conditionally compiled, under the condition that the field attribute matches the Noir native field. +The field can be defined implicitly, by using the name of the elliptic curve usually associated to it - for instance bn254, bls12_381 - or explicitly by using the field (prime) order, in decimal or hexadecimal form. +As a result, it is possible to define multiple versions of a function with each version specialized for a different field attribute. This can be useful when a function requires different parameters depending on the underlying elliptic curve. + +Example: we define the function `foo()` three times below. Once for the default Noir bn254 curve, once for the field $\mathbb F_{23}$, which will normally never be used by Noir, and once again for the bls12_381 curve. + +```rust +#[field(bn254)] +fn foo() -> u32 { + 1 +} + +#[field(23)] +fn foo() -> u32 { + 2 +} + +// This commented code would not compile as foo would be defined twice because it is the same field as bn254 +// #[field(21888242871839275222246405745257275088548364400416034343698204186575808495617)] +// fn foo() -> u32 { +// 2 +// } + +#[field(bls12_381)] +fn foo() -> u32 { + 3 +} +``` + +If the field name is not known to Noir, it will discard the function. Field names are case insensitive. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/generics.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/generics.md new file mode 100644 index 00000000000..ddd42bf1f9b --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/generics.md @@ -0,0 +1,106 @@ +--- +title: Generics +description: Learn how to use Generics in Noir +keywords: [Noir, Rust, generics, functions, structs] +sidebar_position: 7 +--- + +Generics allow you to use the same functions with multiple different concrete data types. You can +read more about the concept of generics in the Rust documentation +[here](https://doc.rust-lang.org/book/ch10-01-syntax.html). + +Here is a trivial example showing the identity function that supports any type. In Rust, it is +common to refer to the most general type as `T`. We follow the same convention in Noir. + +```rust +fn id(x: T) -> T { + x +} +``` + +## In Structs + +Generics are useful for specifying types in structs. For example, we can specify that a field in a +struct will be of a certain generic type. In this case `value` is of type `T`. + +```rust +struct RepeatedValue { + value: T, + count: Field, +} + +impl RepeatedValue { + fn print(self) { + for _i in 0 .. self.count { + println(self.value); + } + } +} + +fn main() { + let repeated = RepeatedValue { value: "Hello!", count: 2 }; + repeated.print(); +} +``` + +The `print` function will print `Hello!` an arbitrary number of times, twice in this case. + +If we want to be generic over array lengths (which are type-level integers), we can use numeric +generics. Using these looks just like using regular generics, but these generics can resolve to +integers at compile-time, rather than resolving to types. Here's an example of a struct that is +generic over the size of the array it contains internally: + +```rust +struct BigInt { + limbs: [u32; N], +} + +impl BigInt { + // `N` is in scope of all methods in the impl + fn first(first: BigInt, second: BigInt) -> Self { + assert(first.limbs != second.limbs); + first + + fn second(first: BigInt, second: Self) -> Self { + assert(first.limbs != second.limbs); + second + } +} +``` + +## Calling functions on generic parameters + +Since a generic type `T` can represent any type, how can we call functions on the underlying type? +In other words, how can we go from "any type `T`" to "any type `T` that has certain methods available?" + +This is what [traits](../concepts/traits) are for in Noir. Here's an example of a function generic over +any type `T` that implements the `Eq` trait for equality: + +```rust +fn first_element_is_equal(array1: [T; N], array2: [T; N]) -> bool + where T: Eq +{ + if (array1.len() == 0) | (array2.len() == 0) { + true + } else { + array1[0] == array2[0] + } +} + +fn main() { + assert(first_element_is_equal([1, 2, 3], [1, 5, 6])); + + // We can use first_element_is_equal for arrays of any type + // as long as we have an Eq impl for the types we pass in + let array = [MyStruct::new(), MyStruct::new()]; + assert(array_eq(array, array, MyStruct::eq)); +} + +impl Eq for MyStruct { + fn eq(self, other: MyStruct) -> bool { + self.foo == other.foo + } +} +``` + +You can find more details on traits and trait implementations on the [traits page](../concepts/traits). diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/globals.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/globals.md new file mode 100644 index 00000000000..063a3d89248 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/globals.md @@ -0,0 +1,72 @@ +--- +title: Global Variables +description: + Learn about global variables in Noir. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, globals, global variables, constants] +sidebar_position: 8 +--- + +## Globals + + +Noir supports global variables. The global's type can be inferred by the compiler entirely: + +```rust +global N = 5; // Same as `global N: Field = 5` + +global TUPLE = (3, 2); + +fn main() { + assert(N == 5); + assert(N == TUPLE.0 + TUPLE.1); +} +``` + +:::info + +Globals can be defined as any expression, so long as they don't depend on themselves - otherwise there would be a dependency cycle! For example: + +```rust +global T = foo(T); // dependency error +``` + +::: + + +If they are initialized to a literal integer, globals can be used to specify an array's length: + +```rust +global N: Field = 2; + +fn main(y : [Field; N]) { + assert(y[0] == y[1]) +} +``` + +A global from another module can be imported or referenced externally like any other name: + +```rust +global N = 20; + +fn main() { + assert(my_submodule::N != N); +} + +mod my_submodule { + global N: Field = 10; +} +``` + +When a global is used, Noir replaces the name with its definition on each occurrence. +This means globals defined using function calls will repeat the call each time they're used: + +```rust +global RESULT = foo(); + +fn foo() -> [Field; 100] { ... } +``` + +This is usually fine since Noir will generally optimize any function call that does not +refer to a program input into a constant. It should be kept in mind however, if the called +function performs side-effects like `println`, as these will still occur on each use. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/lambdas.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/lambdas.md new file mode 100644 index 00000000000..be3c7e0b5ca --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/lambdas.md @@ -0,0 +1,81 @@ +--- +title: Lambdas +description: Learn how to use anonymous functions in Noir programming language. +keywords: [Noir programming language, lambda, closure, function, anonymous function] +sidebar_position: 9 +--- + +## Introduction + +Lambdas are anonymous functions. The syntax is `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +A block can be used as the body of a lambda, allowing you to declare local variables inside it: + +```rust +let cool = || { + let x = 100; + let y = 100; + x + y +} + +assert(cool() == 200); +``` + +## Closures + +Inside the body of a lambda, you can use variables defined in the enclosing function. Such lambdas are called **closures**. In this example `x` is defined inside `main` and is accessed from within the lambda: + +```rust +fn main() { + let x = 100; + let closure = || x + 150; + assert(closure() == 250); +} +``` + +## Passing closures to higher-order functions + +It may catch you by surprise that the following code fails to compile: + +```rust +fn foo(f: fn () -> Field) -> Field { + f() +} + +fn main() { + let (x, y) = (50, 50); + assert(foo(|| x + y) == 100); // error :( +} +``` + +The reason is that the closure's capture environment affects its type - we have a closure that captures two Fields and `foo` +expects a regular function as an argument - those are incompatible. +:::note + +Variables contained within the `||` are the closure's parameters, and the expression that follows it is the closure's body. The capture environment is comprised of any variables used in the closure's body that are not parameters. + +E.g. in |x| x + y, y would be a captured variable, but x would not be, since it is a parameter of the closure. + +::: +The syntax for the type of a closure is `fn[env](args) -> ret_type`, where `env` is the capture environment of the closure - +in this example that's `(Field, Field)`. + +The best solution in our case is to make `foo` generic over the environment type of its parameter, so that it can be called +with closures with any environment, as well as with regular functions: + +```rust +fn foo(f: fn[Env]() -> Field) -> Field { + f() +} + +fn main() { + let (x, y) = (50, 50); + assert(foo(|| x + y) == 100); // compiles fine + assert(foo(|| 60) == 60); // compiles fine +} +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/mutability.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/mutability.md new file mode 100644 index 00000000000..fdeef6a87c5 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/mutability.md @@ -0,0 +1,121 @@ +--- +title: Mutability +description: + Learn about mutable variables in Noir. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, mutability in noir, mutable variables] +sidebar_position: 8 +--- + +Variables in noir can be declared mutable via the `mut` keyword. Mutable variables can be reassigned +to via an assignment expression. + +```rust +let x = 2; +x = 3; // error: x must be mutable to be assigned to + +let mut y = 3; +let y = 4; // OK +``` + +The `mut` modifier can also apply to patterns: + +```rust +let (a, mut b) = (1, 2); +a = 11; // error: a must be mutable to be assigned to +b = 12; // OK + +let mut (c, d) = (3, 4); +c = 13; // OK +d = 14; // OK + +// etc. +let MyStruct { x: mut y } = MyStruct { x: a }; +// y is now in scope +``` + +Note that mutability in noir is local and everything is passed by value, so if a called function +mutates its parameters then the parent function will keep the old value of the parameters. + +```rust +fn main() -> pub Field { + let x = 3; + helper(x); + x // x is still 3 +} + +fn helper(mut x: i32) { + x = 4; +} +``` + +## Non-local mutability + +Non-local mutability can be achieved through the mutable reference type `&mut T`: + +```rust +fn set_to_zero(x: &mut Field) { + *x = 0; +} + +fn main() { + let mut y = 42; + set_to_zero(&mut y); + assert(*y == 0); +} +``` + +When creating a mutable reference, the original variable being referred to (`y` in this +example) must also be mutable. Since mutable references are a reference type, they must +be explicitly dereferenced via `*` to retrieve the underlying value. Note that this yields +a copy of the value, so mutating this copy will not change the original value behind the +reference: + +```rust +fn main() { + let mut x = 1; + let x_ref = &mut x; + + let mut y = *x_ref; + let y_ref = &mut y; + + x = 2; + *x_ref = 3; + + y = 4; + *y_ref = 5; + + assert(x == 3); + assert(*x_ref == 3); + assert(y == 5); + assert(*y_ref == 5); +} +``` + +Note that types in Noir are actually deeply immutable so the copy that occurs when +dereferencing is only a conceptual copy - no additional constraints will occur. + +Mutable references can also be stored within structs. Note that there is also +no lifetime parameter on these unlike rust. This is because the allocated memory +always lasts the entire program - as if it were an array of one element. + +```rust +struct Foo { + x: &mut Field +} + +impl Foo { + fn incr(mut self) { + *self.x += 1; + } +} + +fn main() { + let foo = Foo { x: &mut 0 }; + foo.incr(); + assert(*foo.x == 1); +} +``` + +In general, you should avoid non-local & shared mutability unless it is needed. Sticking +to only local mutability will improve readability and potentially improve compiler optimizations as well. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/ops.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/ops.md new file mode 100644 index 00000000000..c35c36c38a9 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/ops.md @@ -0,0 +1,98 @@ +--- +title: Logical Operations +description: + Learn about the supported arithmetic and logical operations in the Noir programming language. + Discover how to perform operations on private input types, integers, and booleans. +keywords: + [ + Noir programming language, + supported operations, + arithmetic operations, + logical operations, + predicate operators, + bitwise operations, + short-circuiting, + backend, + ] +sidebar_position: 3 +--- + +# Operations + +## Table of Supported Operations + +| Operation | Description | Requirements | +| :-------- | :------------------------------------------------------------: | -------------------------------------: | +| + | Adds two private input types together | Types must be private input | +| - | Subtracts two private input types together | Types must be private input | +| \* | Multiplies two private input types together | Types must be private input | +| / | Divides two private input types together | Types must be private input | +| ^ | XOR two private input types together | Types must be integer | +| & | AND two private input types together | Types must be integer | +| \| | OR two private input types together | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer, shift must be u8 | +| >> | Right shift an integer by another integer amount | Types must be integer, shift must be u8 | +| ! | Bitwise not of a value | Type must be integer or boolean | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| > | returns a bool if one value is more than the other | Upper bound must have a known bit size | +| >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | +| == | returns a bool if one value is equal to the other | Both types must not be constants | +| != | returns a bool if one value is not equal to the other | Both types must not be constants | + +### Predicate Operators + +`<,<=, !=, == , >, >=` are known as predicate/comparison operations because they compare two values. +This differs from the operations such as `+` where the operands are used in _computation_. + +### Bitwise Operations Example + +```rust +fn main(x : Field) { + let y = x as u32; + let z = y & y; +} +``` + +`z` is implicitly constrained to be the result of `y & y`. The `&` operand is used to denote bitwise +`&`. + +> `x & x` would not compile as `x` is a `Field` and not an integer type. + +### Logical Operators + +Noir has no support for the logical operators `||` and `&&`. This is because encoding the +short-circuiting that these operators require can be inefficient for Noir's backend. Instead you can +use the bitwise operators `|` and `&` which operate identically for booleans, just without the +short-circuiting. + +```rust +let my_val = 5; + +let mut flag = 1; +if (my_val > 6) | (my_val == 0) { + flag = 0; +} +assert(flag == 1); + +if (my_val != 10) & (my_val < 50) { + flag = 0; +} +assert(flag == 0); +``` + +### Shorthand operators + +Noir shorthand operators for most of the above operators, namely `+=, -=, *=, /=, %=, &=, |=, ^=, <<=`, and `>>=`. These allow for more concise syntax. For example: + +```rust +let mut i = 0; +i = i + 1; +``` + +could be written as: + +```rust +let mut i = 0; +i += 1; +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/oracles.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/oracles.md new file mode 100644 index 00000000000..aa380b5f7b8 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/oracles.md @@ -0,0 +1,31 @@ +--- +title: Oracles +description: Dive into how Noir supports Oracles via RPC calls, and learn how to declare an Oracle in Noir with our comprehensive guide. +keywords: + - Noir + - Oracles + - RPC Calls + - Unconstrained Functions + - Programming + - Blockchain +sidebar_position: 6 +--- + +:::note + +This is an experimental feature that is not fully documented. If you notice any outdated information or potential improvements to this page, pull request contributions are very welcome: https://github.com/noir-lang/noir + +::: + +Noir has support for Oracles via RPC calls. This means Noir will make an RPC call and use the return value for proof generation. + +Since Oracles are not resolved by Noir, they are [`unconstrained` functions](./unconstrained.md) + +You can declare an Oracle through the `#[oracle()]` flag. Example: + +```rust +#[oracle(get_number_sequence)] +unconstrained fn get_number_sequence(_size: Field) -> [Field] {} +``` + +The timeout for when using an external RPC oracle resolver can be set with the `NARGO_FOREIGN_CALL_TIMEOUT` environment variable. This timeout is in units of milliseconds. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/shadowing.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/shadowing.md new file mode 100644 index 00000000000..5ce6130d201 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/shadowing.md @@ -0,0 +1,44 @@ +--- +title: Shadowing +sidebar_position: 12 +--- + +Noir allows for inheriting variables' values and re-declaring them with the same name similar to Rust, known as shadowing. + +For example, the following function is valid in Noir: + +```rust +fn main() { + let x = 5; + + { + let x = x * 2; + assert (x == 10); + } + + assert (x == 5); +} +``` + +In this example, a variable x is first defined with the value 5. + +The local scope that follows shadows the original x, i.e. creates a local mutable x based on the value of the original x. It is given a value of 2 times the original x. + +When we return to the main scope, x once again refers to just the original x, which stays at the value of 5. + +## Temporal mutability + +One way that shadowing is useful, in addition to ergonomics across scopes, is for temporarily mutating variables. + +```rust +fn main() { + let age = 30; + // age = age + 5; // Would error as `age` is immutable by default. + + let mut age = age + 5; // Temporarily mutates `age` with a new value. + + let age = age; // Locks `age`'s mutability again. + + assert (age == 35); +} +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/traits.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/traits.md new file mode 100644 index 00000000000..ef1445a5907 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/traits.md @@ -0,0 +1,389 @@ +--- +title: Traits +description: + Traits in Noir can be used to abstract out a common interface for functions across + several data types. +keywords: [noir programming language, traits, interfaces, generic, protocol] +sidebar_position: 14 +--- + +## Overview + +Traits in Noir are a useful abstraction similar to interfaces or protocols in other languages. Each trait defines +the interface of several methods contained within the trait. Types can then implement this trait by providing +implementations for these methods. For example in the program: + +```rust +struct Rectangle { + width: Field, + height: Field, +} + +impl Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +fn log_area(r: Rectangle) { + println(r.area()); +} +``` + +We have a function `log_area` to log the area of a `Rectangle`. Now how should we change the program if we want this +function to work on `Triangle`s as well?: + +```rust +struct Triangle { + width: Field, + height: Field, +} + +impl Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Making `log_area` generic over all types `T` would be invalid since not all types have an `area` method. Instead, we can +introduce a new `Area` trait and make `log_area` generic over all types `T` that implement `Area`: + +```rust +trait Area { + fn area(self) -> Field; +} + +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +We also need to explicitly implement `Area` for `Rectangle` and `Triangle`. We can do that by changing their existing +impls slightly. Note that the parameter types and return type of each of our `area` methods must match those defined +by the `Area` trait. + +```rust +impl Area for Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +impl Area for Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Now we have a working program that is generic over any type of Shape that is used! Others can even use this program +as a library with their own types - such as `Circle` - as long as they also implement `Area` for these types. + +## Where Clauses + +As seen in `log_area` above, when we want to create a function or method that is generic over any type that implements +a trait, we can add a where clause to the generic function. + +```rust +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +It is also possible to apply multiple trait constraints on the same variable at once by combining traits with the `+` +operator. Similarly, we can have multiple trait constraints by separating each with a comma: + +```rust +fn foo(elements: [T], thing: U) where + T: Default + Add + Eq, + U: Bar, +{ + let mut sum = T::default(); + + for element in elements { + sum += element; + } + + if sum == T::default() { + thing.bar(); + } +} +``` + +## Generic Implementations + +You can add generics to a trait implementation by adding the generic list after the `impl` keyword: + +```rust +trait Second { + fn second(self) -> Field; +} + +impl Second for (T, Field) { + fn second(self) -> Field { + self.1 + } +} +``` + +You can also implement a trait for every type this way: + +```rust +trait Debug { + fn debug(self); +} + +impl Debug for T { + fn debug(self) { + println(self); + } +} + +fn main() { + 1.debug(); +} +``` + +### Generic Trait Implementations With Where Clauses + +Where clauses can also be placed on trait implementations themselves to restrict generics in a similar way. +For example, while `impl Foo for T` implements the trait `Foo` for every type, `impl Foo for T where T: Bar` +will implement `Foo` only for types that also implement `Bar`. This is often used for implementing generic types. +For example, here is the implementation for array equality: + +```rust +impl Eq for [T; N] where T: Eq { + // Test if two arrays have the same elements. + // Because both arrays must have length N, we know their lengths already match. + fn eq(self, other: Self) -> bool { + let mut result = true; + + for i in 0 .. self.len() { + // The T: Eq constraint is needed to call == on the array elements here + result &= self[i] == other[i]; + } + + result + } +} +``` + +## Generic Traits + +Traits themselves can also be generic by placing the generic arguments after the trait name. These generics are in +scope of every item within the trait. + +```rust +trait Into { + // Convert `self` to type `T` + fn into(self) -> T; +} +``` + +When implementing generic traits the generic arguments of the trait must be specified. This is also true anytime +when referencing a generic trait (e.g. in a `where` clause). + +```rust +struct MyStruct { + array: [Field; 2], +} + +impl Into<[Field; 2]> for MyStruct { + fn into(self) -> [Field; 2] { + self.array + } +} + +fn as_array(x: T) -> [Field; 2] + where T: Into<[Field; 2]> +{ + x.into() +} + +fn main() { + let array = [1, 2]; + let my_struct = MyStruct { array }; + + assert_eq(as_array(my_struct), array); +} +``` + +## Trait Methods With No `self` + +A trait can contain any number of methods, each of which have access to the `Self` type which represents each type +that eventually implements the trait. Similarly, the `self` variable is available as well but is not required to be used. +For example, we can define a trait to create a default value for a type. This trait will need to return the `Self` type +but doesn't need to take any parameters: + +```rust +trait Default { + fn default() -> Self; +} +``` + +Implementing this trait can be done similarly to any other trait: + +```rust +impl Default for Field { + fn default() -> Field { + 0 + } +} + +struct MyType {} + +impl Default for MyType { + fn default() -> Field { + MyType {} + } +} +``` + +However, since there is no `self` parameter, we cannot call it via the method call syntax `object.method()`. +Instead, we'll need to refer to the function directly. This can be done either by referring to the +specific impl `MyType::default()` or referring to the trait itself `Default::default()`. In the later +case, type inference determines the impl that is selected. + +```rust +let my_struct = MyStruct::default(); + +let x: Field = Default::default(); +let result = x + Default::default(); +``` + +:::warning + +```rust +let _ = Default::default(); +``` + +If type inference cannot select which impl to use because of an ambiguous `Self` type, an impl will be +arbitrarily selected. This occurs most often when the result of a trait function call with no parameters +is unused. To avoid this, when calling a trait function with no `self` or `Self` parameters or return type, +always refer to it via the implementation type's namespace - e.g. `MyType::default()`. +This is set to change to an error in future Noir versions. + +::: + +## Default Method Implementations + +A trait can also have default implementations of its methods by giving a body to the desired functions. +Note that this body must be valid for all types that may implement the trait. As a result, the only +valid operations on `self` will be operations valid for any type or other operations on the trait itself. + +```rust +trait Numeric { + fn add(self, other: Self) -> Self; + + // Default implementation of double is (self + self) + fn double(self) -> Self { + self.add(self) + } +} +``` + +When implementing a trait with default functions, a type may choose to implement only the required functions: + +```rust +impl Numeric for Field { + fn add(self, other: Field) -> Field { + self + other + } +} +``` + +Or it may implement the optional methods as well: + +```rust +impl Numeric for u32 { + fn add(self, other: u32) -> u32 { + self + other + } + + fn double(self) -> u32 { + self * 2 + } +} +``` + +## Impl Specialization + +When implementing traits for a generic type it is possible to implement the trait for only a certain combination +of generics. This can be either as an optimization or because those specific generics are required to implement the trait. + +```rust +trait Sub { + fn sub(self, other: Self) -> Self; +} + +struct NonZero { + value: T, +} + +impl Sub for NonZero { + fn sub(self, other: Self) -> Self { + let value = self.value - other.value; + assert(value != 0); + NonZero { value } + } +} +``` + +## Overlapping Implementations + +Overlapping implementations are disallowed by Noir to ensure Noir's decision on which impl to select is never ambiguous. +This means if a trait `Foo` is already implemented +by a type `Bar` for all `T`, then we cannot also have a separate impl for `Bar` (or any other +type argument). Similarly, if there is an impl for all `T` such as `impl Debug for T`, we cannot create +any more impls to `Debug` for other types since it would be ambiguous which impl to choose for any given +method call. + +```rust +trait Trait {} + +// Previous impl defined here +impl Trait for (A, B) {} + +// error: Impl for type `(Field, Field)` overlaps with existing impl +impl Trait for (Field, Field) {} +``` + +## Trait Coherence + +Another restriction on trait implementations is coherence. This restriction ensures other crates cannot create +impls that may overlap with other impls, even if several unrelated crates are used as dependencies in the same +program. + +The coherence restriction is: to implement a trait, either the trait itself or the object type must be declared +in the crate the impl is in. + +In practice this often comes up when using types provided by libraries. If a library provides a type `Foo` that does +not implement a trait in the standard library such as `Default`, you may not `impl Default for Foo` in your own crate. +While restrictive, this prevents later issues or silent changes in the program if the `Foo` library later added its +own impl for `Default`. If you are a user of the `Foo` library in this scenario and need a trait not implemented by the +library your choices are to either submit a patch to the library or use the newtype pattern. + +### The Newtype Pattern + +The newtype pattern gets around the coherence restriction by creating a new wrapper type around the library type +that we cannot create `impl`s for. Since the new wrapper type is defined in our current crate, we can create +impls for any trait we need on it. + +```rust +struct Wrapper { + foo: dep::some_library::Foo, +} + +impl Default for Wrapper { + fn default() -> Wrapper { + Wrapper { + foo: dep::some_library::Foo::new(), + } + } +} +``` + +Since we have an impl for our own type, the behavior of this code will not change even if `some_library` is updated +to provide its own `impl Default for Foo`. The downside of this pattern is that it requires extra wrapping and +unwrapping of values when converting to and from the `Wrapper` and `Foo` types. diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/unconstrained.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/unconstrained.md new file mode 100644 index 00000000000..b8e71fe65f0 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/unconstrained.md @@ -0,0 +1,99 @@ +--- +title: Unconstrained Functions +description: "Learn about what unconstrained functions in Noir are, how to use them and when you'd want to." + +keywords: [Noir programming language, unconstrained, open] +sidebar_position: 5 +--- + +Unconstrained functions are functions which do not constrain any of the included computation and allow for non-deterministic computation. + +## Why? + +Zero-knowledge (ZK) domain-specific languages (DSL) enable developers to generate ZK proofs from their programs by compiling code down to the constraints of an NP complete language (such as R1CS or PLONKish languages). However, the hard bounds of a constraint system can be very limiting to the functionality of a ZK DSL. + +Enabling a circuit language to perform unconstrained execution is a powerful tool. Said another way, unconstrained execution lets developers generate witnesses from code that does not generate any constraints. Being able to execute logic outside of a circuit is critical for both circuit performance and constructing proofs on information that is external to a circuit. + +Fetching information from somewhere external to a circuit can also be used to enable developers to improve circuit efficiency. + +A ZK DSL does not just prove computation, but proves that some computation was handled correctly. Thus, it is necessary that when we switch from performing some operation directly inside of a circuit to inside of an unconstrained environment that the appropriate constraints are still laid down elsewhere in the circuit. + +## Example + +An in depth example might help drive the point home. This example comes from the excellent [post](https://discord.com/channels/1113924620781883405/1124022445054111926/1128747641853972590) by Tom in the Noir Discord. + +Let's look at how we can optimize a function to turn a `u72` into an array of `u8`s. + +```rust +fn main(num: u72) -> pub [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8)) as u72 & 0xff) as u8; + } + + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 91 +Backend circuit size: 3619 +``` + +A lot of the operations in this function are optimized away by the compiler (all the bit-shifts turn into divisions by constants). However we can save a bunch of gates by casting to u8 a bit earlier. This automatically truncates the bit-shifted value to fit in a u8 which allows us to remove the AND against 0xff. This saves us ~480 gates in total. + +```rust +fn main(num: u72) -> pub [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8)) as u8; + } + + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 75 +Backend circuit size: 3143 +``` + +Those are some nice savings already but we can do better. This code is all constrained so we're proving every step of calculating out using num, but we don't actually care about how we calculate this, just that it's correct. This is where brillig comes in. + +It turns out that truncating a u72 into a u8 is hard to do inside a snark, each time we do as u8 we lay down 4 ACIR opcodes which get converted into multiple gates. It's actually much easier to calculate num from out than the other way around. All we need to do is multiply each element of out by a constant and add them all together, both relatively easy operations inside a snark. + +We can then run u72_to_u8 as unconstrained brillig code in order to calculate out, then use that result in our constrained function and assert that if we were to do the reverse calculation we'd get back num. This looks a little like the below: + +```rust +fn main(num: u72) -> pub [u8; 8] { + let out = u72_to_u8(num); + + let mut reconstructed_num: u72 = 0; + for i in 0..8 { + reconstructed_num += (out[i] as u72 << (56 - (8 * i))); + } + assert(num == reconstructed_num); + out +} + +unconstrained fn u72_to_u8(num: u72) -> [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8))) as u8; + } + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 78 +Backend circuit size: 2902 +``` + +This ends up taking off another ~250 gates from our circuit! We've ended up with more ACIR opcodes than before but they're easier for the backend to prove (resulting in fewer gates). + +Generally we want to use brillig whenever there's something that's easy to verify but hard to compute within the circuit. For example, if you wanted to calculate a square root of a number it'll be a much better idea to calculate this in brillig and then assert that if you square the result you get back your number. + +## Break and Continue + +In addition to loops over runtime bounds, `break` and `continue` are also available in unconstrained code. See [break and continue](../concepts/control_flow/#break-and-continue) diff --git a/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/_category_.json b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/_category_.json new file mode 100644 index 00000000000..1debcfe7675 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Modules, Packages and Crates", + "position": 2, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/crates_and_packages.md b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/crates_and_packages.md new file mode 100644 index 00000000000..95ee9f52ab2 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/crates_and_packages.md @@ -0,0 +1,43 @@ +--- +title: Crates and Packages +description: Learn how to use Crates and Packages in your Noir project +keywords: [Nargo, dependencies, package management, crates, package] +sidebar_position: 0 +--- + +## Crates + +A crate is the smallest amount of code that the Noir compiler considers at a time. +Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as we’ll see in the coming sections. + +### Crate Types + +A Noir crate can come in several forms: binaries, libraries or contracts. + +#### Binaries + +_Binary crates_ are programs which you can compile to an ACIR circuit which you can then create proofs against. Each must have a function called `main` that defines the ACIR circuit which is to be proved. + +#### Libraries + +_Library crates_ don't have a `main` function and they don't compile down to ACIR. Instead they define functionality intended to be shared with multiple projects, and eventually included in a binary crate. + +#### Contracts + +Contract crates are similar to binary crates in that they compile to ACIR which you can create proofs against. They are different in that they do not have a single `main` function, but are a collection of functions to be deployed to the [Aztec network](https://aztec.network). You can learn more about the technical details of Aztec in the [monorepo](https://github.com/AztecProtocol/aztec-packages) or contract [examples](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/noir-contracts/contracts). + +### Crate Root + +Every crate has a root, which is the source file that the compiler starts, this is also known as the root module. The Noir compiler does not enforce any conditions on the name of the file which is the crate root, however if you are compiling via Nargo the crate root must be called `lib.nr` or `main.nr` for library or binary crates respectively. + +## Packages + +A Nargo _package_ is a collection of one of more crates that provides a set of functionality. A package must include a Nargo.toml file. + +A package _must_ contain either a library or a binary crate, but not both. + +### Differences from Cargo Packages + +One notable difference between Rust's Cargo and Noir's Nargo is that while Cargo allows a package to contain an unlimited number of binary crates and a single library crate, Nargo currently only allows a package to contain a single crate. + +In future this restriction may be lifted to allow a Nargo package to contain both a binary and library crate or multiple binary crates. diff --git a/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/dependencies.md b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/dependencies.md new file mode 100644 index 00000000000..04c1703d929 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/dependencies.md @@ -0,0 +1,124 @@ +--- +title: Dependencies +description: + Learn how to specify and manage dependencies in Nargo, allowing you to upload packages to GitHub + and use them easily in your project. +keywords: [Nargo, dependencies, GitHub, package management, versioning] +sidebar_position: 1 +--- + +Nargo allows you to upload packages to GitHub and use them as dependencies. + +## Specifying a dependency + +Specifying a dependency requires a tag to a specific commit and the git url to the url containing +the package. + +Currently, there are no requirements on the tag contents. If requirements are added, it would follow +semver 2.0 guidelines. + +> Note: Without a `tag` , there would be no versioning and dependencies would change each time you +> compile your project. + +For example, to add the [ecrecover-noir library](https://github.com/colinnielsen/ecrecover-noir) to your project, add it to `Nargo.toml`: + +```toml +# Nargo.toml + +[dependencies] +ecrecover = {tag = "v0.8.0", git = "https://github.com/colinnielsen/ecrecover-noir"} +``` + +If the module is in a subdirectory, you can define a subdirectory in your git repository, for example: + +```toml +# Nargo.toml + +[dependencies] +easy_private_token_contract = {tag ="v0.1.0-alpha62", git = "https://github.com/AztecProtocol/aztec-packages", directory = "noir-contracts/contracts/easy_private_token_contract"} +``` + +## Specifying a local dependency + +You can also specify dependencies that are local to your machine. + +For example, this file structure has a library and binary crate + +```tree +├── binary_crate +│   ├── Nargo.toml +│   └── src +│   └── main.nr +└── lib_a + ├── Nargo.toml + └── src + └── lib.nr +``` + +Inside of the binary crate, you can specify: + +```toml +# Nargo.toml + +[dependencies] +lib_a = { path = "../lib_a" } +``` + +## Importing dependencies + +You can import a dependency to a Noir file using the following syntax. For example, to import the +ecrecover-noir library and local lib_a referenced above: + +```rust +use dep::ecrecover; +use dep::lib_a; +``` + +You can also import only the specific parts of dependency that you want to use, like so: + +```rust +use dep::std::hash::sha256; +use dep::std::scalar_mul::fixed_base_embedded_curve; +``` + +Lastly, as demonstrated in the +[elliptic curve example](../standard_library/cryptographic_primitives/ec_primitives#examples), you +can import multiple items in the same line by enclosing them in curly braces: + +```rust +use dep::std::ec::tecurve::affine::{Curve, Point}; +``` + +We don't have a way to consume libraries from inside a [workspace](./workspaces) as external dependencies right now. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. + +## Dependencies of Dependencies + +Note that when you import a dependency, you also get access to all of the dependencies of that package. + +For example, the [phy_vector](https://github.com/resurgencelabs/phy_vector) library imports an [fraction](https://github.com/resurgencelabs/fraction) library. If you're importing the phy_vector library, then you can access the functions in fractions library like so: + +```rust +use dep::phy_vector; + +fn main(x : Field, y : pub Field) { + //... + let f = phy_vector::fraction::toFraction(true, 2, 1); + //... +} +``` + +## Available Libraries + +Noir does not currently have an official package manager. You can find a list of available Noir libraries in the [awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). + +Some libraries that are available today include: + +- [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library +- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage proof verification (or verification of any trie proof involving 32-byte long keys) +- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing for computations on large unsigned integers +- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and return the source Ethereum address +- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of sparse Merkle trees +- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data type, allowing access to negative numbers on Noir +- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, allowing results that aren't whole numbers diff --git a/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/modules.md b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/modules.md new file mode 100644 index 00000000000..ae822a1cff4 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/modules.md @@ -0,0 +1,105 @@ +--- +title: Modules +description: + Learn how to organize your files using modules in Noir, following the same convention as Rust's + module system. Examples included. +keywords: [Noir, Rust, modules, organizing files, sub-modules] +sidebar_position: 2 +--- + +Noir's module system follows the same convention as the _newer_ version of Rust's module system. + +## Purpose of Modules + +Modules are used to organize files. Without modules all of your code would need to live in a single +file. In Noir, the compiler does not automatically scan all of your files to detect modules. This +must be done explicitly by the developer. + +## Examples + +### Importing a module in the crate root + +Filename : `src/main.nr` + +```rust +mod foo; + +fn main() { + foo::hello_world(); +} +``` + +Filename : `src/foo.nr` + +```rust +fn from_foo() {} +``` + +In the above snippet, the crate root is the `src/main.nr` file. The compiler sees the module +declaration `mod foo` which prompts it to look for a foo.nr file. + +Visually this module hierarchy looks like the following : + +``` +crate + ├── main + │ + └── foo + └── from_foo + +``` + +### Importing a module throughout the tree + +All modules are accessible from the `crate::` namespace. + +``` +crate + ├── bar + ├── foo + └── main + +``` + +In the above snippet, if `bar` would like to use functions in `foo`, it can do so by `use crate::foo::function_name`. + +### Sub-modules + +Filename : `src/main.nr` + +```rust +mod foo; + +fn main() { + foo::from_foo(); +} +``` + +Filename : `src/foo.nr` + +```rust +mod bar; +fn from_foo() {} +``` + +Filename : `src/foo/bar.nr` + +```rust +fn from_bar() {} +``` + +In the above snippet, we have added an extra module to the module tree; `bar`. `bar` is a submodule +of `foo` hence we declare bar in `foo.nr` with `mod bar`. Since `foo` is not the crate root, the +compiler looks for the file associated with the `bar` module in `src/foo/bar.nr` + +Visually the module hierarchy looks as follows: + +``` +crate + ├── main + │ + └── foo + ├── from_foo + └── bar + └── from_bar +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/workspaces.md b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/workspaces.md new file mode 100644 index 00000000000..513497f12bf --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/modules_packages_crates/workspaces.md @@ -0,0 +1,42 @@ +--- +title: Workspaces +sidebar_position: 3 +--- + +Workspaces are a feature of nargo that allow you to manage multiple related Noir packages in a single repository. A workspace is essentially a group of related projects that share common build output directories and configurations. + +Each Noir project (with it's own Nargo.toml file) can be thought of as a package. Each package is expected to contain exactly one "named circuit", being the "name" defined in Nargo.toml with the program logic defined in `./src/main.nr`. + +For a project with the following structure: + +```tree +├── crates +│ ├── a +│ │ ├── Nargo.toml +│ │ └── Prover.toml +│ │ └── src +│ │ └── main.nr +│ └── b +│ ├── Nargo.toml +│ └── Prover.toml +│ └── src +│ └── main.nr +│ +└── Nargo.toml +``` + +You can define a workspace in Nargo.toml like so: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +`members` indicates which packages are included in the workspace. As such, all member packages of a workspace will be processed when the `--workspace` flag is used with various commands or if a `default-member` is not specified. + +`default-member` indicates which package various commands process by default. + +Libraries can be defined in a workspace. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/_category_.json b/docs/versioned_docs/version-v0.29.0/noir/standard_library/_category_.json new file mode 100644 index 00000000000..af04c0933fd --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Standard Library", + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/bigint.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/bigint.md new file mode 100644 index 00000000000..2bfdeec6631 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/bigint.md @@ -0,0 +1,122 @@ +--- +title: Big Integers +description: How to use big integers from Noir standard library +keywords: + [ + Big Integer, + Noir programming language, + Noir libraries, + ] +--- + +The BigInt module in the standard library exposes some class of integers which do not fit (well) into a Noir native field. It implements modulo arithmetic, modulo a 'big' prime number. + +:::note + +The module can currently be considered as `Field`s with fixed modulo sizes used by a set of elliptic curves, in addition to just the native curve. [More work](https://github.com/noir-lang/noir/issues/510) is needed to achieve arbitrarily sized big integers. + +::: + +Currently 6 classes of integers (i.e 'big' prime numbers) are available in the module, namely: + +- BN254 Fq: Bn254Fq +- BN254 Fr: Bn254Fr +- Secp256k1 Fq: Secpk1Fq +- Secp256k1 Fr: Secpk1Fr +- Secp256r1 Fr: Secpr1Fr +- Secp256r1 Fq: Secpr1Fq + +Where XXX Fq and XXX Fr denote respectively the order of the base and scalar field of the (usual) elliptic curve XXX. +For instance the big integer 'Secpk1Fq' in the standard library refers to integers modulo $2^{256}-2^{32}-977$. + +Feel free to explore the source code for the other primes: + +```rust title="big_int_definition" showLineNumbers +struct BigInt { + pointer: u32, + modulus: u32, +} +``` +> Source code: noir_stdlib/src/bigint.nr#L14-L19 + + +## Example usage + +A common use-case is when constructing a big integer from its bytes representation, and performing arithmetic operations on it: + +```rust title="big_int_example" showLineNumbers +fn big_int_example(x: u8, y: u8) { + let a = Secpk1Fq::from_le_bytes(&[x, y, 0, 45, 2]); + let b = Secpk1Fq::from_le_bytes(&[y, x, 9]); + let c = (a + b) * b / a; + let d = c.to_le_bytes(); + println(d[0]); +} +``` +> Source code: test_programs/execution_success/bigint/src/main.nr#L70-L78 + + +## Methods + +The available operations for each big integer are: + +### from_le_bytes + +Construct a big integer from its little-endian bytes representation. Example: + +```rust + // Construct a big integer from a slice of bytes + let a = Secpk1Fq::from_le_bytes(&[x, y, 0, 45, 2]); + // Construct a big integer from an array of 32 bytes + let a = Secpk1Fq::from_le_bytes_32([1;32]); + ``` + +Sure, here's the formatted version of the remaining methods: + +### to_le_bytes + +Return the little-endian bytes representation of a big integer. Example: + +```rust +let bytes = a.to_le_bytes(); +``` + +### add + +Add two big integers. Example: + +```rust +let sum = a + b; +``` + +### sub + +Subtract two big integers. Example: + +```rust +let difference = a - b; +``` + +### mul + +Multiply two big integers. Example: + +```rust +let product = a * b; +``` + +### div + +Divide two big integers. Note that division is field division and not euclidean division. Example: + +```rust +let quotient = a / b; +``` + +### eq + +Compare two big integers. Example: + +```rust +let are_equal = a == b; +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/black_box_fns.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/black_box_fns.md new file mode 100644 index 00000000000..be8c65679c3 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/black_box_fns.md @@ -0,0 +1,31 @@ +--- +title: Black Box Functions +description: Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. +keywords: [noir, black box functions] +--- + +Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. This makes certain zk-snark unfriendly computations cheaper than if they were implemented in Noir. + +The ACVM spec defines a set of blackbox functions which backends will be expected to implement. This allows backends to use optimized implementations of these constraints if they have them, however they may also fallback to less efficient naive implementations if not. + +## Function list + +Here is a list of the current black box functions: + +- [SHA256](./cryptographic_primitives/hashes.mdx#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr.mdx) +- [Blake2s](./cryptographic_primitives/hashes.mdx#blake2s) +- [Blake3](./cryptographic_primitives/hashes.mdx#blake3) +- [Pedersen Hash](./cryptographic_primitives/hashes.mdx#pedersen_hash) +- [Pedersen Commitment](./cryptographic_primitives/hashes.mdx#pedersen_commitment) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification.mdx) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar.mdx) +- AND +- XOR +- RANGE +- [Keccak256](./cryptographic_primitives/hashes.mdx#keccak256) +- [Recursive proof verification](./recursion) + +Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. + +You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/noir/blob/master/acvm-repo/acir/src/circuit/black_box_functions.rs). diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/bn254.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/bn254.md new file mode 100644 index 00000000000..3294f005dbb --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/bn254.md @@ -0,0 +1,46 @@ +--- +title: Bn254 Field Library +--- + +Noir provides a module in standard library with some optimized functions for bn254 Fr in `std::field::bn254`. + +## decompose + +```rust +fn decompose(x: Field) -> (Field, Field) {} +``` + +Decomposes a single field into two fields, low and high. The low field contains the lower 16 bytes of the input field and the high field contains the upper 16 bytes of the input field. Both field results are range checked to 128 bits. + + +## assert_gt + +```rust +fn assert_gt(a: Field, b: Field) {} +``` + +Asserts that a > b. This will generate less constraints than using `assert(gt(a, b))`. + +## assert_lt + +```rust +fn assert_lt(a: Field, b: Field) {} +``` + +Asserts that a < b. This will generate less constraints than using `assert(lt(a, b))`. + +## gt + +```rust +fn gt(a: Field, b: Field) -> bool {} +``` + +Returns true if a > b. + +## lt + +```rust +fn lt(a: Field, b: Field) -> bool {} +``` + +Returns true if a < b. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/boundedvec.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/boundedvec.md new file mode 100644 index 00000000000..ce4529f6e57 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/boundedvec.md @@ -0,0 +1,326 @@ +--- +title: Bounded Vectors +keywords: [noir, vector, bounded vector, slice] +sidebar_position: 1 +--- + +A `BoundedVec` is a growable storage similar to a `Vec` except that it +is bounded with a maximum possible length. Unlike `Vec`, `BoundedVec` is not implemented +via slices and thus is not subject to the same restrictions slices are (notably, nested +slices - and thus nested vectors as well - are disallowed). + +Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by +pushing an additional element is also more efficient - the length only needs to be increased +by one. + +For these reasons `BoundedVec` should generally be preferred over `Vec` when there +is a reasonable maximum bound that can be placed on the vector. + +Example: + +```rust +let mut vector: BoundedVec = BoundedVec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +assert(vector.max_len() == 10); +``` + +## Methods + +### new + +```rust +pub fn new() -> Self +``` + +Creates a new, empty vector of length zero. + +Since this container is backed by an array internally, it still needs an initial value +to give each element. To resolve this, each element is zeroed internally. This value +is guaranteed to be inaccessible unless `get_unchecked` is used. + +Example: + +```rust +let empty_vector: BoundedVec = BoundedVec::new(); +assert(empty_vector.len() == 0); +``` + +Note that whenever calling `new` the maximum length of the vector should always be specified +via a type signature: + +```rust title="new_example" showLineNumbers +fn foo() -> BoundedVec { + // Ok! MaxLen is specified with a type annotation + let v1: BoundedVec = BoundedVec::new(); + let v2 = BoundedVec::new(); + + // Ok! MaxLen is known from the type of foo's return value + v2 +} + +fn bad() { + let mut v3 = BoundedVec::new(); + + // Not Ok! We don't know if v3's MaxLen is at least 1, and the compiler often infers 0 by default. + v3.push(5); +} +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L11-L27 + + +This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions +but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a constraint failure at runtime when the vec is pushed to. + +### get + +```rust +pub fn get(mut self: Self, index: u64) -> T { +``` + +Retrieves an element from the vector at the given index, starting from zero. + +If the given index is equal to or greater than the length of the vector, this +will issue a constraint failure. + +Example: + +```rust +fn foo(v: BoundedVec) { + let first = v.get(0); + let last = v.get(v.len() - 1); + assert(first != last); +} +``` + +### get_unchecked + +```rust +pub fn get_unchecked(mut self: Self, index: u64) -> T { +``` + +Retrieves an element from the vector at the given index, starting from zero, without +performing a bounds check. + +Since this function does not perform a bounds check on length before accessing the element, +it is unsafe! Use at your own risk! + +Example: + +```rust title="get_unchecked_example" showLineNumbers +fn sum_of_first_three(v: BoundedVec) -> u32 { + // Always ensure the length is larger than the largest + // index passed to get_unchecked + assert(v.len() > 2); + let first = v.get_unchecked(0); + let second = v.get_unchecked(1); + let third = v.get_unchecked(2); + first + second + third +} +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L54-L64 + + + +### push + +```rust +pub fn push(&mut self, elem: T) { +``` + +Pushes an element to the end of the vector. This increases the length +of the vector by one. + +Panics if the new length of the vector will be greater than the max length. + +Example: + +```rust title="bounded-vec-push-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + + v.push(1); + v.push(2); + + // Panics with failed assertion "push out of bounds" + v.push(3); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L68-L76 + + +### pop + +```rust +pub fn pop(&mut self) -> T +``` + +Pops the element at the end of the vector. This will decrease the length +of the vector by one. + +Panics if the vector is empty. + +Example: + +```rust title="bounded-vec-pop-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + v.push(1); + v.push(2); + + let two = v.pop(); + let one = v.pop(); + + assert(two == 2); + assert(one == 1); + // error: cannot pop from an empty vector + // let _ = v.pop(); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L81-L93 + + +### len + +```rust +pub fn len(self) -> u64 { +``` + +Returns the current length of this vector + +Example: + +```rust title="bounded-vec-len-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + assert(v.len() == 0); + + v.push(100); + assert(v.len() == 1); + + v.push(200); + v.push(300); + v.push(400); + assert(v.len() == 4); + + let _ = v.pop(); + let _ = v.pop(); + assert(v.len() == 2); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L98-L113 + + +### max_len + +```rust +pub fn max_len(_self: BoundedVec) -> u64 { +``` + +Returns the maximum length of this vector. This is always +equal to the `MaxLen` parameter this vector was initialized with. + +Example: + +```rust title="bounded-vec-max-len-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + + assert(v.max_len() == 5); + v.push(10); + assert(v.max_len() == 5); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L118-L124 + + +### storage + +```rust +pub fn storage(self) -> [T; MaxLen] { +``` + +Returns the internal array within this vector. +Since arrays in Noir are immutable, mutating the returned storage array will not mutate +the storage held internally by this vector. + +Note that uninitialized elements may be zeroed out! + +Example: + +```rust title="bounded-vec-storage-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + + assert(v.storage() == [0, 0, 0, 0, 0]); + + v.push(57); + assert(v.storage() == [57, 0, 0, 0, 0]); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L129-L136 + + +### extend_from_array + +```rust +pub fn extend_from_array(&mut self, array: [T; Len]) +``` + +Pushes each element from the given array to this vector. + +Panics if pushing each element would cause the length of this vector +to exceed the maximum length. + +Example: + +```rust title="bounded-vec-extend-from-array-example" showLineNumbers +let mut vec: BoundedVec = BoundedVec::new(); + vec.extend_from_array([2, 4]); + + assert(vec.len == 2); + assert(vec.get(0) == 2); + assert(vec.get(1) == 4); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L141-L148 + + +### extend_from_bounded_vec + +```rust +pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) +``` + +Pushes each element from the other vector to this vector. The length of +the other vector is left unchanged. + +Panics if pushing each element would cause the length of this vector +to exceed the maximum length. + +Example: + +```rust title="bounded-vec-extend-from-bounded-vec-example" showLineNumbers +let mut v1: BoundedVec = BoundedVec::new(); + let mut v2: BoundedVec = BoundedVec::new(); + + v2.extend_from_array([1, 2, 3]); + v1.extend_from_bounded_vec(v2); + + assert(v1.storage() == [1, 2, 3, 0, 0]); + assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L153-L162 + + +### any + +```rust +pub fn any(self, predicate: fn[Env](T) -> bool) -> bool +``` + +Returns true if the given predicate returns true for any element +in this vector. + +Example: + +```rust title="bounded-vec-any-example" showLineNumbers +let mut v: BoundedVec = BoundedVec::new(); + v.extend_from_array([2, 4, 6]); + + let all_even = !v.any(|elem: u32| elem % 2 != 0); + assert(all_even); +``` +> Source code: test_programs/noir_test_success/bounded_vec/src/main.nr#L229-L235 + diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/hashmap.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/hashmap.md new file mode 100644 index 00000000000..47faa99aba6 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/hashmap.md @@ -0,0 +1,570 @@ +--- +title: HashMap +keywords: [noir, map, hash, hashmap] +sidebar_position: 1 +--- + +`HashMap` is used to efficiently store and look up key-value pairs. + +`HashMap` is a bounded type which can store anywhere from zero to `MaxLen` total elements. +Note that due to hash collisions, the actual maximum number of elements stored by any particular +hashmap is likely lower than `MaxLen`. This is true even with cryptographic hash functions since +every hash value will be performed modulo `MaxLen`. + +When creating `HashMap`s, the `MaxLen` generic should always be specified if it is not already +known. Otherwise, the compiler may infer a different value for `MaxLen` (such as zero), which +will likely change the result of the program. This behavior is set to become an error in future +versions instead. + +Example: + +```rust +// Create a mapping from Fields to u32s with a maximum length of 12 +// using a poseidon2 hasher +use dep::std::hash::poseidon2::Poseidon2Hasher; +let mut map: HashMap> = HashMap::default(); + +map.insert(1, 2); +map.insert(3, 4); + +let two = map.get(1).unwrap(); +``` + +## Methods + +### default + +```rust title="default" showLineNumbers +impl Default for HashMap +where + B: BuildHasher + Default, + H: Hasher + Default +{ + fn default() -> Self { +``` +> Source code: noir_stdlib/src/collections/map.nr#L462-L469 + + +Creates a fresh, empty HashMap. + +When using this function, always make sure to specify the maximum size of the hash map. + +This is the same `default` from the `Default` implementation given further below. It is +repeated here for convenience since it is the recommended way to create a hashmap. + +Example: + +```rust title="default_example" showLineNumbers +let hashmap: HashMap> = HashMap::default(); + assert(hashmap.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L202-L205 + + +Because `HashMap` has so many generic arguments that are likely to be the same throughout +your program, it may be helpful to create a type alias: + +```rust title="type_alias" showLineNumbers +type MyMap = HashMap>; +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L196-L198 + + +### with_hasher + +```rust title="with_hasher" showLineNumbers +pub fn with_hasher(_build_hasher: B) -> Self + where + B: BuildHasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L82-L86 + + +Creates a hashmap with an existing `BuildHasher`. This can be used to ensure multiple +hashmaps are created with the same hasher instance. + +Example: + +```rust title="with_hasher_example" showLineNumbers +let my_hasher: BuildHasherDefault = Default::default(); + let hashmap: HashMap> = HashMap::with_hasher(my_hasher); + assert(hashmap.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L207-L211 + + +### get + +```rust title="get" showLineNumbers +pub fn get( + self, + key: K + ) -> Option + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L278-L287 + + +Retrieves a value from the hashmap, returning `Option::none()` if it was not found. + +Example: + +```rust title="get_example" showLineNumbers +fn get_example(map: HashMap>) { + let x = map.get(12); + + if x.is_some() { + assert(x.unwrap() == 42); + } +} +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L299-L307 + + +### insert + +```rust title="insert" showLineNumbers +pub fn insert( + &mut self, + key: K, + value: V + ) + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L313-L323 + + +Inserts a new key-value pair into the map. If the key was already in the map, its +previous value will be overridden with the newly provided one. + +Example: + +```rust title="insert_example" showLineNumbers +let mut map: HashMap> = HashMap::default(); + map.insert(12, 42); + assert(map.len() == 1); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L213-L217 + + +### remove + +```rust title="remove" showLineNumbers +pub fn remove( + &mut self, + key: K + ) + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L356-L365 + + +Removes the given key-value pair from the map. If the key was not already present +in the map, this does nothing. + +Example: + +```rust title="remove_example" showLineNumbers +map.remove(12); + assert(map.is_empty()); + + // If a key was not present in the map, remove does nothing + map.remove(12); + assert(map.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L221-L228 + + +### is_empty + +```rust title="is_empty" showLineNumbers +pub fn is_empty(self) -> bool { +``` +> Source code: noir_stdlib/src/collections/map.nr#L115-L117 + + +True if the length of the hash map is empty. + +Example: + +```rust title="is_empty_example" showLineNumbers +assert(map.is_empty()); + + map.insert(1, 2); + assert(!map.is_empty()); + + map.remove(1); + assert(map.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L230-L238 + + +### len + +```rust title="len" showLineNumbers +pub fn len(self) -> u64 { +``` +> Source code: noir_stdlib/src/collections/map.nr#L264-L266 + + +Returns the current length of this hash map. + +Example: + +```rust title="len_example" showLineNumbers +// This is equivalent to checking map.is_empty() + assert(map.len() == 0); + + map.insert(1, 2); + map.insert(3, 4); + map.insert(5, 6); + assert(map.len() == 3); + + // 3 was already present as a key in the hash map, so the length is unchanged + map.insert(3, 7); + assert(map.len() == 3); + + map.remove(1); + assert(map.len() == 2); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L240-L255 + + +### capacity + +```rust title="capacity" showLineNumbers +pub fn capacity(_self: Self) -> u64 { +``` +> Source code: noir_stdlib/src/collections/map.nr#L271-L273 + + +Returns the maximum capacity of this hashmap. This is always equal to the capacity +specified in the hashmap's type. + +Unlike hashmaps in general purpose programming languages, hashmaps in Noir have a +static capacity that does not increase as the map grows larger. Thus, this capacity +is also the maximum possible element count that can be inserted into the hashmap. +Due to hash collisions (modulo the hashmap length), it is likely the actual maximum +element count will be lower than the full capacity. + +Example: + +```rust title="capacity_example" showLineNumbers +let empty_map: HashMap> = HashMap::default(); + assert(empty_map.len() == 0); + assert(empty_map.capacity() == 42); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L257-L261 + + +### clear + +```rust title="clear" showLineNumbers +pub fn clear(&mut self) { +``` +> Source code: noir_stdlib/src/collections/map.nr#L93-L95 + + +Clears the hashmap, removing all key-value pairs from it. + +Example: + +```rust title="clear_example" showLineNumbers +assert(!map.is_empty()); + map.clear(); + assert(map.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L263-L267 + + +### contains_key + +```rust title="contains_key" showLineNumbers +pub fn contains_key( + self, + key: K + ) -> bool + where + K: Hash + Eq, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L101-L110 + + +True if the hashmap contains the given key. Unlike `get`, this will not also return +the value associated with the key. + +Example: + +```rust title="contains_key_example" showLineNumbers +if map.contains_key(7) { + let value = map.get(7); + assert(value.is_some()); + } else { + println("No value for key 7!"); + } +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L269-L276 + + +### entries + +```rust title="entries" showLineNumbers +pub fn entries(self) -> BoundedVec<(K, V), N> { +``` +> Source code: noir_stdlib/src/collections/map.nr#L123-L125 + + +Returns a vector of each key-value pair present in the hashmap. + +The length of the returned vector is always equal to the length of the hashmap. + +Example: + +```rust title="entries_example" showLineNumbers +let entries = map.entries(); + + // The length of a hashmap may not be compile-time known, so we + // need to loop over its capacity instead + for i in 0..map.capacity() { + if i < entries.len() { + let (key, value) = entries.get(i); + println(f"{key} -> {value}"); + } + } +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L310-L321 + + +### keys + +```rust title="keys" showLineNumbers +pub fn keys(self) -> BoundedVec { +``` +> Source code: noir_stdlib/src/collections/map.nr#L144-L146 + + +Returns a vector of each key present in the hashmap. + +The length of the returned vector is always equal to the length of the hashmap. + +Example: + +```rust title="keys_example" showLineNumbers +let keys = map.keys(); + + for i in 0..keys.max_len() { + if i < keys.len() { + let key = keys.get_unchecked(i); + let value = map.get(key).unwrap_unchecked(); + println(f"{key} -> {value}"); + } + } +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L323-L333 + + +### values + +```rust title="values" showLineNumbers +pub fn values(self) -> BoundedVec { +``` +> Source code: noir_stdlib/src/collections/map.nr#L164-L166 + + +Returns a vector of each value present in the hashmap. + +The length of the returned vector is always equal to the length of the hashmap. + +Example: + +```rust title="values_example" showLineNumbers +let values = map.values(); + + for i in 0..values.max_len() { + if i < values.len() { + let value = values.get_unchecked(i); + println(f"Found value {value}"); + } + } +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L335-L344 + + +### iter_mut + +```rust title="iter_mut" showLineNumbers +pub fn iter_mut( + &mut self, + f: fn(K, V) -> (K, V) + ) + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L183-L192 + + +Iterates through each key-value pair of the HashMap, setting each key-value pair to the +result returned from the given function. + +Note that since keys can be mutated, the HashMap needs to be rebuilt as it is iterated +through. If this is not desired, use `iter_values_mut` if only values need to be mutated, +or `entries` if neither keys nor values need to be mutated. + +The iteration order is left unspecified. As a result, if two keys are mutated to become +equal, which of the two values that will be present for the key in the resulting map is also unspecified. + +Example: + +```rust title="iter_mut_example" showLineNumbers +// Add 1 to each key in the map, and double the value associated with that key. + map.iter_mut(|k, v| (k + 1, v * 2)); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L348-L351 + + +### iter_keys_mut + +```rust title="iter_keys_mut" showLineNumbers +pub fn iter_keys_mut( + &mut self, + f: fn(K) -> K + ) + where + K: Eq + Hash, + B: BuildHasher, + H: Hasher { +``` +> Source code: noir_stdlib/src/collections/map.nr#L208-L217 + + +Iterates through the HashMap, mutating each key to the result returned from +the given function. + +Note that since keys can be mutated, the HashMap needs to be rebuilt as it is iterated +through. If only iteration is desired and the keys are not intended to be mutated, +prefer using `entries` instead. + +The iteration order is left unspecified. As a result, if two keys are mutated to become +equal, which of the two values that will be present for the key in the resulting map is also unspecified. + +Example: + +```rust title="iter_keys_mut_example" showLineNumbers +// Double each key, leaving the value associated with that key untouched + map.iter_keys_mut(|k| k * 2); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L353-L356 + + +### iter_values_mut + +```rust title="iter_values_mut" showLineNumbers +pub fn iter_values_mut(&mut self, f: fn(V) -> V) { +``` +> Source code: noir_stdlib/src/collections/map.nr#L233-L235 + + +Iterates through the HashMap, applying the given function to each value and mutating the +value to equal the result. This function is more efficient than `iter_mut` and `iter_keys_mut` +because the keys are untouched and the underlying hashmap thus does not need to be reordered. + +Example: + +```rust title="iter_values_mut_example" showLineNumbers +// Halve each value + map.iter_values_mut(|v| v / 2); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L358-L361 + + +### retain + +```rust title="retain" showLineNumbers +pub fn retain(&mut self, f: fn(K, V) -> bool) { +``` +> Source code: noir_stdlib/src/collections/map.nr#L247-L249 + + +Retains only the key-value pairs for which the given function returns true. +Any key-value pairs for which the function returns false will be removed from the map. + +Example: + +```rust title="retain_example" showLineNumbers +map.retain(|k, v| (k != 0) & (v != 0)); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L281-L283 + + +## Trait Implementations + +### default + +```rust title="default" showLineNumbers +impl Default for HashMap +where + B: BuildHasher + Default, + H: Hasher + Default +{ + fn default() -> Self { +``` +> Source code: noir_stdlib/src/collections/map.nr#L462-L469 + + +Constructs an empty HashMap. + +Example: + +```rust title="default_example" showLineNumbers +let hashmap: HashMap> = HashMap::default(); + assert(hashmap.is_empty()); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L202-L205 + + +### eq + +```rust title="eq" showLineNumbers +impl Eq for HashMap +where + K: Eq + Hash, + V: Eq, + B: BuildHasher, + H: Hasher +{ + fn eq(self, other: HashMap) -> bool { +``` +> Source code: noir_stdlib/src/collections/map.nr#L426-L435 + + +Checks if two HashMaps are equal. + +Example: + +```rust title="eq_example" showLineNumbers +let mut map1: HashMap> = HashMap::default(); + let mut map2: HashMap> = HashMap::default(); + + map1.insert(1, 2); + map1.insert(3, 4); + + map2.insert(3, 4); + map2.insert(1, 2); + + assert(map1 == map2); +``` +> Source code: test_programs/execution_success/hashmap/src/main.nr#L285-L296 + diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/index.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/index.md new file mode 100644 index 00000000000..ea84c6d5c21 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/index.md @@ -0,0 +1,5 @@ +--- +title: Containers +description: Container types provided by Noir's standard library for storing and retrieving data +keywords: [containers, data types, vec, hashmap] +--- diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/vec.mdx b/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/vec.mdx new file mode 100644 index 00000000000..fcfd7e07aa0 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/containers/vec.mdx @@ -0,0 +1,151 @@ +--- +title: Vectors +description: Delve into the Vec data type in Noir. Learn about its methods, practical examples, and best practices for using Vectors in your Noir code. +keywords: [noir, vector type, methods, examples, dynamic arrays] +sidebar_position: 6 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A vector is a collection type similar to Rust's `Vec` type. In Noir, it is a convenient way to use slices as mutable arrays. + +Example: + +```rust +let mut vector: Vec = Vec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +``` + +## Methods + +### new + +Creates a new, empty vector. + +```rust +pub fn new() -> Self +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` + +### from_slice + +Creates a vector containing each element from a given slice. Mutations to the resulting vector will not affect the original slice. + +```rust +pub fn from_slice(slice: [T]) -> Self +``` + +Example: + +```rust +let slice: [Field] = &[1, 2, 3]; +let vector_from_slice = Vec::from_slice(slice); +assert(vector_from_slice.len() == 3); +``` + +### len + +Returns the number of elements in the vector. + +```rust +pub fn len(self) -> Field +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` + +### get + +Retrieves an element from the vector at a given index. Panics if the index points beyond the vector's end. + +```rust +pub fn get(self, index: Field) -> T +``` + +Example: + +```rust +let vector: Vec = Vec::from_slice(&[10, 20, 30]); +assert(vector.get(1) == 20); +``` + +### push + +Adds a new element to the vector's end, returning a new vector with a length one greater than the original unmodified vector. + +```rust +pub fn push(&mut self, elem: T) +``` + +Example: + +```rust +let mut vector: Vec = Vec::new(); +vector.push(10); +assert(vector.len() == 1); +``` + +### pop + +Removes an element from the vector's end, returning a new vector with a length one less than the original vector, along with the removed element. Panics if the vector's length is zero. + +```rust +pub fn pop(&mut self) -> T +``` + +Example: + +```rust +let mut vector = Vec::from_slice(&[10, 20]); +let popped_elem = vector.pop(); +assert(popped_elem == 20); +assert(vector.len() == 1); +``` + +### insert + +Inserts an element at a specified index, shifting subsequent elements to the right. + +```rust +pub fn insert(&mut self, index: Field, elem: T) +``` + +Example: + +```rust +let mut vector = Vec::from_slice(&[10, 30]); +vector.insert(1, 20); +assert(vector.get(1) == 20); +``` + +### remove + +Removes an element at a specified index, shifting subsequent elements to the left, and returns the removed element. + +```rust +pub fn remove(&mut self, index: Field) -> T +``` + +Example: + +```rust +let mut vector = Vec::from_slice(&[10, 20, 30]); +let removed_elem = vector.remove(1); +assert(removed_elem == 20); +assert(vector.len() == 2); +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/_category_.json b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/ec_primitives.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/ec_primitives.md new file mode 100644 index 00000000000..d2b42d67b7c --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/ec_primitives.md @@ -0,0 +1,102 @@ +--- +title: Elliptic Curve Primitives +keywords: [cryptographic primitives, Noir project] +sidebar_position: 4 +--- + +Data structures and methods on them that allow you to carry out computations involving elliptic +curves over the (mathematical) field corresponding to `Field`. For the field currently at our +disposal, applications would involve a curve embedded in BN254, e.g. the +[Baby Jubjub curve](https://eips.ethereum.org/EIPS/eip-2494). + +## Data structures + +### Elliptic curve configurations + +(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Curve`), i.e. the specific elliptic +curve you want to use, which would be specified using any one of the methods +`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::new` which take the coefficients in the +defining equation together with a generator point as parameters. You can find more detail in the +comments in +[`noir_stdlib/src/ec.nr`](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr), but +the gist of it is that the elliptic curves of interest are usually expressed in one of the standard +forms implemented here (Twisted Edwards, Montgomery and Short Weierstraß), and in addition to that, +you could choose to use `affine` coordinates (Cartesian coordinates - the usual (x,y) - possibly +together with a point at infinity) or `curvegroup` coordinates (some form of projective coordinates +requiring more coordinates but allowing for more efficient implementations of elliptic curve +operations). Conversions between all of these forms are provided, and under the hood these +conversions are done whenever an operation is more efficient in a different representation (or a +mixed coordinate representation is employed). + +### Points + +(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Point`), i.e. points lying on the +elliptic curve. For a curve configuration `c` and a point `p`, it may be checked that `p` +does indeed lie on `c` by calling `c.contains(p1)`. + +## Methods + +(given a choice of curve representation, e.g. use `std::ec::tecurve::affine::Curve` and use +`std::ec::tecurve::affine::Point`) + +- The **zero element** is given by `Point::zero()`, and we can verify whether a point `p: Point` is + zero by calling `p.is_zero()`. +- **Equality**: Points `p1: Point` and `p2: Point` may be checked for equality by calling + `p1.eq(p2)`. +- **Addition**: For `c: Curve` and points `p1: Point` and `p2: Point` on the curve, adding these two + points is accomplished by calling `c.add(p1,p2)`. +- **Negation**: For a point `p: Point`, `p.negate()` is its negation. +- **Subtraction**: For `c` and `p1`, `p2` as above, subtracting `p2` from `p1` is accomplished by + calling `c.subtract(p1,p2)`. +- **Scalar multiplication**: For `c` as above, `p: Point` a point on the curve and `n: Field`, + scalar multiplication is given by `c.mul(n,p)`. If instead `n :: [u1; N]`, i.e. `n` is a bit + array, the `bit_mul` method may be used instead: `c.bit_mul(n,p)` +- **Multi-scalar multiplication**: For `c` as above and arrays `n: [Field; N]` and `p: [Point; N]`, + multi-scalar multiplication is given by `c.msm(n,p)`. +- **Coordinate representation conversions**: The `into_group` method converts a point or curve + configuration in the affine representation to one in the CurveGroup representation, and + `into_affine` goes in the other direction. +- **Curve representation conversions**: `tecurve` and `montcurve` curves and points are equivalent + and may be converted between one another by calling `into_montcurve` or `into_tecurve` on their + configurations or points. `swcurve` is more general and a curve c of one of the other two types + may be converted to this representation by calling `c.into_swcurve()`, whereas a point `p` lying + on the curve given by `c` may be mapped to its corresponding `swcurve` point by calling + `c.map_into_swcurve(p)`. +- **Map-to-curve methods**: The Elligator 2 method of mapping a field element `n: Field` into a + `tecurve` or `montcurve` with configuration `c` may be called as `c.elligator2_map(n)`. For all of + the curve configurations, the SWU map-to-curve method may be called as `c.swu_map(z,n)`, where + `z: Field` depends on `Field` and `c` and must be chosen by the user (the conditions it needs to + satisfy are specified in the comments + [here](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr)). + +## Examples + +The +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) +illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more +interesting examples in Noir would be: + +Public-key cryptography: Given an elliptic curve and a 'base point' on it, determine the public key +from the private key. This is a matter of using scalar multiplication. In the case of Baby Jubjub, +for example, this code would do: + +```rust +use dep::std::ec::tecurve::affine::{Curve, Point}; + +fn bjj_pub_key(priv_key: Field) -> Point +{ + + let bjj = Curve::new(168700, 168696, G::new(995203441582195749578291179787384436505546430278305826713579947235728471134,5472060717959818805561601436314318772137091100104008585924551046643952123905)); + + let base_pt = Point::new(5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203); + + bjj.mul(priv_key,base_pt) +} +``` + +This would come in handy in a Merkle proof. + +- EdDSA signature verification: This is a matter of combining these primitives with a suitable hash + function. See + [feat(stdlib): EdDSA sig verification noir#1136](https://github.com/noir-lang/noir/pull/1136) for + the case of Baby Jubjub and the Poseidon hash function. diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx new file mode 100644 index 00000000000..4394b48f907 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx @@ -0,0 +1,98 @@ +--- +title: ECDSA Signature Verification +description: Learn about the cryptographic primitives regarding ECDSA over the secp256k1 and secp256r1 curves +keywords: [cryptographic primitives, Noir project, ecdsa, secp256k1, secp256r1, signatures] +sidebar_position: 3 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 curves. + +## ecdsa_secp256k1::verify_signature + +Verifier for ECDSA Secp256k1 signatures. +See ecdsa_secp256k1::verify_signature_slice for a version that accepts slices directly. + +```rust title="ecdsa_secp256k1" showLineNumbers +pub fn verify_signature( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8; N] +) -> bool +``` +> Source code: noir_stdlib/src/ecdsa_secp256k1.nr#L2-L9 + + +example: + +```rust +fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], signature : [u8;64]) { + let valid_signature = std::ecdsa_secp256k1::verify_signature(pub_key_x, pub_key_y, signature, hashed_message); + assert(valid_signature); +} +``` + + + +## ecdsa_secp256k1::verify_signature_slice + +Verifier for ECDSA Secp256k1 signatures where the message is a slice. + +```rust title="ecdsa_secp256k1_slice" showLineNumbers +pub fn verify_signature_slice( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8] +) -> bool +``` +> Source code: noir_stdlib/src/ecdsa_secp256k1.nr#L13-L20 + + + + +## ecdsa_secp256r1::verify_signature + +Verifier for ECDSA Secp256r1 signatures. +See ecdsa_secp256r1::verify_signature_slice for a version that accepts slices directly. + +```rust title="ecdsa_secp256r1" showLineNumbers +pub fn verify_signature( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8; N] +) -> bool +``` +> Source code: noir_stdlib/src/ecdsa_secp256r1.nr#L2-L9 + + +example: + +```rust +fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], signature : [u8;64]) { + let valid_signature = std::ecdsa_secp256r1::verify_signature(pub_key_x, pub_key_y, signature, hashed_message); + assert(valid_signature); +} +``` + + + +## ecdsa_secp256r1::verify_signature + +Verifier for ECDSA Secp256r1 signatures where the message is a slice. + +```rust title="ecdsa_secp256r1_slice" showLineNumbers +pub fn verify_signature_slice( + public_key_x: [u8; 32], + public_key_y: [u8; 32], + signature: [u8; 64], + message_hash: [u8] +) -> bool +``` +> Source code: noir_stdlib/src/ecdsa_secp256r1.nr#L13-L20 + + + diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/eddsa.mdx b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/eddsa.mdx new file mode 100644 index 00000000000..c2c0624dfad --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/eddsa.mdx @@ -0,0 +1,37 @@ +--- +title: EdDSA Verification +description: Learn about the cryptographic primitives regarding EdDSA +keywords: [cryptographic primitives, Noir project, eddsa, signatures] +sidebar_position: 5 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## eddsa::eddsa_poseidon_verify + +Verifier for EdDSA signatures + +```rust +fn eddsa_poseidon_verify(public_key_x : Field, public_key_y : Field, signature_s: Field, signature_r8_x: Field, signature_r8_y: Field, message: Field) -> bool +``` + +It is also possible to specify the hash algorithm used for the signature by using the `eddsa_verify_with_hasher` function with a parameter implementing the Hasher trait. For instance, if you want to use Poseidon2 instead, you can do the following: +```rust +use dep::std::hash::poseidon2::Poseidon2Hasher; + +let mut hasher = Poseidon2Hasher::default(); +eddsa_verify_with_hasher(pub_key_a.x, pub_key_a.y, s_a, r8_a.x, r8_a.y, msg, &mut hasher); +``` + + + +## eddsa::eddsa_to_pub + +Private to public key conversion. + +Returns `(pub_key_x, pub_key_y)` + +```rust +fn eddsa_to_pub(secret : Field) -> (Field, Field) +``` + diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/hashes.mdx b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/hashes.mdx new file mode 100644 index 00000000000..3b83d9ec31a --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -0,0 +1,257 @@ +--- +title: Hash methods +description: + Learn about the cryptographic primitives ready to use for any Noir project, including sha256, + blake2s, pedersen, mimc_bn254 and mimc +keywords: + [cryptographic primitives, Noir project, sha256, blake2s, pedersen, mimc_bn254, mimc, hash] +sidebar_position: 0 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## sha256 + +Given an array of bytes, returns the resulting sha256 hash. +Specify a message_size to hash only the first `message_size` bytes of the input. + +```rust title="sha256" showLineNumbers +pub fn sha256(input: [u8; N]) -> [u8; 32] +``` +> Source code: noir_stdlib/src/hash.nr#L10-L12 + + +example: +```rust title="sha256_var" showLineNumbers +let digest = std::hash::sha256_var([x as u8], 1); +``` +> Source code: test_programs/execution_success/sha256/src/main.nr#L17-L19 + + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::sha256::sha256_var(x, 4); +} +``` + + + + +## blake2s + +Given an array of bytes, returns an array with the Blake2 hash + +```rust title="blake2s" showLineNumbers +pub fn blake2s(input: [u8; N]) -> [u8; 32] +``` +> Source code: noir_stdlib/src/hash.nr#L16-L18 + + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::blake2s(x); +} +``` + + + +## blake3 + +Given an array of bytes, returns an array with the Blake3 hash + +```rust title="blake3" showLineNumbers +pub fn blake3(input: [u8; N]) -> [u8; 32] +``` +> Source code: noir_stdlib/src/hash.nr#L22-L24 + + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::blake3(x); +} +``` + + + +## pedersen_hash + +Given an array of Fields, returns the Pedersen hash. + +```rust title="pedersen_hash" showLineNumbers +pub fn pedersen_hash(input: [Field; N]) -> Field +``` +> Source code: noir_stdlib/src/hash.nr#L46-L48 + + +example: + +```rust title="pedersen-hash" showLineNumbers +use dep::std; + +fn main(x: Field, y: Field, expected_hash: Field) { + let hash = std::hash::pedersen_hash([x, y]); + assert_eq(hash, expected_hash); +} +``` +> Source code: test_programs/execution_success/pedersen_hash/src/main.nr#L1-L8 + + + + +## pedersen_commitment + +Given an array of Fields, returns the Pedersen commitment. + +```rust title="pedersen_commitment" showLineNumbers +struct PedersenPoint { + x : Field, + y : Field, +} + +pub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint { +``` +> Source code: noir_stdlib/src/hash.nr#L27-L34 + + +example: + +```rust title="pedersen-commitment" showLineNumbers +use dep::std; + +fn main(x: Field, y: Field, expected_commitment: std::hash::PedersenPoint) { + let commitment = std::hash::pedersen_commitment([x, y]); + assert_eq(commitment.x, expected_commitment.x); + assert_eq(commitment.y, expected_commitment.y); +} +``` +> Source code: test_programs/execution_success/pedersen_commitment/src/main.nr#L1-L9 + + + + +## keccak256 + +Given an array of bytes (`u8`), returns the resulting keccak hash as an array of +32 bytes (`[u8; 32]`). Specify a message_size to hash only the first +`message_size` bytes of the input. + +```rust title="keccak256" showLineNumbers +pub fn keccak256(input: [u8; N], message_size: u32) -> [u8; 32] +``` +> Source code: noir_stdlib/src/hash.nr#L68-L70 + + +example: + +```rust title="keccak256" showLineNumbers +use dep::std; + +fn main(x: Field, result: [u8; 32]) { + // We use the `as` keyword here to denote the fact that we want to take just the first byte from the x Field + // The padding is taken care of by the program + let digest = std::hash::keccak256([x as u8], 1); + assert(digest == result); + + //#1399: variable message size + let message_size = 4; + let hash_a = std::hash::keccak256([1, 2, 3, 4], message_size); + let hash_b = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size); + + assert(hash_a == hash_b); + + let message_size_big = 8; + let hash_c = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size_big); + + assert(hash_a != hash_c); +} +``` +> Source code: test_programs/execution_success/keccak256/src/main.nr#L1-L22 + + + + +## poseidon + +Given an array of Fields, returns a new Field with the Poseidon Hash. Mind that you need to specify +how many inputs are there to your Poseidon function. + +```rust +// example for hash_1, hash_2 accepts an array of length 2, etc +fn hash_1(input: [Field; 1]) -> Field +``` + +example: + +```rust title="poseidon" showLineNumbers +use dep::std::hash::poseidon; +use dep::std::hash::poseidon2; + +fn main(x1: [Field; 2], y1: pub Field, x2: [Field; 4], y2: pub Field, x3: [Field; 4], y3: Field) { + let hash1 = poseidon::bn254::hash_2(x1); + assert(hash1 == y1); + + let hash2 = poseidon::bn254::hash_4(x2); + assert(hash2 == y2); + + let hash3 = poseidon2::Poseidon2::hash(x3, x3.len()); + assert(hash3 == y3); +} +``` +> Source code: test_programs/execution_success/poseidon_bn254_hash/src/main.nr#L1-L15 + + +## poseidon 2 + +Given an array of Fields, returns a new Field with the Poseidon2 Hash. Contrary to the Poseidon +function, there is only one hash and you can specify a message_size to hash only the first +`message_size` bytes of the input, + +```rust +// example for hashing the first three elements of the input +Poseidon2::hash(input, 3); +``` + +The above example for Poseidon also includes Poseidon2. + +## mimc_bn254 and mimc + +`mimc_bn254` is `mimc`, but with hardcoded parameters for the BN254 curve. You can use it by +providing an array of Fields, and it returns a Field with the hash. You can use the `mimc` method if +you're willing to input your own constants: + +```rust +fn mimc(x: Field, k: Field, constants: [Field; N], exp : Field) -> Field +``` + +otherwise, use the `mimc_bn254` method: + +```rust +fn mimc_bn254(array: [Field; N]) -> Field +``` + +example: + +```rust + +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::mimc::mimc_bn254(x); +} +``` + +## hash_to_field + +```rust +fn hash_to_field(_input : [Field]) -> Field {} +``` + +Calculates the `blake2s` hash of the inputs and returns the hash modulo the field modulus to return +a value which can be represented as a `Field`. + diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/index.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/index.md new file mode 100644 index 00000000000..650f30165d5 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/index.md @@ -0,0 +1,14 @@ +--- +title: Cryptographic Primitives +description: + Learn about the cryptographic primitives ready to use for any Noir project +keywords: + [ + cryptographic primitives, + Noir project, + ] +--- + +The Noir team is progressively adding new cryptographic primitives to the standard library. Reach out for news or if you would be interested in adding more of these calculations in Noir. + +Some methods are available thanks to the Aztec backend, not being performed using Noir. When using other backends, these methods may or may not be supplied. diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/scalar.mdx b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/scalar.mdx new file mode 100644 index 00000000000..df411ca5443 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/scalar.mdx @@ -0,0 +1,33 @@ +--- +title: Scalar multiplication +description: See how you can perform scalar multiplications over a fixed base in Noir +keywords: [cryptographic primitives, Noir project, scalar multiplication] +sidebar_position: 1 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## scalar_mul::fixed_base_embedded_curve + +Performs scalar multiplication over the embedded curve whose coordinates are defined by the +configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. + +```rust title="fixed_base_embedded_curve" showLineNumbers +pub fn fixed_base_embedded_curve( + low: Field, + high: Field +) -> [Field; 2] +``` +> Source code: noir_stdlib/src/scalar_mul.nr#L27-L32 + + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base_embedded_curve(x); + println(scal); +} +``` + + diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/schnorr.mdx b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/schnorr.mdx new file mode 100644 index 00000000000..b59e69c8f07 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/cryptographic_primitives/schnorr.mdx @@ -0,0 +1,64 @@ +--- +title: Schnorr Signatures +description: Learn how you can verify Schnorr signatures using Noir +keywords: [cryptographic primitives, Noir project, schnorr, signatures] +sidebar_position: 2 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## schnorr::verify_signature + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). +See schnorr::verify_signature_slice for a version that works directly on slices. + +```rust title="schnorr_verify" showLineNumbers +pub fn verify_signature( + public_key_x: Field, + public_key_y: Field, + signature: [u8; 64], + message: [u8; N] +) -> bool +``` +> Source code: noir_stdlib/src/schnorr.nr#L2-L9 + + +where `_signature` can be generated like so using the npm package +[@noir-lang/barretenberg](https://www.npmjs.com/package/@noir-lang/barretenberg) + +```js +const { BarretenbergWasm } = require('@noir-lang/barretenberg/dest/wasm'); +const { Schnorr } = require('@noir-lang/barretenberg/dest/crypto/schnorr'); + +... + +const barretenberg = await BarretenbergWasm.new(); +const schnorr = new Schnorr(barretenberg); +const pubKey = schnorr.computePublicKey(privateKey); +const message = ... +const signature = Array.from( + schnorr.constructSignature(hash, privateKey).toBuffer() +); + +... +``` + + + +## schnorr::verify_signature_slice + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin) +where the message is a slice. + +```rust title="schnorr_verify_slice" showLineNumbers +pub fn verify_signature_slice( + public_key_x: Field, + public_key_y: Field, + signature: [u8; 64], + message: [u8] +) -> bool +``` +> Source code: noir_stdlib/src/schnorr.nr#L13-L20 + + + diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/logging.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/logging.md new file mode 100644 index 00000000000..db75ef9f86f --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/logging.md @@ -0,0 +1,78 @@ +--- +title: Logging +description: + Learn how to use the println statement for debugging in Noir with this tutorial. Understand the + basics of logging in Noir and how to implement it in your code. +keywords: + [ + noir logging, + println statement, + print statement, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +The standard library provides two familiar statements you can use: `println` and `print`. Despite being a limited implementation of rust's `println!` and `print!` macros, these constructs can be useful for debugging. + +You can print the output of both statements in your Noir code by using the `nargo execute` command or the `--show-output` flag when using `nargo test` (provided there are print statements in your tests). + +It is recommended to use `nargo execute` if you want to debug failing constraints with `println` or `print` statements. This is due to every input in a test being a constant rather than a witness, so we issue an error during compilation while we only print during execution (which comes after compilation). Neither `println`, nor `print` are callable for failed constraints caught at compile time. + +Both `print` and `println` are generic functions which can work on integers, fields, strings, and even structs or expressions. Note however, that slices are currently unsupported. For example: + +```rust +struct Person { + age: Field, + height: Field, +} + +fn main(age: Field, height: Field) { + let person = Person { + age: age, + height: height, + }; + println(person); + println(age + height); + println("Hello world!"); +} +``` + +You can print different types in the same statement (including strings) with a type called `fmtstr`. It can be specified in the same way as a normal string, just prepended with an "f" character: + +```rust + let fmt_str = f"i: {i}, j: {j}"; + println(fmt_str); + + let s = myStruct { y: x, x: y }; + println(s); + + println(f"i: {i}, s: {s}"); + + println(x); + println([x, y]); + + let foo = fooStruct { my_struct: s, foo: 15 }; + println(f"s: {s}, foo: {foo}"); + + println(15); // prints 0x0f, implicit Field + println(-1 as u8); // prints 255 + println(-1 as i8); // prints -1 +``` + +Examples shown above are interchangeable between the two `print` statements: + +```rust +let person = Person { age : age, height : height }; + +println(person); +print(person); + +println("Hello world!"); // Prints with a newline at the end of the input +print("Hello world!"); // Prints the input and keeps cursor on the same line +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/merkle_trees.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/merkle_trees.md new file mode 100644 index 00000000000..6a9ebf72ada --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/merkle_trees.md @@ -0,0 +1,58 @@ +--- +title: Merkle Trees +description: Learn about Merkle Trees in Noir with this tutorial. Explore the basics of computing a merkle root using a proof, with examples. +keywords: + [ + Merkle trees in Noir, + Noir programming language, + check membership, + computing root from leaf, + Noir Merkle tree implementation, + Merkle tree tutorial, + Merkle tree code examples, + Noir libraries, + pedersen hash., + ] +--- + +## compute_merkle_root + +Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](./cryptographic_primitives/hashes.mdx#pedersen_hash). + +```rust +fn compute_merkle_root(leaf : Field, index : Field, hash_path: [Field]) -> Field +``` + +example: + +```rust +/** + // these values are for this example only + index = "0" + priv_key = "0x000000000000000000000000000000000000000000000000000000616c696365" + secret = "0x1929ea3ab8d9106a899386883d9428f8256cfedb3c4f6b66bf4aa4d28a79988f" + note_hash_path = [ + "0x1e61bdae0f027b1b2159e1f9d3f8d00fa668a952dddd822fda80dc745d6f65cc", + "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", + "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" + ] + */ +fn main(index: Field, priv_key: Field, secret: Field, note_hash_path: [Field; 3]) { + + let pubkey = std::scalar_mul::fixed_base_embedded_curve(priv_key); + let pubkey_x = pubkey[0]; + let pubkey_y = pubkey[1]; + let note_commitment = std::hash::pedersen(&[pubkey_x, pubkey_y, secret]); + + let root = std::merkle::compute_merkle_root(note_commitment[0], index, note_hash_path.as_slice()); + println(root); +} +``` + +To check merkle tree membership: + +1. Include a merkle root as a program input. +2. Compute the merkle root of a given leaf, index and hash path. +3. Assert the merkle roots are equal. + +For more info about merkle trees, see the Wikipedia [page](https://en.wikipedia.org/wiki/Merkle_tree). diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/options.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/options.md new file mode 100644 index 00000000000..a1bd4e1de5f --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/options.md @@ -0,0 +1,101 @@ +--- +title: Option Type +--- + +The `Option` type is a way to express that a value might be present (`Some(T))` or absent (`None`). It's a safer way to handle potential absence of values, compared to using nulls in many other languages. + +```rust +struct Option { + None, + Some(T), +} +``` + +The `Option` type, already imported into your Noir program, can be used directly: + +```rust +fn main() { + let none = Option::none(); + let some = Option::some(3); +} +``` + +See [this test](https://github.com/noir-lang/noir/blob/5cbfb9c4a06c8865c98ff2b594464b037d821a5c/crates/nargo_cli/tests/test_data/option/src/main.nr) for a more comprehensive set of examples of each of the methods described below. + +## Methods + +### none + +Constructs a none value. + +### some + +Constructs a some wrapper around a given value. + +### is_none + +Returns true if the Option is None. + +### is_some + +Returns true of the Option is Some. + +### unwrap + +Asserts `self.is_some()` and returns the wrapped value. + +### unwrap_unchecked + +Returns the inner value without asserting `self.is_some()`. This method can be useful within an if condition when we already know that `option.is_some()`. If the option is None, there is no guarantee what value will be returned, only that it will be of type T for an `Option`. + +### unwrap_or + +Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value. + +### unwrap_or_else + +Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return a default value. + +### expect + +Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value. The custom message is expected to be a format string. + +### map + +If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`. + +### map_or + +If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value. + +### map_or_else + +If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`. + +### and + +Returns None if self is None. Otherwise, this returns `other`. + +### and_then + +If self is None, this returns None. Otherwise, this calls the given function with the Some value contained within self, and returns the result of that call. In some languages this function is called `flat_map` or `bind`. + +### or + +If self is Some, return self. Otherwise, return `other`. + +### or_else + +If self is Some, return self. Otherwise, return `default()`. + +### xor + +If only one of the two Options is Some, return that option. Otherwise, if both options are Some or both are None, None is returned. + +### filter + +Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true. Otherwise, this returns `None`. + +### flatten + +Flattens an `Option>` into a `Option`. This returns `None` if the outer Option is None. Otherwise, this returns the inner Option. diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/recursion.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/recursion.md new file mode 100644 index 00000000000..a93894043dc --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/recursion.md @@ -0,0 +1,88 @@ +--- +title: Recursive Proofs +description: Learn about how to write recursive proofs in Noir. +keywords: [recursion, recursive proofs, verification_key, verify_proof] +--- + +Noir supports recursively verifying proofs, meaning you verify the proof of a Noir program in another Noir program. This enables creating proofs of arbitrary size by doing step-wise verification of smaller components of a large proof. + +Read [the explainer on recursion](../../explainers/explainer-recursion.md) to know more about this function and the [guide on how to use it.](../../how_to/how-to-recursion.md) + +## The `#[recursive]` Attribute + +In Noir, the `#[recursive]` attribute is used to indicate that a circuit is designed for recursive proof generation. When applied, it informs the compiler and the tooling that the circuit should be compiled in a way that makes its proofs suitable for recursive verification. This attribute eliminates the need for manual flagging of recursion at the tooling level, streamlining the proof generation process for recursive circuits. + +### Example usage with `#[recursive]` + +```rust +#[recursive] +fn main(x: Field, y: pub Field) { + assert(x == y, "x and y are not equal"); +} + +// This marks the circuit as recursion-friendly and indicates that proofs generated from this circuit +// are intended for recursive verification. +``` + +By incorporating this attribute directly in the circuit's definition, tooling like Nargo and NoirJS can automatically execute recursive-specific duties for Noir programs (e.g. recursive-friendly proof artifact generation) without additional flags or configurations. + +## Verifying Recursive Proofs + +```rust +#[foreign(recursive_aggregation)] +pub fn verify_proof(verification_key: [Field], proof: [Field], public_inputs: [Field], key_hash: Field) {} +``` + +:::info + +This is a black box function. Read [this section](./black_box_fns) to learn more about black box functions in Noir. + +::: + +## Example usage + +```rust +use dep::std; + +fn main( + verification_key : [Field; 114], + proof : [Field; 93], + public_inputs : [Field; 1], + key_hash : Field, + proof_b : [Field; 93], +) { + std::verify_proof( + verification_key.as_slice(), + proof.as_slice(), + public_inputs.as_slice(), + key_hash + ); + + std::verify_proof( + verification_key.as_slice(), + proof_b.as_slice(), + public_inputs.as_slice(), + key_hash + ); +} +``` + +You can see a full example of recursive proofs in [this example recursion demo repo](https://github.com/noir-lang/noir-examples/tree/master/recursion). + +## Parameters + +### `verification_key` + +The verification key for the zk program that is being verified. + +### `proof` + +The proof for the zk program that is being verified. + +### `public_inputs` + +These represent the public inputs of the proof we are verifying. + +### `key_hash` + +A key hash is used to check the validity of the verification key. The circuit implementing this opcode can use this hash to ensure that the key provided to the circuit matches the key produced by the circuit creator. diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/traits.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/traits.md new file mode 100644 index 00000000000..04dc40f0dac --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/traits.md @@ -0,0 +1,410 @@ +--- +title: Traits +description: Noir's stdlib provides a few commonly used traits. +keywords: [traits, trait, interface, protocol, default, add, eq] +--- + +## `std::default` + +### `std::default::Default` + +```rust title="default-trait" showLineNumbers +trait Default { + fn default() -> Self; +} +``` +> Source code: noir_stdlib/src/default.nr#L1-L5 + + +Constructs a default value of a type. + +Implementations: +```rust +impl Default for Field { .. } + +impl Default for i8 { .. } +impl Default for i16 { .. } +impl Default for i32 { .. } +impl Default for i64 { .. } + +impl Default for u8 { .. } +impl Default for u16 { .. } +impl Default for u32 { .. } +impl Default for u64 { .. } + +impl Default for () { .. } +impl Default for bool { .. } + +impl Default for [T; N] + where T: Default { .. } + +impl Default for [T] { .. } + +impl Default for (A, B) + where A: Default, B: Default { .. } + +impl Default for (A, B, C) + where A: Default, B: Default, C: Default { .. } + +impl Default for (A, B, C, D) + where A: Default, B: Default, C: Default, D: Default { .. } + +impl Default for (A, B, C, D, E) + where A: Default, B: Default, C: Default, D: Default, E: Default { .. } +``` + +For primitive integer types, the return value of `default` is `0`. Container +types such as arrays are filled with default values of their element type, +except slices whose length is unknown and thus defaulted to zero. + + +## `std::convert` + +### `std::convert::From` + +```rust title="from-trait" showLineNumbers +trait From { + fn from(input: T) -> Self; +} +``` +> Source code: noir_stdlib/src/convert.nr#L1-L5 + + +The `From` trait defines how to convert from a given type `T` to the type on which the trait is implemented. + +The Noir standard library provides a number of implementations of `From` between primitive types. +```rust title="from-impls" showLineNumbers +// Unsigned integers + +impl From for u32 { fn from(value: u8) -> u32 { value as u32 } } + +impl From for u64 { fn from(value: u8) -> u64 { value as u64 } } +impl From for u64 { fn from(value: u32) -> u64 { value as u64 } } + +impl From for Field { fn from(value: u8) -> Field { value as Field } } +impl From for Field { fn from(value: u32) -> Field { value as Field } } +impl From for Field { fn from(value: u64) -> Field { value as Field } } + +// Signed integers + +impl From for i32 { fn from(value: i8) -> i32 { value as i32 } } + +impl From for i64 { fn from(value: i8) -> i64 { value as i64 } } +impl From for i64 { fn from(value: i32) -> i64 { value as i64 } } + +// Booleans +impl From for u8 { fn from(value: bool) -> u8 { value as u8 } } +impl From for u32 { fn from(value: bool) -> u32 { value as u32 } } +impl From for u64 { fn from(value: bool) -> u64 { value as u64 } } +impl From for i8 { fn from(value: bool) -> i8 { value as i8 } } +impl From for i32 { fn from(value: bool) -> i32 { value as i32 } } +impl From for i64 { fn from(value: bool) -> i64 { value as i64 } } +impl From for Field { fn from(value: bool) -> Field { value as Field } } +``` +> Source code: noir_stdlib/src/convert.nr#L25-L52 + + +#### When to implement `From` + +As a general rule of thumb, `From` may be implemented in the [situations where it would be suitable in Rust](https://doc.rust-lang.org/std/convert/trait.From.html#when-to-implement-from): + +- The conversion is *infallible*: Noir does not provide an equivalent to Rust's `TryFrom`, if the conversion can fail then provide a named method instead. +- The conversion is *lossless*: semantically, it should not lose or discard information. For example, `u32: From` can losslessly convert any `u16` into a valid `u32` such that the original `u16` can be recovered. On the other hand, `u16: From` should not be implemented as `2**16` is a `u32` which cannot be losslessly converted into a `u16`. +- The conversion is *value-preserving*: the conceptual kind and meaning of the resulting value is the same, even though the Noir type and technical representation might be different. While it's possible to infallibly and losslessly convert a `u8` into a `str<2>` hex representation, `4u8` and `"04"` are too different for `str<2>: From` to be implemented. +- The conversion is *obvious*: it's the only reasonable conversion between the two types. If there's ambiguity on how to convert between them such that the same input could potentially map to two different values then a named method should be used. For instance rather than implementing `U128: From<[u8; 16]>`, the methods `U128::from_le_bytes` and `U128::from_be_bytes` are used as otherwise the endianness of the array would be ambiguous, resulting in two potential values of `U128` from the same byte array. + +One additional recommendation specific to Noir is: +- The conversion is *efficient*: it's relatively cheap to convert between the two types. Due to being a ZK DSL, it's more important to avoid unnecessary computation compared to Rust. If the implementation of `From` would encourage users to perform unnecessary conversion, resulting in additional proving time, then it may be preferable to expose functionality such that this conversion may be avoided. + +### `std::convert::Into` + +The `Into` trait is defined as the reciprocal of `From`. It should be easy to convince yourself that if we can convert to type `A` from type `B`, then it's possible to convert type `B` into type `A`. + +For this reason, implementing `From` on a type will automatically generate a matching `Into` implementation. One should always prefer implementing `From` over `Into` as implementing `Into` will not generate a matching `From` implementation. + +```rust title="into-trait" showLineNumbers +trait Into { + fn into(self) -> T; +} + +impl Into for U where T: From { + fn into(self) -> T { + T::from(self) + } +} +``` +> Source code: noir_stdlib/src/convert.nr#L13-L23 + + +`Into` is most useful when passing function arguments where the types don't quite match up with what the function expects. In this case, the compiler has enough type information to perform the necessary conversion by just appending `.into()` onto the arguments in question. + + +## `std::cmp` + +### `std::cmp::Eq` + +```rust title="eq-trait" showLineNumbers +trait Eq { + fn eq(self, other: Self) -> bool; +} +``` +> Source code: noir_stdlib/src/cmp.nr#L1-L5 + + +Returns `true` if `self` is equal to `other`. Implementing this trait on a type +allows the type to be used with `==` and `!=`. + +Implementations: +```rust +impl Eq for Field { .. } + +impl Eq for i8 { .. } +impl Eq for i16 { .. } +impl Eq for i32 { .. } +impl Eq for i64 { .. } + +impl Eq for u8 { .. } +impl Eq for u16 { .. } +impl Eq for u32 { .. } +impl Eq for u64 { .. } + +impl Eq for () { .. } +impl Eq for bool { .. } + +impl Eq for [T; N] + where T: Eq { .. } + +impl Eq for [T] + where T: Eq { .. } + +impl Eq for (A, B) + where A: Eq, B: Eq { .. } + +impl Eq for (A, B, C) + where A: Eq, B: Eq, C: Eq { .. } + +impl Eq for (A, B, C, D) + where A: Eq, B: Eq, C: Eq, D: Eq { .. } + +impl Eq for (A, B, C, D, E) + where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { .. } +``` + +### `std::cmp::Ord` + +```rust title="ord-trait" showLineNumbers +trait Ord { + fn cmp(self, other: Self) -> Ordering; +} +``` +> Source code: noir_stdlib/src/cmp.nr#L102-L106 + + +`a.cmp(b)` compares two values returning `Ordering::less()` if `a < b`, +`Ordering::equal()` if `a == b`, or `Ordering::greater()` if `a > b`. +Implementing this trait on a type allows `<`, `<=`, `>`, and `>=` to be +used on values of the type. + +`std::cmp` also provides `max` and `min` functions for any type which implements the `Ord` trait. + +Implementations: + +```rust +impl Ord for u8 { .. } +impl Ord for u16 { .. } +impl Ord for u32 { .. } +impl Ord for u64 { .. } + +impl Ord for i8 { .. } +impl Ord for i16 { .. } +impl Ord for i32 { .. } + +impl Ord for i64 { .. } + +impl Ord for () { .. } +impl Ord for bool { .. } + +impl Ord for [T; N] + where T: Ord { .. } + +impl Ord for [T] + where T: Ord { .. } + +impl Ord for (A, B) + where A: Ord, B: Ord { .. } + +impl Ord for (A, B, C) + where A: Ord, B: Ord, C: Ord { .. } + +impl Ord for (A, B, C, D) + where A: Ord, B: Ord, C: Ord, D: Ord { .. } + +impl Ord for (A, B, C, D, E) + where A: Ord, B: Ord, C: Ord, D: Ord, E: Ord { .. } +``` + +## `std::ops` + +### `std::ops::Add`, `std::ops::Sub`, `std::ops::Mul`, and `std::ops::Div` + +These traits abstract over addition, subtraction, multiplication, and division respectively. +Implementing these traits for a given type will also allow that type to be used with the corresponding operator +for that trait (`+` for Add, etc) in addition to the normal method names. + +```rust title="add-trait" showLineNumbers +trait Add { + fn add(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L1-L5 + +```rust title="sub-trait" showLineNumbers +trait Sub { + fn sub(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L17-L21 + +```rust title="mul-trait" showLineNumbers +trait Mul { + fn mul(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L33-L37 + +```rust title="div-trait" showLineNumbers +trait Div { + fn div(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L49-L53 + + +The implementations block below is given for the `Add` trait, but the same types that implement +`Add` also implement `Sub`, `Mul`, and `Div`. + +Implementations: +```rust +impl Add for Field { .. } + +impl Add for i8 { .. } +impl Add for i16 { .. } +impl Add for i32 { .. } +impl Add for i64 { .. } + +impl Add for u8 { .. } +impl Add for u16 { .. } +impl Add for u32 { .. } +impl Add for u64 { .. } +``` + +### `std::ops::Rem` + +```rust title="rem-trait" showLineNumbers +trait Rem{ + fn rem(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L65-L69 + + +`Rem::rem(a, b)` is the remainder function returning the result of what is +left after dividing `a` and `b`. Implementing `Rem` allows the `%` operator +to be used with the implementation type. + +Unlike other numeric traits, `Rem` is not implemented for `Field`. + +Implementations: +```rust +impl Rem for u8 { fn rem(self, other: u8) -> u8 { self % other } } +impl Rem for u16 { fn rem(self, other: u16) -> u16 { self % other } } +impl Rem for u32 { fn rem(self, other: u32) -> u32 { self % other } } +impl Rem for u64 { fn rem(self, other: u64) -> u64 { self % other } } + +impl Rem for i8 { fn rem(self, other: i8) -> i8 { self % other } } +impl Rem for i16 { fn rem(self, other: i16) -> i16 { self % other } } +impl Rem for i32 { fn rem(self, other: i32) -> i32 { self % other } } +impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } +``` + +### `std::ops::{ BitOr, BitAnd, BitXor }` + +```rust title="bitor-trait" showLineNumbers +trait BitOr { + fn bitor(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L79-L83 + +```rust title="bitand-trait" showLineNumbers +trait BitAnd { + fn bitand(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L95-L99 + +```rust title="bitxor-trait" showLineNumbers +trait BitXor { + fn bitxor(self, other: Self) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L111-L115 + + +Traits for the bitwise operations `|`, `&`, and `^`. + +Implementing `BitOr`, `BitAnd` or `BitXor` for a type allows the `|`, `&`, or `^` operator respectively +to be used with the type. + +The implementations block below is given for the `BitOr` trait, but the same types that implement +`BitOr` also implement `BitAnd` and `BitXor`. + +Implementations: +```rust +impl BitOr for bool { fn bitor(self, other: bool) -> bool { self | other } } + +impl BitOr for u8 { fn bitor(self, other: u8) -> u8 { self | other } } +impl BitOr for u16 { fn bitor(self, other: u16) -> u16 { self | other } } +impl BitOr for u32 { fn bitor(self, other: u32) -> u32 { self | other } } +impl BitOr for u64 { fn bitor(self, other: u64) -> u64 { self | other } } + +impl BitOr for i8 { fn bitor(self, other: i8) -> i8 { self | other } } +impl BitOr for i16 { fn bitor(self, other: i16) -> i16 { self | other } } +impl BitOr for i32 { fn bitor(self, other: i32) -> i32 { self | other } } +impl BitOr for i64 { fn bitor(self, other: i64) -> i64 { self | other } } +``` + +### `std::ops::{ Shl, Shr }` + +```rust title="shl-trait" showLineNumbers +trait Shl { + fn shl(self, other: u8) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L127-L131 + +```rust title="shr-trait" showLineNumbers +trait Shr { + fn shr(self, other: u8) -> Self; +} +``` +> Source code: noir_stdlib/src/ops.nr#L142-L146 + + +Traits for a bit shift left and bit shift right. + +Implementing `Shl` for a type allows the left shift operator (`<<`) to be used with the implementation type. +Similarly, implementing `Shr` allows the right shift operator (`>>`) to be used with the type. + +Note that bit shifting is not currently implemented for signed types. + +The implementations block below is given for the `Shl` trait, but the same types that implement +`Shl` also implement `Shr`. + +Implementations: +```rust +impl Shl for u8 { fn shl(self, other: u8) -> u8 { self << other } } +impl Shl for u16 { fn shl(self, other: u16) -> u16 { self << other } } +impl Shl for u32 { fn shl(self, other: u32) -> u32 { self << other } } +impl Shl for u64 { fn shl(self, other: u64) -> u64 { self << other } } +``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/standard_library/zeroed.md b/docs/versioned_docs/version-v0.29.0/noir/standard_library/zeroed.md new file mode 100644 index 00000000000..f450fecdd36 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/noir/standard_library/zeroed.md @@ -0,0 +1,26 @@ +--- +title: Zeroed Function +description: + The zeroed function returns a zeroed value of any type. +keywords: + [ + zeroed + ] +--- + +Implements `fn zeroed() -> T` to return a zeroed value of any type. This function is generally unsafe to use as the zeroed bit pattern is not guaranteed to be valid for all types. It can however, be useful in cases when the value is guaranteed not to be used such as in a BoundedVec library implementing a growable vector, up to a certain length, backed by an array. The array can be initialized with zeroed values which are guaranteed to be inaccessible until the vector is pushed to. Similarly, enumerations in noir can be implemented using this method by providing zeroed values for the unused variants. + +You can access the function at `std::unsafe::zeroed`. + +This function currently supports the following types: + +- Field +- Bool +- Uint +- Array +- Slice +- String +- Tuple +- Function + +Using it on other types could result in unexpected behavior. diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/.nojekyll b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md new file mode 100644 index 00000000000..d7249d24330 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md @@ -0,0 +1,160 @@ +# BarretenbergBackend + +## Extends + +- `BarretenbergVerifierBackend` + +## Implements + +- [`Backend`](../index.md#backend) + +## Constructors + +### new BarretenbergBackend(acirCircuit, options) + +```ts +new BarretenbergBackend(acirCircuit, options): BarretenbergBackend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `acirCircuit` | `CompiledCircuit` | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergBackend`](BarretenbergBackend.md) + +#### Inherited from + +BarretenbergVerifierBackend.constructor + +## Properties + +| Property | Type | Description | Inheritance | +| :------ | :------ | :------ | :------ | +| `acirComposer` | `any` | - | BarretenbergVerifierBackend.acirComposer | +| `acirUncompressedBytecode` | `Uint8Array` | - | BarretenbergVerifierBackend.acirUncompressedBytecode | +| `api` | `Barretenberg` | - | BarretenbergVerifierBackend.api | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | - | BarretenbergVerifierBackend.options | + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Inherited from + +BarretenbergVerifierBackend.destroy + +*** + +### generateProof() + +```ts +generateProof(compressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `compressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<`ProofData`\> + +#### Description + +Generates a proof + +*** + +### generateRecursiveProofArtifacts() + +```ts +generateRecursiveProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +Generates artifacts that will be passed to a circuit that will verify this proof. + +Instead of passing the proof and verification key as a byte array, we pass them +as fields which makes it cheaper to verify in a circuit. + +The proof that is passed here will have been created using a circuit +that has the #[recursive] attribute on its `main` method. + +The number of public inputs denotes how many public inputs are in the inner proof. + +#### Parameters + +| Parameter | Type | Default value | +| :------ | :------ | :------ | +| `proofData` | `ProofData` | `undefined` | +| `numOfPublicInputs` | `number` | `0` | + +#### Returns + +`Promise`\<`object`\> + +#### Example + +```typescript +const artifacts = await backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs); +``` + +*** + +### getVerificationKey() + +```ts +getVerificationKey(): Promise +``` + +#### Returns + +`Promise`\<`Uint8Array`\> + +#### Inherited from + +BarretenbergVerifierBackend.getVerificationKey + +*** + +### verifyProof() + +```ts +verifyProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | `ProofData` | + +#### Returns + +`Promise`\<`boolean`\> + +#### Inherited from + +BarretenbergVerifierBackend.verifyProof + +#### Description + +Verifies a proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier.md new file mode 100644 index 00000000000..500276ea748 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier.md @@ -0,0 +1,58 @@ +# BarretenbergVerifier + +## Constructors + +### new BarretenbergVerifier(options) + +```ts +new BarretenbergVerifier(options): BarretenbergVerifier +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergVerifier`](BarretenbergVerifier.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +*** + +### verifyProof() + +```ts +verifyProof(proofData, verificationKey): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | `ProofData` | +| `verificationKey` | `Uint8Array` | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/index.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/index.md new file mode 100644 index 00000000000..64971973196 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/index.md @@ -0,0 +1,59 @@ +# backend_barretenberg + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [BarretenbergBackend](classes/BarretenbergBackend.md) | - | +| [BarretenbergVerifier](classes/BarretenbergVerifier.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [BackendOptions](type-aliases/BackendOptions.md) | - | + +## References + +### CompiledCircuit + +Renames and re-exports [Backend](index.md#backend) + +*** + +### ProofData + +Renames and re-exports [Backend](index.md#backend) + +## Variables + +### Backend + +```ts +Backend: any; +``` + +## Functions + +### publicInputsToWitnessMap() + +```ts +publicInputsToWitnessMap(publicInputs, abi): Backend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `publicInputs` | `string`[] | +| `abi` | `Abi` | + +#### Returns + +[`Backend`](index.md#backend) + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md new file mode 100644 index 00000000000..b49a479f4f4 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md @@ -0,0 +1,21 @@ +# BackendOptions + +```ts +type BackendOptions: object; +``` + +## Description + +An options object, currently only used to specify the number of threads to use. + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `memory` | `object` | - | +| `memory.maximum` | `number` | - | +| `threads` | `number` | **Description**

Number of threads | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs new file mode 100644 index 00000000000..d7d5128f9e3 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend","label":"BarretenbergBackend"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/classes/BarretenbergVerifier","label":"BarretenbergVerifier"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions","label":"BackendOptions"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/.nojekyll b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/classes/Noir.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/classes/Noir.md new file mode 100644 index 00000000000..45dd62ee57e --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/classes/Noir.md @@ -0,0 +1,132 @@ +# Noir + +## Constructors + +### new Noir(circuit, backend) + +```ts +new Noir(circuit, backend?): Noir +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `circuit` | `CompiledCircuit` | +| `backend`? | `any` | + +#### Returns + +[`Noir`](Noir.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the underlying backend instance. + +#### Example + +```typescript +await noir.destroy(); +``` + +*** + +### execute() + +```ts +execute(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | `InputMap` | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Allows to execute a circuit to get its witness and return value. + +#### Example + +```typescript +async execute(inputs) +``` + +*** + +### generateProof() + +```ts +generateProof(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | `InputMap` | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`ProofData`\> + +#### Description + +Generates a witness and a proof given an object as input. + +#### Example + +```typescript +async generateProof(input) +``` + +*** + +### verifyProof() + +```ts +verifyProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | `ProofData` | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Instantiates the verification key and verifies a proof. + +#### Example + +```typescript +async verifyProof(proof) +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/and.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/and.md new file mode 100644 index 00000000000..c783283e396 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/and.md @@ -0,0 +1,22 @@ +# and() + +```ts +and(lhs, rhs): string +``` + +Performs a bitwise AND operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/blake2s256.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/blake2s256.md new file mode 100644 index 00000000000..7882d0da8d5 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/blake2s256.md @@ -0,0 +1,21 @@ +# blake2s256() + +```ts +blake2s256(inputs): Uint8Array +``` + +Calculates the Blake2s256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md new file mode 100644 index 00000000000..5e3cd53e9d3 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256k1\_verify() + +```ts +ecdsa_secp256k1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256k1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md new file mode 100644 index 00000000000..0b20ff68957 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256r1\_verify() + +```ts +ecdsa_secp256r1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256r1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/keccak256.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/keccak256.md new file mode 100644 index 00000000000..d10f155ce86 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/keccak256.md @@ -0,0 +1,21 @@ +# keccak256() + +```ts +keccak256(inputs): Uint8Array +``` + +Calculates the Keccak256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/sha256.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/sha256.md new file mode 100644 index 00000000000..6ba4ecac022 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/sha256.md @@ -0,0 +1,21 @@ +# sha256() + +```ts +sha256(inputs): Uint8Array +``` + +Calculates the SHA256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/xor.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/xor.md new file mode 100644 index 00000000000..8d762b895d3 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/functions/xor.md @@ -0,0 +1,22 @@ +# xor() + +```ts +xor(lhs, rhs): string +``` + +Performs a bitwise XOR operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/index.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/index.md new file mode 100644 index 00000000000..cca6b3ace41 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/index.md @@ -0,0 +1,54 @@ +# noir_js + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [Noir](classes/Noir.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [ForeignCallHandler](type-aliases/ForeignCallHandler.md) | A callback which performs an foreign call and returns the response. | +| [ForeignCallInput](type-aliases/ForeignCallInput.md) | - | +| [ForeignCallOutput](type-aliases/ForeignCallOutput.md) | - | +| [WitnessMap](type-aliases/WitnessMap.md) | - | + +### Functions + +| Function | Description | +| :------ | :------ | +| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` | +| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes | +| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Verifies a ECDSA signature over the secp256k1 curve. | +| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. | +| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes | +| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes | +| [xor](functions/xor.md) | Performs a bitwise XOR operation between `lhs` and `rhs` | + +## References + +### CompiledCircuit + +Renames and re-exports [InputMap](index.md#inputmap) + +*** + +### ProofData + +Renames and re-exports [InputMap](index.md#inputmap) + +## Variables + +### InputMap + +```ts +InputMap: any; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md new file mode 100644 index 00000000000..812b8b16481 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md @@ -0,0 +1,24 @@ +# ForeignCallHandler + +```ts +type ForeignCallHandler: (name, inputs) => Promise; +``` + +A callback which performs an foreign call and returns the response. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | The identifier for the type of foreign call being performed. | +| `inputs` | [`ForeignCallInput`](ForeignCallInput.md)[] | An array of hex encoded inputs to the foreign call. | + +## Returns + +`Promise`\<[`ForeignCallOutput`](ForeignCallOutput.md)[]\> + +outputs - An array of hex encoded outputs containing the results of the foreign call. + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md new file mode 100644 index 00000000000..dd95809186a --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md @@ -0,0 +1,9 @@ +# ForeignCallInput + +```ts +type ForeignCallInput: string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md new file mode 100644 index 00000000000..b71fb78a946 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md @@ -0,0 +1,9 @@ +# ForeignCallOutput + +```ts +type ForeignCallOutput: string | string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md new file mode 100644 index 00000000000..258c46f9d0c --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md @@ -0,0 +1,9 @@ +# WitnessMap + +```ts +type WitnessMap: Map; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs new file mode 100644 index 00000000000..c6d8125eaad --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/noir_js/classes/Noir","label":"Noir"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallHandler","label":"ForeignCallHandler"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallInput","label":"ForeignCallInput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallOutput","label":"ForeignCallOutput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/WitnessMap","label":"WitnessMap"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_js/functions/and","label":"and"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/blake2s256","label":"blake2s256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify","label":"ecdsa_secp256k1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify","label":"ecdsa_secp256r1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/keccak256","label":"keccak256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/sha256","label":"sha256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/xor","label":"xor"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/.nojekyll b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/compile.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/compile.md new file mode 100644 index 00000000000..6faf763b37f --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/compile.md @@ -0,0 +1,51 @@ +# compile() + +```ts +compile( + fileManager, + projectPath?, + logFn?, +debugLogFn?): Promise +``` + +Compiles a Noir project + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `fileManager` | `FileManager` | The file manager to use | +| `projectPath`? | `string` | The path to the project inside the file manager. Defaults to the root of the file manager | +| `logFn`? | `LogFn` | A logging function. If not provided, console.log will be used | +| `debugLogFn`? | `LogFn` | A debug logging function. If not provided, logFn will be used | + +## Returns + +`Promise`\<[`ProgramCompilationArtifacts`](../index.md#programcompilationartifacts)\> + +## Example + +```typescript +// Node.js + +import { compile_program, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile_program(fm); +``` + +```typescript +// Browser + +import { compile_program, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile_program(fm); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/compile_contract.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/compile_contract.md new file mode 100644 index 00000000000..7d0b39a43ef --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/compile_contract.md @@ -0,0 +1,51 @@ +# compile\_contract() + +```ts +compile_contract( + fileManager, + projectPath?, + logFn?, +debugLogFn?): Promise +``` + +Compiles a Noir project + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `fileManager` | `FileManager` | The file manager to use | +| `projectPath`? | `string` | The path to the project inside the file manager. Defaults to the root of the file manager | +| `logFn`? | `LogFn` | A logging function. If not provided, console.log will be used | +| `debugLogFn`? | `LogFn` | A debug logging function. If not provided, logFn will be used | + +## Returns + +`Promise`\<[`ContractCompilationArtifacts`](../index.md#contractcompilationartifacts)\> + +## Example + +```typescript +// Node.js + +import { compile_contract, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile_contract(fm); +``` + +```typescript +// Browser + +import { compile_contract, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile_contract(fm); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/createFileManager.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/createFileManager.md new file mode 100644 index 00000000000..7e65c1d69c7 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/createFileManager.md @@ -0,0 +1,21 @@ +# createFileManager() + +```ts +createFileManager(dataDir): FileManager +``` + +Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `dataDir` | `string` | root of the file system | + +## Returns + +`FileManager` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md new file mode 100644 index 00000000000..fcea9275341 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md @@ -0,0 +1,21 @@ +# inflateDebugSymbols() + +```ts +inflateDebugSymbols(debugSymbols): any +``` + +Decompresses and decodes the debug symbols + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `debugSymbols` | `string` | The base64 encoded debug symbols | + +## Returns + +`any` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/index.md b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/index.md new file mode 100644 index 00000000000..b6e0f9d1bc0 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/index.md @@ -0,0 +1,49 @@ +# noir_wasm + +## Exports + +### Functions + +| Function | Description | +| :------ | :------ | +| [compile](functions/compile.md) | Compiles a Noir project | +| [compile\_contract](functions/compile_contract.md) | Compiles a Noir project | +| [createFileManager](functions/createFileManager.md) | Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) | +| [inflateDebugSymbols](functions/inflateDebugSymbols.md) | Decompresses and decodes the debug symbols | + +## References + +### compile\_program + +Renames and re-exports [compile](functions/compile.md) + +## Interfaces + +### ContractCompilationArtifacts + +The compilation artifacts of a given contract. + +#### Properties + +| Property | Type | Description | +| :------ | :------ | :------ | +| `contract` | `ContractArtifact` | The compiled contract. | +| `warnings` | `unknown`[] | Compilation warnings. | + +*** + +### ProgramCompilationArtifacts + +The compilation artifacts of a given program. + +#### Properties + +| Property | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | not part of the compilation output, injected later | +| `program` | `ProgramArtifact` | The compiled contract. | +| `warnings` | `unknown`[] | Compilation warnings. | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs new file mode 100644 index 00000000000..e0870710349 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"doc","id":"reference/NoirJS/noir_wasm/index","label":"API"},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/compile","label":"compile"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/compile_contract","label":"compile_contract"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/createFileManager","label":"createFileManager"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/inflateDebugSymbols","label":"inflateDebugSymbols"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/reference/_category_.json b/docs/versioned_docs/version-v0.29.0/reference/_category_.json new file mode 100644 index 00000000000..5b6a20a609a --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 4, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/reference/debugger/_category_.json b/docs/versioned_docs/version-v0.29.0/reference/debugger/_category_.json new file mode 100644 index 00000000000..27869205ad3 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/debugger/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Debugger", + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_known_limitations.md b/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_known_limitations.md new file mode 100644 index 00000000000..936d416ac4b --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_known_limitations.md @@ -0,0 +1,59 @@ +--- +title: Known limitations +description: + An overview of known limitations of the current version of the Noir debugger +keywords: + [ + Nargo, + Noir Debugger, + VS Code, + ] +sidebar_position: 2 +--- + +# Debugger Known Limitations + +There are currently some limits to what the debugger can observe. + +## Mutable references + +The debugger is currently blind to any state mutated via a mutable reference. For example, in: + +``` +let mut x = 1; +let y = &mut x; +*y = 2; +``` + +The update on `x` will not be observed by the debugger. That means, when running `vars` from the debugger REPL, or inspecting the _local variables_ pane in the VS Code debugger, `x` will appear with value 1 despite having executed `*y = 2;`. + +## Variables of type function or mutable references are opaque + +When inspecting variables, any variable of type `Function` or `MutableReference` will render its value as `<>` or `<>`. + +## Debugger instrumentation affects resulting ACIR + +In order to make the state of local variables observable, the debugger compiles Noir circuits interleaving foreign calls that track any mutations to them. While this works (except in the cases described above) and doesn't introduce any behavior changes, it does as a side effect produce bigger bytecode. In particular, when running the command `opcodes` on the REPL debugger, you will notice Unconstrained VM blocks that look like this: + +``` +... +5 BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [], q_c: 2 }), Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(2))], q_c: 0 })] + | outputs=[] + 5.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 5.1 | Mov { destination: RegisterIndex(3), source: RegisterIndex(1) } + 5.2 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 5.3 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 5.4 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 5.5 | Mov { destination: RegisterIndex(3), source: RegisterIndex(3) } + 5.6 | Call { location: 8 } + 5.7 | Stop + 5.8 | ForeignCall { function: "__debug_var_assign", destinations: [], inputs: [RegisterIndex(RegisterIndex(2)), RegisterIndex(RegisterIndex(3))] } +... +``` + +If you are interested in debugging/inspecting compiled ACIR without these synthetic changes, you can invoke the REPL debugger with the `--skip-instrumentation` flag or launch the VS Code debugger with the `skipConfiguration` property set to true in its launch configuration. You can find more details about those in the [Debugger REPL reference](debugger_repl.md) and the [VS Code Debugger reference](debugger_vscode.md). + +:::note +Skipping debugger instrumentation means you won't be able to inspect values of local variables. +::: + diff --git a/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_repl.md b/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_repl.md new file mode 100644 index 00000000000..46e2011304e --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_repl.md @@ -0,0 +1,360 @@ +--- +title: REPL Debugger +description: + Noir Debugger REPL options and commands. +keywords: + [ + Nargo, + Noir CLI, + Noir Debugger, + REPL, + ] +sidebar_position: 1 +--- + +## Running the REPL debugger + +`nargo debug [OPTIONS] [WITNESS_NAME]` + +Runs the Noir REPL debugger. If a `WITNESS_NAME` is provided the debugger writes the resulting execution witness to a `WITNESS_NAME` file. + +### Options + +| Option | Description | +| --------------------- | ------------------------------------------------------------ | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover]| +| `--package ` | The name of the package to debug | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +None of these options are required. + +:::note +Since the debugger starts by compiling the target package, all Noir compiler options are also available. Check out the [compiler reference](../nargo_commands.md#nargo-compile) to learn more about the compiler options. +::: + +## REPL commands + +Once the debugger is running, it accepts the following commands. + +#### `help` (h) + +Displays the menu of available commands. + +``` +> help +Available commands: + + opcodes display ACIR opcodes + into step into to the next opcode + next step until a new source location is reached + out step until a new source location is reached + and the current stack frame is finished + break LOCATION:OpcodeLocation add a breakpoint at an opcode location + over step until a new source location is reached + without diving into function calls + restart restart the debugging session + delete LOCATION:OpcodeLocation delete breakpoint at an opcode location + witness show witness map + witness index:u32 display a single witness from the witness map + witness index:u32 value:String update a witness with the given value + memset index:usize value:String update a memory cell with the given + value + continue continue execution until the end of the + program + vars show variable values available at this point + in execution + stacktrace display the current stack trace + memory show memory (valid when executing unconstrained code) value + step step to the next ACIR opcode + +Other commands: + + help Show this help message + quit Quit repl + +``` + +### Stepping through programs + +#### `next` (n) + +Step until the next Noir source code location. While other commands, such as [`into`](#into-i) and [`step`](#step-s), allow for finer grained control of the program's execution at the opcode level, `next` is source code centric. For example: + +``` +3 ... +4 fn main(x: u32) { +5 assert(entry_point(x) == 2); +6 swap_entry_point(x, x + 1); +7 -> assert(deep_entry_point(x) == 4); +8 multiple_values_entry_point(x); +9 } +``` + + +Using `next` here would cause the debugger to jump to the definition of `deep_entry_point` (if available). + +If you want to step over `deep_entry_point` and go straight to line 8, use [the `over` command](#over) instead. + +#### `over` + +Step until the next source code location, without diving into function calls. For example: + +``` +3 ... +4 fn main(x: u32) { +5 assert(entry_point(x) == 2); +6 swap_entry_point(x, x + 1); +7 -> assert(deep_entry_point(x) == 4); +8 multiple_values_entry_point(x); +9 } +``` + + +Using `over` here would cause the debugger to execute until line 8 (`multiple_values_entry_point(x);`). + +If you want to step into `deep_entry_point` instead, use [the `next` command](#next-n). + +#### `out` + +Step until the end of the current function call. For example: + +``` + 3 ... + 4 fn main(x: u32) { + 5 assert(entry_point(x) == 2); + 6 swap_entry_point(x, x + 1); + 7 -> assert(deep_entry_point(x) == 4); + 8 multiple_values_entry_point(x); + 9 } + 10 + 11 unconstrained fn returns_multiple_values(x: u32) -> (u32, u32, u32, u32) { + 12 ... + ... + 55 + 56 unconstrained fn deep_entry_point(x: u32) -> u32 { + 57 -> level_1(x + 1) + 58 } + +``` + +Running `out` here will resume execution until line 8. + +#### `step` (s) + +Skips to the next ACIR code. A compiled Noir program is a sequence of ACIR opcodes. However, an unconstrained VM opcode denotes the start of an unconstrained code block, to be executed by the unconstrained VM. For example (redacted for brevity): + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +The `->` here shows the debugger paused at an ACIR opcode: `BRILLIG`, at index 1, which denotes an unconstrained code block is about to start. + +Using the `step` command at this point would result in the debugger stopping at ACIR opcode 2, `EXPR`, skipping unconstrained computation steps. + +Use [the `into` command](#into-i) instead if you want to follow unconstrained computation step by step. + +#### `into` (i) + +Steps into the next opcode. A compiled Noir program is a sequence of ACIR opcodes. However, a BRILLIG opcode denotes the start of an unconstrained code block, to be executed by the unconstrained VM. For example (redacted for brevity): + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +The `->` here shows the debugger paused at an ACIR opcode: `BRILLIG`, at index 1, which denotes an unconstrained code block is about to start. + +Using the `into` command at this point would result in the debugger stopping at opcode 1.0, `Mov ...`, allowing the debugger user to follow unconstrained computation step by step. + +Use [the `step` command](#step-s) instead if you want to skip to the next ACIR code directly. + +#### `continue` (c) + +Continues execution until the next breakpoint, or the end of the program. + +#### `restart` (res) + +Interrupts execution, and restarts a new debugging session from scratch. + +#### `opcodes` (o) + +Display the program's ACIR opcode sequence. For example: + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +### Breakpoints + +#### `break [Opcode]` (or shorthand `b [Opcode]`) + +Sets a breakpoint on the specified opcode index. To get a list of the program opcode numbers, see [the `opcode` command](#opcodes-o). For example: + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +In this example, issuing a `break 1.2` command adds break on opcode 1.2, as denoted by the `*` character: + +``` +0 BLACKBOX::RANGE [(_0, num_bits: 32)] [ ] +1 -> BRILLIG inputs=[Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(0))], q_c: 0 })] outputs=[Simple(Witness(1))] + 1.0 | Mov { destination: RegisterIndex(2), source: RegisterIndex(0) } + 1.1 | Const { destination: RegisterIndex(0), value: Value { inner: 0 } } + 1.2 | * Const { destination: RegisterIndex(1), value: Value { inner: 0 } } + 1.3 | Mov { destination: RegisterIndex(2), source: RegisterIndex(2) } + 1.4 | Call { location: 7 } + ... + 1.43 | Return +2 EXPR [ (1, _1) -2 ] +``` + +Running [the `continue` command](#continue-c) at this point would cause the debugger to execute the program until opcode 1.2. + +#### `delete [Opcode]` (or shorthand `d [Opcode]`) + +Deletes a breakpoint at an opcode location. Usage is analogous to [the `break` command](#). + +### Variable inspection + +#### vars + +Show variable values available at this point in execution. + +:::note +The ability to inspect variable values from the debugger depends on compilation to be run in a special debug instrumentation mode. This instrumentation weaves variable tracing code with the original source code. + +So variable value inspection comes at the expense of making the resulting ACIR bytecode bigger and harder to understand and optimize. + +If you find this compromise unacceptable, you can run the debugger with the flag `--skip-debug-instrumentation`. This will compile your circuit without any additional debug information, so the resulting ACIR bytecode will be identical to the one produced by standard Noir compilation. However, if you opt for this, the `vars` command will not be available while debugging. +::: + + +### Stacktrace + +#### `stacktrace` + +Displays the current stack trace. + + +### Witness map + +#### `witness` (w) + +Show witness map. For example: + +``` +_0 = 0 +_1 = 2 +_2 = 1 +``` + +#### `witness [Witness Index]` + +Display a single witness from the witness map. For example: + +``` +> witness 1 +_1 = 2 +``` + +#### `witness [Witness Index] [New value]` + +Overwrite the given index with a new value. For example: + +``` +> witness 1 3 +_1 = 3 +``` + + +### Unconstrained VM memory + +#### `memory` + +Show unconstrained VM memory state. For example: + +``` +> memory +At opcode 1.13: Store { destination_pointer: RegisterIndex(0), source: RegisterIndex(3) } +... +> registers +0 = 0 +1 = 10 +2 = 0 +3 = 1 +4 = 1 +5 = 2³² +6 = 1 +> into +At opcode 1.14: Const { destination: RegisterIndex(5), value: Value { inner: 1 } } +... +> memory +0 = 1 +> +``` + +In the example above: we start with clean memory, then step through a `Store` opcode which stores the value of register 3 (1) into the memory address stored in register 0 (0). Thus now `memory` shows memory address 0 contains value 1. + +:::note +This command is only functional while the debugger is executing unconstrained code. +::: + +#### `memset [Memory address] [New value]` + +Update a memory cell with the given value. For example: + +``` +> memory +0 = 1 +> memset 0 2 +> memory +0 = 2 +> memset 1 4 +> memory +0 = 2 +1 = 4 +> +``` + +:::note +This command is only functional while the debugger is executing unconstrained code. +::: \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_vscode.md b/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_vscode.md new file mode 100644 index 00000000000..c027332b3b0 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/debugger/debugger_vscode.md @@ -0,0 +1,82 @@ +--- +title: VS Code Debugger +description: + VS Code Debugger configuration and features. +keywords: + [ + Nargo, + Noir CLI, + Noir Debugger, + VS Code, + IDE, + ] +sidebar_position: 0 +--- + +# VS Code Noir Debugger Reference + +The Noir debugger enabled by the vscode-noir extension ships with default settings such that the most common scenario should run without any additional configuration steps. + +These defaults can nevertheless be overridden by defining a launch configuration file. This page provides a reference for the properties you can override via a launch configuration file, as well as documenting the Nargo `dap` command, which is a dependency of the VS Code Noir debugger. + + +## Creating and editing launch configuration files + +To create a launch configuration file from VS Code, open the _debug pane_, and click on _create a launch.json file_. + +![Creating a launch configuration file](@site/static/img/debugger/ref1-create-launch.png) + +A `launch.json` file will be created, populated with basic defaults. + +### Noir Debugger launch.json properties + +#### projectFolder + +_String, optional._ + +Absolute path to the Nargo project to debug. By default, it is dynamically determined by looking for the nearest `Nargo.toml` file to the active file at the moment of launching the debugger. + +#### proverName + +_String, optional._ + +Name of the prover input to use. Defaults to `Prover`, which looks for a file named `Prover.toml` at the `projectFolder`. + +#### generateAcir + +_Boolean, optional._ + +If true, generate ACIR opcodes instead of unconstrained opcodes which will be closer to release binaries but less convenient for debugging. Defaults to `false`. + +#### skipInstrumentation + +_Boolean, optional._ + +Skips variables debugging instrumentation of code, making debugging less convenient but the resulting binary smaller and closer to production. Defaults to `false`. + +:::note +Skipping instrumentation causes the debugger to be unable to inspect local variables. +::: + +## `nargo dap [OPTIONS]` + +When run without any option flags, it starts the Nargo Debug Adapter Protocol server, which acts as the debugging backend for the VS Code Noir Debugger. + +All option flags are related to preflight checks. The Debug Adapter Protocol specifies how errors are to be informed from a running DAP server, but it doesn't specify mechanisms to communicate server initialization errors between the DAP server and its client IDE. + +Thus `nargo dap` ships with a _preflight check_ mode. If flag `--preflight-check` and the rest of the `--preflight-*` flags are provided, Nargo will run the same initialization routine except it will not start the DAP server. + +`vscode-noir` will then run `nargo dap` in preflight check mode first before a debugging session starts. If the preflight check ends in error, vscode-noir will present stderr and stdout output from this process through its own Output pane in VS Code. This makes it possible for users to diagnose what pieces of configuration might be wrong or missing in case of initialization errors. + +If the preflight check succeeds, `vscode-noir` proceeds to start the DAP server normally but running `nargo dap` without any additional flags. + +### Options + +| Option | Description | +| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `--preflight-check` | If present, dap runs in preflight check mode. | +| `--preflight-project-folder ` | Absolute path to the project to debug for preflight check. | +| `--preflight-prover-name ` | Name of prover file to use for preflight check | +| `--preflight-generate-acir` | Optional. If present, compile in ACIR mode while running preflight check. | +| `--preflight-skip-instrumentation` | Optional. If present, compile without introducing debug instrumentation while running preflight check. | +| `-h, --help` | Print help. | diff --git a/docs/versioned_docs/version-v0.29.0/reference/nargo_commands.md b/docs/versioned_docs/version-v0.29.0/reference/nargo_commands.md new file mode 100644 index 00000000000..218fcfb0c8c --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/reference/nargo_commands.md @@ -0,0 +1,381 @@ +--- +title: Nargo +description: + Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, + generate Solidity verifier smart contract and compile into JSON file containing ACIR + representation and ABI of circuit. +keywords: + [ + Nargo, + Noir CLI, + Noir Prover, + Noir Verifier, + generate Solidity verifier, + compile JSON file, + ACIR representation, + ABI of circuit, + TypeScript, + ] +sidebar_position: 0 +--- + +# Command-Line Help for `nargo` + +This document contains the help content for the `nargo` command-line program. + +**Command Overview:** + +* [`nargo`↴](#nargo) +* [`nargo backend`↴](#nargo-backend) +* [`nargo backend current`↴](#nargo-backend-current) +* [`nargo backend ls`↴](#nargo-backend-ls) +* [`nargo backend use`↴](#nargo-backend-use) +* [`nargo backend install`↴](#nargo-backend-install) +* [`nargo backend uninstall`↴](#nargo-backend-uninstall) +* [`nargo check`↴](#nargo-check) +* [`nargo fmt`↴](#nargo-fmt) +* [`nargo codegen-verifier`↴](#nargo-codegen-verifier) +* [`nargo compile`↴](#nargo-compile) +* [`nargo new`↴](#nargo-new) +* [`nargo init`↴](#nargo-init) +* [`nargo execute`↴](#nargo-execute) +* [`nargo prove`↴](#nargo-prove) +* [`nargo verify`↴](#nargo-verify) +* [`nargo test`↴](#nargo-test) +* [`nargo info`↴](#nargo-info) +* [`nargo lsp`↴](#nargo-lsp) + +## `nargo` + +Noir's package manager + +**Usage:** `nargo ` + +###### **Subcommands:** + +* `backend` — Install and select custom backends used to generate and verify proofs +* `check` — Checks the constraint system for errors +* `fmt` — Format the Noir files in a workspace +* `codegen-verifier` — Generates a Solidity verifier smart contract for the program +* `compile` — Compile the program and its secret execution trace into ACIR format +* `new` — Create a Noir project in a new directory +* `init` — Create a Noir project in the current directory +* `execute` — Executes a circuit to calculate its return value +* `prove` — Create proof for this program. The proof is returned as a hex encoded string +* `verify` — Given a proof and a program, verify whether the proof is valid +* `test` — Run the tests for this program +* `info` — Provides detailed information on each of a program's function (represented by a single circuit) +* `lsp` — Starts the Noir LSP server + +###### **Options:** + + + + +## `nargo backend` + +Install and select custom backends used to generate and verify proofs + +**Usage:** `nargo backend ` + +###### **Subcommands:** + +* `current` — Prints the name of the currently active backend +* `ls` — Prints the list of currently installed backends +* `use` — Select the backend to use +* `install` — Install a new backend from a URL +* `uninstall` — Uninstalls a backend + + + +## `nargo backend current` + +Prints the name of the currently active backend + +**Usage:** `nargo backend current` + + + +## `nargo backend ls` + +Prints the list of currently installed backends + +**Usage:** `nargo backend ls` + + + +## `nargo backend use` + +Select the backend to use + +**Usage:** `nargo backend use ` + +###### **Arguments:** + +* `` + + + +## `nargo backend install` + +Install a new backend from a URL + +**Usage:** `nargo backend install ` + +###### **Arguments:** + +* `` — The name of the backend to install +* `` — The URL from which to download the backend + + + +## `nargo backend uninstall` + +Uninstalls a backend + +**Usage:** `nargo backend uninstall ` + +###### **Arguments:** + +* `` — The name of the backend to uninstall + + + +## `nargo check` + +Checks the constraint system for errors + +**Usage:** `nargo check [OPTIONS]` + +###### **Options:** + +* `--package ` — The name of the package to check +* `--workspace` — Check all packages in the workspace +* `--overwrite` — Force overwrite of existing files +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo fmt` + +Format the Noir files in a workspace + +**Usage:** `nargo fmt [OPTIONS]` + +###### **Options:** + +* `--check` — Run noirfmt in check mode + + + +## `nargo codegen-verifier` + +Generates a Solidity verifier smart contract for the program + +**Usage:** `nargo codegen-verifier [OPTIONS]` + +###### **Options:** + +* `--package ` — The name of the package to codegen +* `--workspace` — Codegen all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo compile` + +Compile the program and its secret execution trace into ACIR format + +**Usage:** `nargo compile [OPTIONS]` + +###### **Options:** + +* `--package ` — The name of the package to compile +* `--workspace` — Compile all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo new` + +Create a Noir project in a new directory + +**Usage:** `nargo new [OPTIONS] ` + +###### **Arguments:** + +* `` — The path to save the new project + +###### **Options:** + +* `--name ` — Name of the package [default: package directory name] +* `--lib` — Use a library template +* `--bin` — Use a binary template [default] +* `--contract` — Use a contract template + + + +## `nargo init` + +Create a Noir project in the current directory + +**Usage:** `nargo init [OPTIONS]` + +###### **Options:** + +* `--name ` — Name of the package [default: current directory name] +* `--lib` — Use a library template +* `--bin` — Use a binary template [default] +* `--contract` — Use a contract template + + + +## `nargo execute` + +Executes a circuit to calculate its return value + +**Usage:** `nargo execute [OPTIONS] [WITNESS_NAME]` + +###### **Arguments:** + +* `` — Write the execution witness to named file + +###### **Options:** + +* `-p`, `--prover-name ` — The name of the toml file which contains the inputs for the prover + + Default value: `Prover` +* `--package ` — The name of the package to execute +* `--workspace` — Execute all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings +* `--oracle-resolver ` — JSON RPC url to solve oracle calls + + + +## `nargo prove` + +Create proof for this program. The proof is returned as a hex encoded string + +**Usage:** `nargo prove [OPTIONS]` + +###### **Options:** + +* `-p`, `--prover-name ` — The name of the toml file which contains the inputs for the prover + + Default value: `Prover` +* `-v`, `--verifier-name ` — The name of the toml file which contains the inputs for the verifier + + Default value: `Verifier` +* `--verify` — Verify proof after proving +* `--package ` — The name of the package to prove +* `--workspace` — Prove all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings +* `--oracle-resolver ` — JSON RPC url to solve oracle calls + + + +## `nargo verify` + +Given a proof and a program, verify whether the proof is valid + +**Usage:** `nargo verify [OPTIONS]` + +###### **Options:** + +* `-v`, `--verifier-name ` — The name of the toml file which contains the inputs for the verifier + + Default value: `Verifier` +* `--package ` — The name of the package verify +* `--workspace` — Verify all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo test` + +Run the tests for this program + +**Usage:** `nargo test [OPTIONS] [TEST_NAME]` + +###### **Arguments:** + +* `` — If given, only tests with names containing this string will be run + +###### **Options:** + +* `--show-output` — Display output of `println` statements +* `--exact` — Only run tests that match exactly +* `--package ` — The name of the package to test +* `--workspace` — Test all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings +* `--oracle-resolver ` — JSON RPC url to solve oracle calls + + + +## `nargo info` + +Provides detailed information on each of a program's function (represented by a single circuit) + +Current information provided per circuit: 1. The number of ACIR opcodes 2. Counts the final number gates in the circuit used by a backend + +**Usage:** `nargo info [OPTIONS]` + +###### **Options:** + +* `--package ` — The name of the package to detail +* `--workspace` — Detail all packages in the workspace +* `--expression-width ` — Override the expression width requested by the backend +* `--force` — Force a full recompilation +* `--print-acir` — Display the ACIR for compiled circuit +* `--deny-warnings` — Treat all warnings as errors +* `--silence-warnings` — Suppress warnings + + + +## `nargo lsp` + +Starts the Noir LSP server + +Starts an LSP server which allows IDEs such as VS Code to display diagnostics in Noir source. + +VS Code Noir Language Support: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir + +**Usage:** `nargo lsp` + + + +
+ + + This document was generated automatically by + clap-markdown. + + diff --git a/docs/versioned_docs/version-v0.29.0/tooling/debugger.md b/docs/versioned_docs/version-v0.29.0/tooling/debugger.md new file mode 100644 index 00000000000..184c436068f --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/tooling/debugger.md @@ -0,0 +1,27 @@ +--- +title: Debugger +description: Learn about the Noir Debugger, in its REPL or VS Code versions. +keywords: [Nargo, VSCode, Visual Studio Code, REPL, Debugger] +sidebar_position: 2 +--- + +# Noir Debugger + +There are currently two ways of debugging Noir programs: + +1. From VS Code, via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). +2. Via the REPL debugger, which ships with Nargo. + +In order to use either version of the debugger, you will need to install recent enough versions of Noir, [Nargo](../getting_started/installation) and vscode-noir: + +- Noir 0.xx +- Nargo 0.xx +- vscode-noir 0.xx + +:::info +At the moment, the debugger supports debugging binary projects, but not contracts. +::: + +We cover the VS Code Noir debugger more in depth in [its VS Code debugger how-to guide](../how_to/debugger/debugging_with_vs_code.md) and [the reference](../reference/debugger/debugger_vscode.md). + +The REPL debugger is discussed at length in [the REPL debugger how-to guide](../how_to/debugger/debugging_with_the_repl.md) and [the reference](../reference/debugger/debugger_repl.md). diff --git a/docs/versioned_docs/version-v0.29.0/tooling/language_server.md b/docs/versioned_docs/version-v0.29.0/tooling/language_server.md new file mode 100644 index 00000000000..81e0356ef8a --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/tooling/language_server.md @@ -0,0 +1,43 @@ +--- +title: Language Server +description: Learn about the Noir Language Server, how to install the components, and configuration that may be required. +keywords: [Nargo, Language Server, LSP, VSCode, Visual Studio Code] +sidebar_position: 0 +--- + +This section helps you install and configure the Noir Language Server. + +The Language Server Protocol (LSP) has two components, the [Server](#language-server) and the [Client](#language-client). Below we describe each in the context of Noir. + +## Language Server + +The Server component is provided by the Nargo command line tool that you installed at the beginning of this guide. +As long as Nargo is installed and you've used it to run other commands in this guide, it should be good to go! + +If you'd like to verify that the `nargo lsp` command is available, you can run `nargo --help` and look for `lsp` in the list of commands. If you see it, you're using a version of Noir with LSP support. + +## Language Client + +The Client component is usually an editor plugin that launches the Server. It communicates LSP messages between the editor and the Server. For example, when you save a file, the Client will alert the Server, so it can try to compile the project and report any errors. + +Currently, Noir provides a Language Client for Visual Studio Code via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). + +> **Note:** Noir's Language Server Protocol support currently assumes users' VSCode workspace root to be the same as users' Noir project root (i.e. where Nargo.toml lies). +> +> If LSP features seem to be missing / malfunctioning, make sure you are opening your Noir project directly (instead of as a sub-folder) in your VSCode instance. + +When your language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, measuring circuit size, execution, and tests: + +![Compile and Execute](@site/static/img/codelens_compile_execute.png) +![Run test](@site/static/img/codelens_run_test.png) + +You should also see your tests in the `testing` panel: + +![Testing panel](@site/static/img/codelens_testing_panel.png) + +### Configuration + +- **Noir: Enable LSP** - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. +- **Noir: Nargo Flags** - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. +- **Noir: Nargo Path** - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. +- **Noir > Trace: Server** - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. diff --git a/docs/versioned_docs/version-v0.29.0/tooling/testing.md b/docs/versioned_docs/version-v0.29.0/tooling/testing.md new file mode 100644 index 00000000000..d3e0c522473 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/tooling/testing.md @@ -0,0 +1,62 @@ +--- +title: Testing in Noir +description: Learn how to use Nargo to test your Noir program in a quick and easy way +keywords: [Nargo, testing, Noir, compile, test] +sidebar_position: 1 +--- + +You can test your Noir programs using Noir circuits. + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. + +For example if you have a program like: + +```rust +fn add(x: u64, y: u64) -> u64 { + x + y +} +#[test] +fn test_add() { + assert(add(2,2) == 4); + assert(add(0,1) == 1); + assert(add(1,0) == 1); +} +``` + +Running `nargo test` will test that the `test_add` function can be executed while satisfying all +the constraints which allows you to test that add returns the expected values. Test functions can't +have any arguments currently. + +### Test fail + +You can write tests that are expected to fail by using the decorator `#[test(should_fail)]`. For example: + +```rust +fn add(x: u64, y: u64) -> u64 { + x + y +} +#[test(should_fail)] +fn test_add() { + assert(add(2,2) == 5); +} +``` + +You can be more specific and make it fail with a specific reason by using `should_fail_with = "`: + +```rust +fn main(african_swallow_avg_speed : Field) { + assert(african_swallow_avg_speed == 65, "What is the airspeed velocity of an unladen swallow"); +} + +#[test] +fn test_king_arthur() { + main(65); +} + +#[test(should_fail_with = "What is the airspeed velocity of an unladen swallow")] +fn test_bridgekeeper() { + main(32); +} + +``` diff --git a/docs/versioned_docs/version-v0.29.0/tutorials/noirjs_app.md b/docs/versioned_docs/version-v0.29.0/tutorials/noirjs_app.md new file mode 100644 index 00000000000..6446e0b2a76 --- /dev/null +++ b/docs/versioned_docs/version-v0.29.0/tutorials/noirjs_app.md @@ -0,0 +1,326 @@ +--- +title: Building a web app with NoirJS +description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment. +keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs, app] +sidebar_position: 0 +pagination_next: noir/concepts/data_types/index +--- + +NoirJS is a set of packages meant to work both in a browser and a server environment. In this tutorial, we will build a simple web app using them. From here, you should get an idea on how to proceed with your own Noir projects! + +You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). + +## Setup + +:::note + +Feel free to use whatever versions, just keep in mind that Nargo and the NoirJS packages are meant to be in sync. For example, Nargo 0.27.x matches `noir_js@0.27.x`, etc. + +In this guide, we will be pinned to 0.27.0. + +::: + +Before we start, we want to make sure we have Node and Nargo installed. + +We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). + +As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: + +```sh +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Easy enough. Onwards! + +## Our project + +ZK is a powerful technology. An app that doesn't reveal one of the inputs to _anyone_ is almost unbelievable, yet Noir makes it as easy as a single line of code. + +In fact, it's so simple that it comes nicely packaged in `nargo`. Let's do that! + +### Nargo + +Run: + +`nargo new circuit` + +And... That's about it. Your program is ready to be compiled and run. + +To compile, let's `cd` into the `circuit` folder to enter our project, and call: + +`nargo compile` + +This compiles our circuit into `json` format and add it to a new `target` folder. + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit <---- our working directory + ├── Nargo.toml + ├── src + │ └── main.nr + └── target + └── circuit.json +``` + +::: + +### Node and Vite + +If you want to explore Nargo, feel free to go on a side-quest now and follow the steps in the +[getting started](../getting_started/hello_noir/index.md) guide. However, we want our app to run on the browser, so we need Vite. + +Vite is a powerful tool to generate static websites. While it provides all kinds of features, let's just go barebones with some good old vanilla JS. + +To do this this, go back to the previous folder (`cd ..`) and create a new vite project by running `npm create vite` and choosing "Vanilla" and "Javascript". + +A wild `vite-project` directory should now appear in your root folder! Let's not waste any time and dive right in: + +```bash +cd vite-project +``` + +### Setting Up Vite and Configuring the Project + +Before we proceed with any coding, let's get our environment tailored for Noir. We'll start by laying down the foundations with a `vite.config.js` file. This little piece of configuration is our secret sauce for making sure everything meshes well with the NoirJS libraries and other special setups we might need, like handling WebAssembly modules. Here’s how you get that going: + +#### Creating the vite.config.js + +In your freshly minted `vite-project` folder, create a new file named `vite.config.js` and open it in your code editor. Paste the following to set the stage: + +```javascript +import { defineConfig } from "vite"; +import copy from "rollup-plugin-copy"; + +export default defineConfig({ + esbuild: { + target: "esnext", + }, + optimizeDeps: { + esbuildOptions: { + target: "esnext", + }, + }, + plugins: [ + copy({ + targets: [ + { src: "node_modules/**/*.wasm", dest: "node_modules/.vite/dist" }, + ], + copySync: true, + hook: "buildStart", + }), + ], + server: { + port: 3000, + }, +}); +``` + +#### Install Dependencies + +Now that our stage is set, install the necessary NoirJS packages along with our other dependencies: + +```bash +npm install && npm install @noir-lang/backend_barretenberg@0.27.0 @noir-lang/noir_js@0.27.0 +npm install rollup-plugin-copy --save-dev +``` + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit + └── ...etc... +└── vite-project <---- our working directory + └── ...etc... +``` + +::: + +#### Some cleanup + +`npx create vite` is amazing but it creates a bunch of files we don't really need for our simple example. Actually, let's just delete everything except for `vite.config.js`, `index.html`, `main.js` and `package.json`. I feel lighter already. + +![my heart is ready for you, noir.js](@site/static/img/memes/titanic.jpeg) + +## HTML + +Our app won't run like this, of course. We need some working HTML, at least. Let's open our broken-hearted `index.html` and replace everything with this code snippet: + +```html + + + + + + +

Noir app

+
+ + +
+
+

Logs

+

Proof

+
+ + +``` + +It _could_ be a beautiful UI... Depending on which universe you live in. + +## Some good old vanilla Javascript + +Our love for Noir needs undivided attention, so let's just open `main.js` and delete everything (this is where the romantic scenery becomes a bit creepy). + +Start by pasting in this boilerplate code: + +```js +const setup = async () => { + await Promise.all([ + import('@noir-lang/noirc_abi').then((module) => + module.default(new URL('@noir-lang/noirc_abi/web/noirc_abi_wasm_bg.wasm', import.meta.url).toString()), + ), + import('@noir-lang/acvm_js').then((module) => + module.default(new URL('@noir-lang/acvm_js/web/acvm_js_bg.wasm', import.meta.url).toString()), + ), + ]); +}; + +function display(container, msg) { + const c = document.getElementById(container); + const p = document.createElement('p'); + p.textContent = msg; + c.appendChild(p); +} + +document.getElementById('submitGuess').addEventListener('click', async () => { + try { + // here's where love happens + } catch (err) { + display('logs', 'Oh 💔 Wrong guess'); + } +}); +``` + +The display function doesn't do much. We're simply manipulating our website to see stuff happening. For example, if the proof fails, it will simply log a broken heart 😢 + +As for the `setup` function, it's just a sad reminder that dealing with `wasm` on the browser is not as easy as it should. Just copy, paste, and forget. + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit + └── ...same as above +└── vite-project + ├── vite.config.js + ├── main.js + ├── package.json + └── index.html +``` + +You'll see other files and folders showing up (like `package-lock.json`, `node_modules`) but you shouldn't have to care about those. + +::: + +## Some NoirJS + +We're starting with the good stuff now. If you've compiled the circuit as described above, you should have a `json` file we want to import at the very top of our `main.js` file: + +```ts +import circuit from '../circuit/target/circuit.json'; +``` + +[Noir is backend-agnostic](../index.mdx#whats-new-about-noir). We write Noir, but we also need a proving backend. That's why we need to import and instantiate the two dependencies we installed above: `BarretenbergBackend` and `Noir`. Let's import them right below: + +```js +import { BarretenbergBackend, BarretenbergVerifier as Verifier } from '@noir-lang/backend_barretenberg'; +import { Noir } from '@noir-lang/noir_js'; +``` + +And instantiate them inside our try-catch block: + +```ts +// try { +const backend = new BarretenbergBackend(circuit); +const noir = new Noir(circuit, backend); +// } +``` + +:::note + +For the remainder of the tutorial, everything will be happening inside the `try` block + +::: + +## Our app + +Now for the app itself. We're capturing whatever is in the input when people press the submit button. Just add this: + +```js +const x = parseInt(document.getElementById('guessInput').value); +const input = { x, y: 2 }; +``` + +Now we're ready to prove stuff! Let's feed some inputs to our circuit and calculate the proof: + +```js +await setup(); // let's squeeze our wasm inits here + +display('logs', 'Generating proof... ⌛'); +const proof = await noir.generateProof(input); +display('logs', 'Generating proof... ✅'); +display('results', proof.proof); +``` + +You're probably eager to see stuff happening, so go and run your app now! + +From your terminal, run `npm run dev`. If it doesn't open a browser for you, just visit `localhost:5173`. You should now see the worst UI ever, with an ugly input. + +![Getting Started 0](@site/static/img/noir_getting_started_1.png) + +Now, our circuit says `fn main(x: Field, y: pub Field)`. This means only the `y` value is public, and it's hardcoded above: `input = { x, y: 2 }`. In other words, you won't need to send your secret`x` to the verifier! + +By inputting any number other than 2 in the input box and clicking "submit", you should get a valid proof. Otherwise the proof won't even generate correctly. By the way, if you're human, you shouldn't be able to understand anything on the "proof" box. That's OK. We like you, human ❤️. + +## Verifying + +Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add these lines to see our proof being verified: + +```js +display('logs', 'Verifying proof... ⌛'); +const verificationKey = await backend.getVerificationKey(); +const verifier = new Verifier(); +const isValid = await verifier.verifyProof(proof, verificationKey); +if (isValid) display('logs', 'Verifying proof... ✅'); +``` + +You have successfully generated a client-side Noir web app! + +![coded app without math knowledge](@site/static/img/memes/flextape.jpeg) + +## Further Reading + +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. + +You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/docs/versioned_sidebars/version-v0.28.0-sidebars.json b/docs/versioned_sidebars/version-v0.28.0-sidebars.json new file mode 100644 index 00000000000..b9ad026f69f --- /dev/null +++ b/docs/versioned_sidebars/version-v0.28.0-sidebars.json @@ -0,0 +1,93 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "The Noir Language", + "items": [ + { + "type": "autogenerated", + "dirName": "noir" + } + ] + }, + { + "type": "html", + "value": "
", + "defaultStyle": true + }, + { + "type": "category", + "label": "How To Guides", + "items": [ + { + "type": "autogenerated", + "dirName": "how_to" + } + ] + }, + { + "type": "category", + "label": "Explainers", + "items": [ + { + "type": "autogenerated", + "dirName": "explainers" + } + ] + }, + { + "type": "category", + "label": "Tutorials", + "items": [ + { + "type": "autogenerated", + "dirName": "tutorials" + } + ] + }, + { + "type": "category", + "label": "Reference", + "items": [ + { + "type": "autogenerated", + "dirName": "reference" + } + ] + }, + { + "type": "category", + "label": "Tooling", + "items": [ + { + "type": "autogenerated", + "dirName": "tooling" + } + ] + }, + { + "type": "html", + "value": "
", + "defaultStyle": true + }, + { + "type": "doc", + "id": "migration_notes", + "label": "Migration notes" + } + ] +} diff --git a/docs/versioned_sidebars/version-v0.29.0-sidebars.json b/docs/versioned_sidebars/version-v0.29.0-sidebars.json new file mode 100644 index 00000000000..b9ad026f69f --- /dev/null +++ b/docs/versioned_sidebars/version-v0.29.0-sidebars.json @@ -0,0 +1,93 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "The Noir Language", + "items": [ + { + "type": "autogenerated", + "dirName": "noir" + } + ] + }, + { + "type": "html", + "value": "
", + "defaultStyle": true + }, + { + "type": "category", + "label": "How To Guides", + "items": [ + { + "type": "autogenerated", + "dirName": "how_to" + } + ] + }, + { + "type": "category", + "label": "Explainers", + "items": [ + { + "type": "autogenerated", + "dirName": "explainers" + } + ] + }, + { + "type": "category", + "label": "Tutorials", + "items": [ + { + "type": "autogenerated", + "dirName": "tutorials" + } + ] + }, + { + "type": "category", + "label": "Reference", + "items": [ + { + "type": "autogenerated", + "dirName": "reference" + } + ] + }, + { + "type": "category", + "label": "Tooling", + "items": [ + { + "type": "autogenerated", + "dirName": "tooling" + } + ] + }, + { + "type": "html", + "value": "
", + "defaultStyle": true + }, + { + "type": "doc", + "id": "migration_notes", + "label": "Migration notes" + } + ] +} diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 5a9f9470a1f..00000000000 --- a/flake.lock +++ /dev/null @@ -1,170 +0,0 @@ -{ - "nodes": { - "crane": { - "inputs": { - "flake-compat": [ - "flake-compat" - ], - "flake-utils": [ - "flake-utils" - ], - "nixpkgs": [ - "nixpkgs" - ], - "rust-overlay": "rust-overlay" - }, - "locked": { - "lastModified": 1681177078, - "narHash": "sha256-ZNIjBDou2GOabcpctiQykEQVkI8BDwk7TyvlWlI4myE=", - "owner": "ipetkov", - "repo": "crane", - "rev": "0c9f468ff00576577d83f5019a66c557ede5acf6", - "type": "github" - }, - "original": { - "owner": "ipetkov", - "repo": "crane", - "type": "github" - } - }, - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src" - }, - "locked": { - "lastModified": 1694499657, - "narHash": "sha256-u/fZtLtN7VcDrMMVrdsFy93PEkaiK+tNpJT9on4SGdU=", - "owner": "nix-community", - "repo": "fenix", - "rev": "2895ff377cbb3cb6f5dd92066734b0447cb04e20", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1695559356, - "narHash": "sha256-kXZ1pUoImD9OEbPCwpTz4tHsNTr4CIyIfXb3ocuR8sI=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "261abe8a44a7e8392598d038d2e01f7b33cf26d0", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-23.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "crane": "crane", - "fenix": "fenix", - "flake-compat": "flake-compat", - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" - } - }, - "rust-analyzer-src": { - "flake": false, - "locked": { - "lastModified": 1694421477, - "narHash": "sha256-df6YZzR57VFzkOPwIohJfC0fRwgq6yUPbMJkKAtQyAE=", - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "cc6c8209cbaf7df55013977cf5cc8488d6b7ff1c", - "type": "github" - }, - "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", - "type": "github" - } - }, - "rust-overlay": { - "inputs": { - "flake-utils": [ - "crane", - "flake-utils" - ], - "nixpkgs": [ - "crane", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1694484610, - "narHash": "sha256-aeSDkp7fkAqtVjW3QUn7vq7BKNlFul/BiGgdv7rK+mA=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "c5b977a7e6a295697fa1f9c42174fd6313b38df4", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/noir_stdlib/src/aes128.nr b/noir_stdlib/src/aes128.nr new file mode 100644 index 00000000000..ac5c2b48ad8 --- /dev/null +++ b/noir_stdlib/src/aes128.nr @@ -0,0 +1,5 @@ + +#[foreign(aes128_encrypt)] +// docs:start:aes128 +pub fn aes128_encrypt(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8] {} +// docs:end:aes128 diff --git a/noir_stdlib/src/collections/bounded_vec.nr b/noir_stdlib/src/collections/bounded_vec.nr index c6a3365a979..65f3716dd34 100644 --- a/noir_stdlib/src/collections/bounded_vec.nr +++ b/noir_stdlib/src/collections/bounded_vec.nr @@ -1,4 +1,4 @@ -use crate::cmp::Eq; +use crate::{cmp::Eq, convert::From}; struct BoundedVec { storage: [T; MaxLen], @@ -74,6 +74,13 @@ impl BoundedVec { self.len = new_len; } + pub fn from_array(array: [T; Len]) -> Self { + assert(Len <= MaxLen, "from array out of bounds"); + let mut vec: BoundedVec = BoundedVec::new(); + vec.extend_from_array(array); + vec + } + pub fn pop(&mut self) -> T { assert(self.len > 0); self.len -= 1; @@ -107,6 +114,12 @@ impl Eq for BoundedVec where T: Eq { } } +impl From<[T; Len]> for BoundedVec { + fn from(array: [T; Len]) -> BoundedVec { + BoundedVec::from_array(array) + } +} + mod bounded_vec_tests { // TODO: Allow imports from "super" use crate::collections::bounded_vec::BoundedVec; @@ -128,4 +141,60 @@ mod bounded_vec_tests { assert(bounded_vec1 != bounded_vec2); } + + mod from_array { + use crate::collections::bounded_vec::BoundedVec; + + #[test] + fn empty() { + let empty_array: [Field; 0] = []; + let bounded_vec = BoundedVec::from_array([]); + + assert_eq(bounded_vec.max_len(), 0); + assert_eq(bounded_vec.len(), 0); + assert_eq(bounded_vec.storage(), empty_array); + } + + #[test] + fn equal_len() { + let array = [1, 2, 3]; + let bounded_vec = BoundedVec::from_array(array); + + assert_eq(bounded_vec.max_len(), 3); + assert_eq(bounded_vec.len(), 3); + assert_eq(bounded_vec.storage(), array); + } + + #[test] + fn max_len_greater_then_array_len() { + let array = [1, 2, 3]; + let bounded_vec: BoundedVec = BoundedVec::from_array(array); + + assert_eq(bounded_vec.max_len(), 10); + assert_eq(bounded_vec.len(), 3); + assert_eq(bounded_vec.storage()[0], 1); + assert_eq(bounded_vec.storage()[1], 2); + assert_eq(bounded_vec.storage()[2], 3); + } + + #[test(should_fail_with="from array out of bounds")] + fn max_len_lower_then_array_len() { + let _: BoundedVec = BoundedVec::from_array([0; 3]); + } + } + + mod trait_from { + use crate::collections::bounded_vec::BoundedVec; + + #[test] + fn simple() { + let array = [1, 2]; + let bounded_vec: BoundedVec = BoundedVec::from(array); + + assert_eq(bounded_vec.max_len(), 10); + assert_eq(bounded_vec.len(), 2); + assert_eq(bounded_vec.storage()[0], 1); + assert_eq(bounded_vec.storage()[1], 2); + } + } } diff --git a/noir_stdlib/src/embedded_curve_ops.nr b/noir_stdlib/src/embedded_curve_ops.nr new file mode 100644 index 00000000000..6a1f17dae98 --- /dev/null +++ b/noir_stdlib/src/embedded_curve_ops.nr @@ -0,0 +1,82 @@ +use crate::ops::{Add, Sub, Neg}; + +// TODO(https://github.com/noir-lang/noir/issues/4931) +struct EmbeddedCurvePoint { + x: Field, + y: Field, +} + +impl EmbeddedCurvePoint { + fn double(self) -> EmbeddedCurvePoint { + embedded_curve_add(self, self) + } +} + +impl Add for EmbeddedCurvePoint { + fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint { + embedded_curve_add(self, other) + } +} + +impl Sub for EmbeddedCurvePoint { + fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint { + self + other.neg() + } +} + +impl Neg for EmbeddedCurvePoint { + fn neg(self) -> EmbeddedCurvePoint { + EmbeddedCurvePoint { + x: self.x, + y: -self.y + } + } +} + +// Computes a multi scalar multiplication over the embedded curve. +// For bn254, We have Grumpkin and Baby JubJub. +// For bls12-381, we have JubJub and Bandersnatch. +// +// The embedded curve being used is decided by the +// underlying proof system. +#[foreign(multi_scalar_mul)] +// docs:start:multi_scalar_mul +pub fn multi_scalar_mul( + points: [Field; N], // points represented as x and y coordinates [x1, y1, x2, y2, ...] + scalars: [Field; N] // scalars represented as low and high limbs [low1, high1, low2, high2, ...] +) -> [Field; 2] +// docs:end:multi_scalar_mul +{} + +// docs:start:fixed_base_scalar_mul +pub fn fixed_base_scalar_mul( + scalar_low: Field, + scalar_high: Field +) -> [Field; 2] +// docs:end:fixed_base_scalar_mul +{ + let g1_x = 1; + let g1_y = 17631683881184975370165255887551781615748388533673675138860; + multi_scalar_mul([g1_x, g1_y], [scalar_low, scalar_high]) +} + +// This is a hack as returning an `EmbeddedCurvePoint` from a foreign function in brillig returns a [BrilligVariable::SingleAddr; 2] rather than BrilligVariable::BrilligArray +// as is defined in the brillig bytecode format. This is a workaround which allows us to fix this without modifying the serialization format. +// docs:start:embedded_curve_add +fn embedded_curve_add( + point1: EmbeddedCurvePoint, + point2: EmbeddedCurvePoint +) -> EmbeddedCurvePoint +// docs:end:embedded_curve_add +{ + let point_array = embedded_curve_add_array_return(point1, point2); + let x = point_array[0]; + let y = point_array[1]; + EmbeddedCurvePoint { x, y } +} + +#[foreign(embedded_curve_add)] +fn embedded_curve_add_array_return( + _point1: EmbeddedCurvePoint, + _point2: EmbeddedCurvePoint +) -> [Field; 2] {} diff --git a/noir_stdlib/src/grumpkin_scalar.nr b/noir_stdlib/src/grumpkin_scalar.nr deleted file mode 100644 index d05158488f4..00000000000 --- a/noir_stdlib/src/grumpkin_scalar.nr +++ /dev/null @@ -1,21 +0,0 @@ -struct GrumpkinScalar { - low: Field, - high: Field, -} - -impl GrumpkinScalar { - pub fn new(low: Field, high: Field) -> Self { - // TODO: check that the low and high value fit within the grumpkin modulus - GrumpkinScalar { low, high } - } -} - -global GRUMPKIN_SCALAR_SERIALIZED_LEN: Field = 2; - -pub fn deserialize_grumpkin_scalar(fields: [Field; GRUMPKIN_SCALAR_SERIALIZED_LEN]) -> GrumpkinScalar { - GrumpkinScalar { low: fields[0], high: fields[1] } -} - -pub fn serialize_grumpkin_scalar(scalar: GrumpkinScalar) -> [Field; GRUMPKIN_SCALAR_SERIALIZED_LEN] { - [scalar.low, scalar.high] -} diff --git a/noir_stdlib/src/grumpkin_scalar_mul.nr b/noir_stdlib/src/grumpkin_scalar_mul.nr deleted file mode 100644 index 06d30d62332..00000000000 --- a/noir_stdlib/src/grumpkin_scalar_mul.nr +++ /dev/null @@ -1,7 +0,0 @@ -use crate::grumpkin_scalar::GrumpkinScalar; -use crate::scalar_mul::fixed_base_embedded_curve; - -pub fn grumpkin_fixed_base(scalar: GrumpkinScalar) -> [Field; 2] { - // TODO: this should use both the low and high limbs to do the scalar multiplication - fixed_base_embedded_curve(scalar.low, scalar.high) -} diff --git a/noir_stdlib/src/hash.nr b/noir_stdlib/src/hash.nr index 26a9fa6c2c0..ef1cb0889d7 100644 --- a/noir_stdlib/src/hash.nr +++ b/noir_stdlib/src/hash.nr @@ -4,6 +4,7 @@ mod poseidon2; use crate::default::Default; use crate::uint128::U128; +use crate::sha256::{digest, sha256_var}; #[foreign(sha256)] // docs:start:sha256 diff --git a/noir_stdlib/src/internal.nr b/noir_stdlib/src/internal.nr deleted file mode 100644 index 8d5c01dda7f..00000000000 --- a/noir_stdlib/src/internal.nr +++ /dev/null @@ -1,12 +0,0 @@ -// This file contains functions which should only be used in calls injected by the Noir compiler. -// These functions should not be called manually in user code. -// -// Changes to this file will not be considered breaking. - -#[oracle(assert_message)] -unconstrained fn assert_message_oracle(_input: T) {} -unconstrained pub fn resolve_assert_message(input: T, condition: bool) { - if !condition { - assert_message_oracle(input); - } -} diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index 90c04472066..33504be0b9a 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -1,4 +1,5 @@ mod hash; +mod aes128; mod array; mod slice; mod merkle; @@ -6,9 +7,7 @@ mod schnorr; mod ecdsa_secp256k1; mod ecdsa_secp256r1; mod eddsa; -mod grumpkin_scalar; -mod grumpkin_scalar_mul; -mod scalar_mul; +mod embedded_curve_ops; mod sha256; mod sha512; mod field; @@ -26,7 +25,6 @@ mod default; mod prelude; mod uint128; mod bigint; -mod internal; // Oracle calls are required to be wrapped in an unconstrained function // Thus, the only argument to the `println` oracle is expected to always be an ident diff --git a/noir_stdlib/src/ops.nr b/noir_stdlib/src/ops.nr index d855e794fb4..e0814267aea 100644 --- a/noir_stdlib/src/ops.nr +++ b/noir_stdlib/src/ops.nr @@ -76,6 +76,20 @@ impl Rem for i8 { fn rem(self, other: i8) -> i8 { self % other } } impl Rem for i32 { fn rem(self, other: i32) -> i32 { self % other } } impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } +// docs:start:neg-trait +trait Neg { + fn neg(self) -> Self; +} +// docs:end:neg-trait + +// docs:start:neg-trait-impls +impl Neg for Field { fn neg(self) -> Field { -self } } + +impl Neg for i8 { fn neg(self) -> i8 { -self } } +impl Neg for i32 { fn neg(self) -> i32 { -self } } +impl Neg for i64 { fn neg(self) -> i64 { -self } } +// docs:end:neg-trait-impls + // docs:start:bitor-trait trait BitOr { fn bitor(self, other: Self) -> Self; @@ -126,30 +140,31 @@ impl BitXor for i64 { fn bitxor(self, other: i64) -> i64 { self ^ other } } // docs:start:shl-trait trait Shl { - fn shl(self, other: Self) -> Self; + fn shl(self, other: u8) -> Self; } // docs:end:shl-trait -impl Shl for u32 { fn shl(self, other: u32) -> u32 { self << other } } -impl Shl for u64 { fn shl(self, other: u64) -> u64 { self << other } } +impl Shl for u32 { fn shl(self, other: u8) -> u32 { self << other } } +impl Shl for u64 { fn shl(self, other: u8) -> u64 { self << other } } impl Shl for u8 { fn shl(self, other: u8) -> u8 { self << other } } -impl Shl for u1 { fn shl(self, other: u1) -> u1 { self << other } } +impl Shl for u1 { fn shl(self, other: u8) -> u1 { self << other } } -impl Shl for i8 { fn shl(self, other: i8) -> i8 { self << other } } -impl Shl for i32 { fn shl(self, other: i32) -> i32 { self << other } } -impl Shl for i64 { fn shl(self, other: i64) -> i64 { self << other } } +impl Shl for i8 { fn shl(self, other: u8) -> i8 { self << other } } +impl Shl for i32 { fn shl(self, other: u8) -> i32 { self << other } } +impl Shl for i64 { fn shl(self, other: u8) -> i64 { self << other } } // docs:start:shr-trait trait Shr { - fn shr(self, other: Self) -> Self; + fn shr(self, other: u8) -> Self; } // docs:end:shr-trait -impl Shr for u64 { fn shr(self, other: u64) -> u64 { self >> other } } -impl Shr for u32 { fn shr(self, other: u32) -> u32 { self >> other } } +impl Shr for u64 { fn shr(self, other: u8) -> u64 { self >> other } } +impl Shr for u32 { fn shr(self, other: u8) -> u32 { self >> other } } impl Shr for u8 { fn shr(self, other: u8) -> u8 { self >> other } } -impl Shr for u1 { fn shr(self, other: u1) -> u1 { self >> other } } +impl Shr for u1 { fn shr(self, other: u8) -> u1 { self >> other } } + +impl Shr for i8 { fn shr(self, other: u8) -> i8 { self >> other } } +impl Shr for i32 { fn shr(self, other: u8) -> i32 { self >> other } } +impl Shr for i64 { fn shr(self, other: u8) -> i64 { self >> other } } -impl Shr for i8 { fn shr(self, other: i8) -> i8 { self >> other } } -impl Shr for i32 { fn shr(self, other: i32) -> i32 { self >> other } } -impl Shr for i64 { fn shr(self, other: i64) -> i64 { self >> other } } diff --git a/noir_stdlib/src/scalar_mul.nr b/noir_stdlib/src/scalar_mul.nr deleted file mode 100644 index eee7aac39f2..00000000000 --- a/noir_stdlib/src/scalar_mul.nr +++ /dev/null @@ -1,45 +0,0 @@ -use crate::ops::Add; - -struct EmbeddedCurvePoint { - x: Field, - y: Field, -} - -impl EmbeddedCurvePoint { - fn double(self) -> EmbeddedCurvePoint { - embedded_curve_add(self, self) - } -} - -impl Add for EmbeddedCurvePoint { - fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint { - embedded_curve_add(self, other) - } -} - -// Computes a fixed base scalar multiplication over the embedded curve. -// For bn254, We have Grumpkin and Baby JubJub. -// For bls12-381, we have JubJub and Bandersnatch. -// -// The embedded curve being used is decided by the -// underlying proof system. -#[foreign(fixed_base_scalar_mul)] -// docs:start:fixed_base_embedded_curve -pub fn fixed_base_embedded_curve( - low: Field, - high: Field -) -> [Field; 2] -// docs:end:fixed_base_embedded_curve -{} - -// This is a hack as returning an `EmbeddedCurvePoint` from a foreign function in brillig returns a [BrilligVariable::SingleAddr; 2] rather than BrilligVariable::BrilligArray -// as is defined in the brillig bytecode format. This is a workaround which allows us to fix this without modifying the serialization format. -fn embedded_curve_add(point1: EmbeddedCurvePoint, point2: EmbeddedCurvePoint) -> EmbeddedCurvePoint { - let point_array = embedded_curve_add_array_return(point1, point2); - let x = point_array[0]; - let y = point_array[1]; - EmbeddedCurvePoint { x, y } -} - -#[foreign(embedded_curve_add)] -fn embedded_curve_add_array_return(_point1: EmbeddedCurvePoint, _point2: EmbeddedCurvePoint) -> [Field; 2] {} diff --git a/noir_stdlib/src/sha256.nr b/noir_stdlib/src/sha256.nr index 8ca6808568d..d856043fcfa 100644 --- a/noir_stdlib/src/sha256.nr +++ b/noir_stdlib/src/sha256.nr @@ -17,19 +17,42 @@ fn msg_u8_to_u32(msg: [u8; 64]) -> [u32; 16] { } // SHA-256 hash function pub fn digest(msg: [u8; N]) -> [u8; 32] { + sha256_var(msg, N) +} + +fn hash_final_block(msg_block: [u8; 64], mut state: [u32; 8]) -> [u8; 32] { + let mut out_h: [u8; 32] = [0; 32]; // Digest as sequence of bytes + + // Hash final padded block + state = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), state); + + // Return final hash as byte array + for j in 0..8 { + let h_bytes = (state[7 - j] as Field).to_le_bytes(4); + for k in 0..4 { + out_h[31 - 4*j - k] = h_bytes[k]; + } + } + + out_h +} + +// Variable size SHA-256 hash +pub fn sha256_var(msg: [u8; N], message_size: u64) -> [u8; 32] { let mut msg_block: [u8; 64] = [0; 64]; let mut h: [u32; 8] = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]; // Intermediate hash, starting with the canonical initial value - let mut out_h: [u8; 32] = [0; 32]; // Digest as sequence of bytes let mut i: u64 = 0; // Message byte pointer for k in 0..N { - // Populate msg_block - msg_block[i] = msg[k]; - i = i + 1; - if i == 64 { - // Enough to hash block - h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); + if k < message_size { + // Populate msg_block + msg_block[i] = msg[k]; + i = i + 1; + if i == 64 { + // Enough to hash block + h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); - i = 0; + i = 0; + } } } // Pad the rest such that we have a [u32; 2] block at the end representing the length @@ -53,7 +76,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { i = 0; } - let len = 8 * msg.len(); + let len = 8 * message_size; let len_bytes = (len as Field).to_le_bytes(8); for _i in 0..64 { // In any case, fill blocks up with zeros until the last 64 (i.e. until i = 56). @@ -67,16 +90,5 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { i += 8; } } - // Hash final padded block - h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); - - // Return final hash as byte array - for j in 0..8 { - let h_bytes = (h[7 - j] as Field).to_le_bytes(4); - for k in 0..4 { - out_h[31 - 4*j - k] = h_bytes[k]; - } - } - - out_h + hash_final_block(msg_block, h) } diff --git a/noir_stdlib/src/sha512.nr b/noir_stdlib/src/sha512.nr index a766ae50d55..0f8ffcfcb1c 100644 --- a/noir_stdlib/src/sha512.nr +++ b/noir_stdlib/src/sha512.nr @@ -2,7 +2,7 @@ // 64 bytes. // Internal functions act on 64-bit unsigned integers for simplicity. // Auxiliary mappings; names as in FIPS PUB 180-4 -fn rotr64(a: u64, b: u64) -> u64 // 64-bit right rotation +fn rotr64(a: u64, b: u8) -> u64 // 64-bit right rotation { // None of the bits overlap between `(a >> b)` and `(a << (64 - b))` // Addition is then equivalent to OR, with fewer constraints. diff --git a/noir_stdlib/src/uint128.nr b/noir_stdlib/src/uint128.nr index b91ed5c4cb2..d0f38079e6f 100644 --- a/noir_stdlib/src/uint128.nr +++ b/noir_stdlib/src/uint128.nr @@ -256,9 +256,9 @@ impl BitXor for U128 { } impl Shl for U128 { - fn shl(self, other: U128) -> U128 { - assert(other < U128::from_u64s_le(128,0), "attempt to shift left with overflow"); - let exp_bits = other.lo.to_be_bits(7); + fn shl(self, other: u8) -> U128 { + assert(other < 128, "attempt to shift left with overflow"); + let exp_bits = (other as Field).to_be_bits(7); let mut r: Field = 2; let mut y: Field = 1; @@ -271,9 +271,9 @@ impl Shl for U128 { } impl Shr for U128 { - fn shr(self, other: U128) -> U128 { - assert(other < U128::from_u64s_le(128,0), "attempt to shift right with overflow"); - let exp_bits = other.lo.to_be_bits(7); + fn shr(self, other: u8) -> U128 { + assert(other < 128, "attempt to shift right with overflow"); + let exp_bits = (other as Field).to_be_bits(7); let mut r: Field = 2; let mut y: Field = 1; diff --git a/test_programs/compile_failure/self_referential_struct/Nargo.toml b/test_programs/compile_failure/self_referential_struct/Nargo.toml new file mode 100644 index 00000000000..a0693f9d4b1 --- /dev/null +++ b/test_programs/compile_failure/self_referential_struct/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "self_referential_struct" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/compile_failure/self_referential_struct/src/main.nr b/test_programs/compile_failure/self_referential_struct/src/main.nr new file mode 100644 index 00000000000..d70b1a10ded --- /dev/null +++ b/test_programs/compile_failure/self_referential_struct/src/main.nr @@ -0,0 +1,11 @@ +struct Option2 { + _is_some: bool, + _value: T, +} + +struct SelfReferential +{ + prop : Option2 +} + +fn main(x: SelfReferential) { assert(x._is_some); } diff --git a/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr b/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr index a873bcd5dbd..7d3f9459598 100644 --- a/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr +++ b/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr @@ -23,8 +23,8 @@ fn main() { assert((x | y) == or(x, y)); // TODO SSA => ACIR has some issues with xor ops assert(check_xor(x, y, 4)); - assert((x >> y) == shr(x, y)); - assert((x << y) == shl(x, y)); + assert((x >> y as u8) == shr(x, y as u8)); + assert((x << y as u8) == shl(x, y as u8)); } unconstrained fn add(x: u32, y: u32) -> u32 { @@ -67,11 +67,11 @@ unconstrained fn check_xor(x: u32, y: u32, result: u32) -> bool { (x ^ y) == result } -unconstrained fn shr(x: u32, y: u32) -> u32 { +unconstrained fn shr(x: u32, y: u8) -> u32 { x >> y } -unconstrained fn shl(x: u32, y: u32) -> u32 { +unconstrained fn shl(x: u32, y: u8) -> u32 { x << y } diff --git a/test_programs/compile_success_empty/comptime_mut_global/Nargo.toml b/test_programs/compile_success_empty/comptime_mut_global/Nargo.toml new file mode 100644 index 00000000000..c29aa8d83b9 --- /dev/null +++ b/test_programs/compile_success_empty/comptime_mut_global/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "comptime_mut_global" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] diff --git a/test_programs/compile_success_empty/comptime_mut_global/src/main.nr b/test_programs/compile_success_empty/comptime_mut_global/src/main.nr new file mode 100644 index 00000000000..fa739289d37 --- /dev/null +++ b/test_programs/compile_success_empty/comptime_mut_global/src/main.nr @@ -0,0 +1,30 @@ +comptime mut global COUNTER: Field = 0; + +comptime fn get_unique_id() -> Field { + let id = COUNTER; + COUNTER += 1; + id +} + +fn id1() -> Field { + comptime + { + get_unique_id() + } +} + +fn id2() -> Field { + comptime + { + get_unique_id() + } +} + +fn main() { + // Order of comptime evaluation between functions isn't guaranteed + // so we don't know if (id1 == 0 && id2 == 1) or if (id1 == 1 && id2 == 0). + // we only know they are not equal + let id1 = id1(); + let id2 = id2(); + assert(id1 != id2); +} diff --git a/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml b/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml new file mode 100644 index 00000000000..5894e457dd8 --- /dev/null +++ b/test_programs/compile_success_empty/impl_from_where_impl/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "impl_from_where_impl" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] diff --git a/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr new file mode 100644 index 00000000000..3cec46bdfcd --- /dev/null +++ b/test_programs/compile_success_empty/impl_from_where_impl/src/main.nr @@ -0,0 +1,15 @@ +trait Bar { + fn ok(self) -> Self; + + fn ref_ok(self) -> Self { + self.ok() + } +} + +impl Bar for (T, T) where T: Bar { + fn ok(self) -> Self { + self + } +} + +fn main() {} diff --git a/test_programs/compile_success_empty/intrinsic_die/src/main.nr b/test_programs/compile_success_empty/intrinsic_die/src/main.nr index 8cac707dfea..9ce17f72c0d 100644 --- a/test_programs/compile_success_empty/intrinsic_die/src/main.nr +++ b/test_programs/compile_success_empty/intrinsic_die/src/main.nr @@ -2,5 +2,7 @@ use dep::std; // This test checks that we perform dead-instruction-elimination on intrinsic functions. fn main(x: Field) { let hash = std::hash::pedersen_commitment([x]); - let _p1 = std::scalar_mul::fixed_base_embedded_curve(x, 0); + let g1_x = 0x0000000000000000000000000000000000000000000000000000000000000001; + let g1_y = 0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c; + let _p1 = std::embedded_curve_ops::multi_scalar_mul([g1_x, g1_y], [x, 0]); } diff --git a/test_programs/execution_success/aes128_encrypt/Nargo.toml b/test_programs/execution_success/aes128_encrypt/Nargo.toml new file mode 100644 index 00000000000..29425131cff --- /dev/null +++ b/test_programs/execution_success/aes128_encrypt/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "aes128_encrypt" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/aes128_encrypt/Prover.toml b/test_programs/execution_success/aes128_encrypt/Prover.toml new file mode 100644 index 00000000000..b6b684790e1 --- /dev/null +++ b/test_programs/execution_success/aes128_encrypt/Prover.toml @@ -0,0 +1,4 @@ +inputs = "kevlovesrust" +iv = "0000000000000000" +key = "0000000000000000" +output = "F40E7EACAB28D0BAADB8E269EE7ACDBF" \ No newline at end of file diff --git a/test_programs/execution_success/aes128_encrypt/src/main.nr b/test_programs/execution_success/aes128_encrypt/src/main.nr new file mode 100644 index 00000000000..f6ed0f309c3 --- /dev/null +++ b/test_programs/execution_success/aes128_encrypt/src/main.nr @@ -0,0 +1,44 @@ +use dep::std; + +unconstrained fn decode_ascii(ascii: u8) -> u8 { + if ascii < 58 { + ascii - 48 + } else if ascii < 71 { + ascii - 55 + } else { + ascii - 87 + } +} + +unconstrained fn decode_hex(s: str) -> [u8; M] { + let mut result: [u8; M] = [0; M]; + let as_bytes = s.as_bytes(); + for i in 0..N { + if i % 2 != 0 { + continue; + } + result[i/2] = decode_ascii(as_bytes[i]) * 16 + decode_ascii(as_bytes[i + 1]); + } + result +} + +unconstrained fn cipher(plaintext: [u8; 12], iv: [u8; 16], key: [u8; 16]) -> [u8; 16] { + let slice_res = std::aes128::aes128_encrypt(plaintext, iv, key); + let mut result = [0; 16]; + for i in 0..16 { + result[i] = slice_res[i]; + } + result +} + +fn main(inputs: str<12>, iv: str<16>, key: str<16>, output: str<32>) { + let result = std::aes128::aes128_encrypt(inputs.as_bytes(), iv.as_bytes(), key.as_bytes()); + let output_bytes: [u8; 16] = decode_hex(output); + for i in 0..16 { + assert(result[i] == output_bytes[i]); + } + let unconstrained_result = cipher(inputs.as_bytes(), iv.as_bytes(), key.as_bytes()); + for i in 0..16 { + assert(unconstrained_result[i] == output_bytes[i]); + } +} diff --git a/test_programs/execution_success/array_if_cond_simple/Nargo.toml b/test_programs/execution_success/array_if_cond_simple/Nargo.toml new file mode 100644 index 00000000000..b885d22c019 --- /dev/null +++ b/test_programs/execution_success/array_if_cond_simple/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "array_if_cond_simple" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/array_if_cond_simple/Prover.toml b/test_programs/execution_success/array_if_cond_simple/Prover.toml new file mode 100644 index 00000000000..2825143e8ad --- /dev/null +++ b/test_programs/execution_success/array_if_cond_simple/Prover.toml @@ -0,0 +1,2 @@ +x = true +y = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] \ No newline at end of file diff --git a/test_programs/execution_success/array_if_cond_simple/src/main.nr b/test_programs/execution_success/array_if_cond_simple/src/main.nr new file mode 100644 index 00000000000..ee2f762d43c --- /dev/null +++ b/test_programs/execution_success/array_if_cond_simple/src/main.nr @@ -0,0 +1,8 @@ +fn main(x: bool, mut y: [u32; 30]) { + if x { + y[0] = 1; + } + + let z = y[0] + y[1]; + assert(z == 1); +} diff --git a/test_programs/execution_success/bit_shifts_comptime/src/main.nr b/test_programs/execution_success/bit_shifts_comptime/src/main.nr index 9184b5bd5e6..6d9736b6abb 100644 --- a/test_programs/execution_success/bit_shifts_comptime/src/main.nr +++ b/test_programs/execution_success/bit_shifts_comptime/src/main.nr @@ -14,7 +14,7 @@ fn main(x: u64) { //regression for 3481 assert(x << 63 == 0); - assert_eq((1 as u64) << (32 as u64), 0x0100000000); + assert_eq((1 as u64) << 32, 0x0100000000); } fn regression_2250() { diff --git a/test_programs/execution_success/bit_shifts_runtime/src/main.nr b/test_programs/execution_success/bit_shifts_runtime/src/main.nr index ff424c9fbf6..059bbe84dac 100644 --- a/test_programs/execution_success/bit_shifts_runtime/src/main.nr +++ b/test_programs/execution_success/bit_shifts_runtime/src/main.nr @@ -1,4 +1,4 @@ -fn main(x: u64, y: u64) { +fn main(x: u64, y: u8) { // runtime shifts on compile-time known values assert(64 << y == 128); assert(64 >> y == 32); @@ -11,10 +11,10 @@ fn main(x: u64, y: u64) { let mut b: i8 = x as i8; assert(b << 1 == -128); assert(b >> 2 == 16); - assert(b >> a == 32); + assert(b >> y == 32); a = -a; assert(a << 7 == -128); - assert(a << -a == -2); + assert(a << y == -2); - assert(x >> x == 0); + assert(x >> (x as u8) == 0); } diff --git a/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr b/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr index f22166b5993..cdeaad7514c 100644 --- a/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr +++ b/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr @@ -1,7 +1,7 @@ -unconstrained fn main(x: u64, y: u64) { +unconstrained fn main(x: u64, y: u8) { // runtime shifts on compile-time known values - assert(64 << y == 128); - assert(64 >> y == 32); + assert(64 as u32 << y == 128); + assert(64 as u32 >> y == 32); // runtime shifts on runtime values assert(x << y == 128); assert(x >> y == 32); @@ -11,10 +11,10 @@ unconstrained fn main(x: u64, y: u64) { let mut b: i8 = x as i8; assert(b << 1 == -128); assert(b >> 2 == 16); - assert(b >> a == 32); + assert(b >> y == 32); a = -a; assert(a << 7 == -128); - assert(a << -a == -2); + assert(a << y == -2); - assert(x >> x == 0); + assert(x >> (x as u8) == 0); } diff --git a/test_programs/execution_success/distinct_keyword/Nargo.toml b/test_programs/execution_success/brillig_embedded_curve/Nargo.toml similarity index 62% rename from test_programs/execution_success/distinct_keyword/Nargo.toml rename to test_programs/execution_success/brillig_embedded_curve/Nargo.toml index 3f1b1386ba7..b92e11d6383 100644 --- a/test_programs/execution_success/distinct_keyword/Nargo.toml +++ b/test_programs/execution_success/brillig_embedded_curve/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "distinct_keyword" +name = "brillig_embedded_curve" type = "bin" authors = [""] diff --git a/test_programs/execution_success/brillig_embedded_curve/Prover.toml b/test_programs/execution_success/brillig_embedded_curve/Prover.toml new file mode 100644 index 00000000000..7113b9cd038 --- /dev/null +++ b/test_programs/execution_success/brillig_embedded_curve/Prover.toml @@ -0,0 +1,3 @@ +priv_key = "1" +pub_x = "0x0000000000000000000000000000000000000000000000000000000000000001" +pub_y = "0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c" \ No newline at end of file diff --git a/test_programs/execution_success/brillig_embedded_curve/src/main.nr b/test_programs/execution_success/brillig_embedded_curve/src/main.nr new file mode 100644 index 00000000000..1a183bb13d9 --- /dev/null +++ b/test_programs/execution_success/brillig_embedded_curve/src/main.nr @@ -0,0 +1,28 @@ +use dep::std; + +unconstrained fn main( + priv_key: Field, + pub_x: pub Field, + pub_y: pub Field, +) { + let g1_y = 17631683881184975370165255887551781615748388533673675138860; + let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: g1_y }; + + // Test that multi_scalar_mul correctly derives the public key + let res = std::embedded_curve_ops::multi_scalar_mul([g1.x, g1.y], [priv_key, 0]); + assert(res[0] == pub_x); + assert(res[1] == pub_y); + + // Test that double function calling embedded_curve_add works as expected + let pub_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y }; + let res = pub_point.double(); + let double = g1.add(g1); + + assert(double.x == res.x); + + // Test calling multi_scalar_mul with multiple points and scalars + let res = std::embedded_curve_ops::multi_scalar_mul([g1.x, g1.y, g1.x, g1.y], [priv_key, 0, priv_key, 0]); + + // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice + assert(double.x == res[0]); +} diff --git a/test_programs/execution_success/brillig_scalar_mul/Prover.toml b/test_programs/execution_success/brillig_scalar_mul/Prover.toml deleted file mode 100644 index 69b91cb5f31..00000000000 --- a/test_programs/execution_success/brillig_scalar_mul/Prover.toml +++ /dev/null @@ -1,7 +0,0 @@ -a = "1" -a_pub_x = "0x0000000000000000000000000000000000000000000000000000000000000001" -a_pub_y = "0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c" - -b = "2" -b_pub_x = "0x06ce1b0827aafa85ddeb49cdaa36306d19a74caa311e13d46d8bc688cdbffffe" -b_pub_y = "0x1c122f81a3a14964909ede0ba2a6855fc93faf6fa1a788bf467be7e7a43f80ac" \ No newline at end of file diff --git a/test_programs/execution_success/brillig_scalar_mul/src/main.nr b/test_programs/execution_success/brillig_scalar_mul/src/main.nr deleted file mode 100644 index c7c3a85a4ff..00000000000 --- a/test_programs/execution_success/brillig_scalar_mul/src/main.nr +++ /dev/null @@ -1,32 +0,0 @@ -use dep::std; - -unconstrained fn main( - a: Field, - a_pub_x: pub Field, - a_pub_y: pub Field, - b: Field, - b_pub_x: pub Field, - b_pub_y: pub Field -) { - let mut priv_key = a; - let mut pub_x: Field = a_pub_x; - let mut pub_y: Field = a_pub_y; - if a != 1 { - // Change `a` in Prover.toml to test input `b` - priv_key = b; - pub_x = b_pub_x; - pub_y = b_pub_y; - } - let res = std::scalar_mul::fixed_base_embedded_curve(priv_key, 0); - assert(res[0] == pub_x); - assert(res[1] == pub_y); - - let pub_point= std::scalar_mul::EmbeddedCurvePoint { x: pub_x, y: pub_y }; - let g1_y = 17631683881184975370165255887551781615748388533673675138860; - let g1= std::scalar_mul::EmbeddedCurvePoint { x: 1, y: g1_y }; - - let res = pub_point.double(); - let double = g1.add(g1); - - assert(double.x == res.x); -} diff --git a/test_programs/compile_success_empty/conditional_regression_547/Nargo.toml b/test_programs/execution_success/conditional_regression_547/Nargo.toml similarity index 100% rename from test_programs/compile_success_empty/conditional_regression_547/Nargo.toml rename to test_programs/execution_success/conditional_regression_547/Nargo.toml diff --git a/test_programs/compile_success_empty/conditional_regression_547/Prover.toml b/test_programs/execution_success/conditional_regression_547/Prover.toml similarity index 100% rename from test_programs/compile_success_empty/conditional_regression_547/Prover.toml rename to test_programs/execution_success/conditional_regression_547/Prover.toml diff --git a/test_programs/compile_success_empty/conditional_regression_547/src/main.nr b/test_programs/execution_success/conditional_regression_547/src/main.nr similarity index 100% rename from test_programs/compile_success_empty/conditional_regression_547/src/main.nr rename to test_programs/execution_success/conditional_regression_547/src/main.nr diff --git a/test_programs/execution_success/debug_logs/src/main.nr b/test_programs/execution_success/debug_logs/src/main.nr index ec24b0cc8e8..c7fd01ebbc5 100644 --- a/test_programs/execution_success/debug_logs/src/main.nr +++ b/test_programs/execution_success/debug_logs/src/main.nr @@ -71,6 +71,8 @@ fn main(x: Field, y: pub Field) { let closured_lambda = |x| x + one; println(f"closured_lambda: {closured_lambda}, sentinel: {sentinel}"); println(closured_lambda); + + regression_4967(); } fn string_identity(string: fmtstr<14, (Field, Field)>) -> fmtstr<14, (Field, Field)> { @@ -122,3 +124,14 @@ fn regression_2906() { println(f"array_five_vals: {array_five_vals}, label_five_vals: {label_five_vals}"); } +fn regression_4967() { + let sentinel: u32 = 8888; + + let slice_of_tuples: [(i32, u8)] = &[(11, 22), (33, 44)]; + println(f"slice_of_tuples: {slice_of_tuples}, sentinel: {sentinel}"); + println(slice_of_tuples); + + let slice_of_tuples_coerced: [(i32, u8)] = [(11, 22), (33, 44)]; + println(f"slice_of_tuples: {slice_of_tuples_coerced}, sentinel: {sentinel}"); + println(slice_of_tuples_coerced); +} diff --git a/test_programs/execution_success/distinct_keyword/src/main.nr b/test_programs/execution_success/distinct_keyword/src/main.nr deleted file mode 100644 index 8e9b5c008ed..00000000000 --- a/test_programs/execution_success/distinct_keyword/src/main.nr +++ /dev/null @@ -1,4 +0,0 @@ -// Example that uses the distinct keyword -fn main(x: pub Field) -> distinct pub [Field; 2] { - [x + 1, x] -} diff --git a/test_programs/execution_success/brillig_scalar_mul/Nargo.toml b/test_programs/execution_success/embedded_curve_ops/Nargo.toml similarity index 65% rename from test_programs/execution_success/brillig_scalar_mul/Nargo.toml rename to test_programs/execution_success/embedded_curve_ops/Nargo.toml index eefd041b899..1c389149aaf 100644 --- a/test_programs/execution_success/brillig_scalar_mul/Nargo.toml +++ b/test_programs/execution_success/embedded_curve_ops/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "brillig_scalar_mul" +name = "embedded_curve_ops" type = "bin" authors = [""] diff --git a/test_programs/execution_success/embedded_curve_ops/Prover.toml b/test_programs/execution_success/embedded_curve_ops/Prover.toml new file mode 100644 index 00000000000..7113b9cd038 --- /dev/null +++ b/test_programs/execution_success/embedded_curve_ops/Prover.toml @@ -0,0 +1,3 @@ +priv_key = "1" +pub_x = "0x0000000000000000000000000000000000000000000000000000000000000001" +pub_y = "0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c" \ No newline at end of file diff --git a/test_programs/execution_success/embedded_curve_ops/src/main.nr b/test_programs/execution_success/embedded_curve_ops/src/main.nr new file mode 100644 index 00000000000..3cb27d8c181 --- /dev/null +++ b/test_programs/execution_success/embedded_curve_ops/src/main.nr @@ -0,0 +1,24 @@ +use dep::std; + +fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { + let g1_y = 17631683881184975370165255887551781615748388533673675138860; + let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: g1_y }; + + // Test that multi_scalar_mul correctly derives the public key + let res = std::embedded_curve_ops::multi_scalar_mul([g1.x, g1.y], [priv_key, 0]); + assert(res[0] == pub_x); + assert(res[1] == pub_y); + + // Test that double function calling embedded_curve_add works as expected + let pub_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y }; + let res = pub_point.double(); + let double = g1.add(g1); + + assert(double.x == res.x); + + // Test calling multi_scalar_mul with multiple points and scalars + let res = std::embedded_curve_ops::multi_scalar_mul([g1.x, g1.y, g1.x, g1.y], [priv_key, 0, priv_key, 0]); + + // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice + assert(double.x == res[0]); +} diff --git a/test_programs/execution_success/fold_complex_outputs/Nargo.toml b/test_programs/execution_success/fold_complex_outputs/Nargo.toml new file mode 100644 index 00000000000..f00c6520b4a --- /dev/null +++ b/test_programs/execution_success/fold_complex_outputs/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "fold_complex_outputs" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/fold_complex_outputs/Prover.toml b/test_programs/execution_success/fold_complex_outputs/Prover.toml new file mode 100644 index 00000000000..a26b97d6471 --- /dev/null +++ b/test_programs/execution_success/fold_complex_outputs/Prover.toml @@ -0,0 +1,2 @@ +x = "5" +y = "3" diff --git a/test_programs/execution_success/fold_complex_outputs/src/main.nr b/test_programs/execution_success/fold_complex_outputs/src/main.nr new file mode 100644 index 00000000000..309d9747598 --- /dev/null +++ b/test_programs/execution_success/fold_complex_outputs/src/main.nr @@ -0,0 +1,72 @@ +struct MyStruct { + x: u32, + y: u32, + z: u32, + nested_struct: InnerStruct +} + +struct InnerStruct { + small_array: [u32; 2], + big_array: [u32; 5], +} + +struct ParentStruct { + basic_array: [Field; 3], + id: u32, + my_structs: [MyStruct; 2], +} + +fn main(x: u32, y: pub u32) { + let nested_struct = InnerStruct { small_array: [1 as u32; 2], big_array: [0 as u32; 5] }; + let s = MyStruct { x, y, z: x + y, nested_struct }; + let parent = ParentStruct { basic_array: [1; 3], id: 100, my_structs: [s, s] }; + let new_parent = map_fields(parent); + + // Now check that the outputs are as we expect them to be + assert(new_parent.basic_array[0] == 1); + assert(new_parent.basic_array[1] == 18); + assert(new_parent.basic_array[2] == 1); + + let struct_0 = new_parent.my_structs[0]; + assert(struct_0.x == 5); + assert(struct_0.y == 3); + assert(struct_0.z == 8); + assert(struct_0.nested_struct.small_array == nested_struct.small_array); + assert(struct_0.nested_struct.big_array == nested_struct.big_array); + + let struct_1 = new_parent.my_structs[1]; + assert(struct_1.x == 50); + assert(struct_1.y == 30); + assert(struct_1.z == 80); + assert(struct_1.nested_struct.small_array == [5, 10]); + assert(struct_1.nested_struct.big_array == [15, 20, 25, 30, 35]); +} + +// Meaningless mapping to test whether the values returned are what we expect +#[fold] +fn map_fields(mut input: ParentStruct) -> ParentStruct { + let current_struct = input.my_structs[0]; + let mut sum = 0; + for value in current_struct.nested_struct.small_array { + sum += value; + } + for value in current_struct.nested_struct.big_array { + sum += value; + } + sum += (current_struct.x + current_struct.y + current_struct.z); + + input.basic_array[1] = sum as Field; + + input.my_structs[1].nested_struct.small_array = [5, 10]; + input.my_structs[1].nested_struct.big_array = [15, 20, 25, 30, 35]; + + // LHS input.my_structs[1].x == 50 + input.my_structs[1].x = input.my_structs[1].x * 10; + // LHS input.my_structs[1].y == 30 + input.my_structs[1].y = input.my_structs[1].y * 10; + // LHS input.my_structs[1].x == 80 + input.my_structs[1].z = input.my_structs[1].x + input.my_structs[1].y; + + input +} + diff --git a/test_programs/execution_success/fold_distinct_return/Nargo.toml b/test_programs/execution_success/fold_distinct_return/Nargo.toml new file mode 100644 index 00000000000..f18edb7e49d --- /dev/null +++ b/test_programs/execution_success/fold_distinct_return/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "fold_distinct_return" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/fold_distinct_return/Prover.toml b/test_programs/execution_success/fold_distinct_return/Prover.toml new file mode 100644 index 00000000000..f28f2f8cc48 --- /dev/null +++ b/test_programs/execution_success/fold_distinct_return/Prover.toml @@ -0,0 +1,2 @@ +x = "5" +y = "10" diff --git a/test_programs/execution_success/fold_distinct_return/src/main.nr b/test_programs/execution_success/fold_distinct_return/src/main.nr new file mode 100644 index 00000000000..b0843a02b80 --- /dev/null +++ b/test_programs/execution_success/fold_distinct_return/src/main.nr @@ -0,0 +1,10 @@ +fn main(x: u32, y: pub u32) { + let new_field = new_field_in_array([x, y, 3]); + assert(new_field[0] == 25); +} + +#[fold] +fn new_field_in_array(mut input: [u32; 3]) -> [u32; 3] { + input[0] = input[0] + 20; + input +} diff --git a/test_programs/execution_success/fold_fibonacci/Nargo.toml b/test_programs/execution_success/fold_fibonacci/Nargo.toml new file mode 100644 index 00000000000..6d8214689b0 --- /dev/null +++ b/test_programs/execution_success/fold_fibonacci/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "fold_fibonacci" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/fold_fibonacci/Prover.toml b/test_programs/execution_success/fold_fibonacci/Prover.toml new file mode 100644 index 00000000000..3a627b9188b --- /dev/null +++ b/test_programs/execution_success/fold_fibonacci/Prover.toml @@ -0,0 +1 @@ +x = "10" diff --git a/test_programs/execution_success/fold_fibonacci/src/main.nr b/test_programs/execution_success/fold_fibonacci/src/main.nr new file mode 100644 index 00000000000..e150a586086 --- /dev/null +++ b/test_programs/execution_success/fold_fibonacci/src/main.nr @@ -0,0 +1,12 @@ +fn main(x: u32) { + assert(fibonacci(x) == 55); +} + +#[fold] +fn fibonacci(x: u32) -> u32 { + if x <= 1 { + x + } else { + fibonacci(x - 1) + fibonacci(x - 2) + } +} diff --git a/test_programs/execution_success/inline_never_basic/Nargo.toml b/test_programs/execution_success/inline_never_basic/Nargo.toml new file mode 100644 index 00000000000..16691770d76 --- /dev/null +++ b/test_programs/execution_success/inline_never_basic/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "inline_never_basic" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/inline_never_basic/Prover.toml b/test_programs/execution_success/inline_never_basic/Prover.toml new file mode 100644 index 00000000000..f28f2f8cc48 --- /dev/null +++ b/test_programs/execution_success/inline_never_basic/Prover.toml @@ -0,0 +1,2 @@ +x = "5" +y = "10" diff --git a/test_programs/execution_success/inline_never_basic/src/main.nr b/test_programs/execution_success/inline_never_basic/src/main.nr new file mode 100644 index 00000000000..1922aaedb6c --- /dev/null +++ b/test_programs/execution_success/inline_never_basic/src/main.nr @@ -0,0 +1,8 @@ +fn main(x: Field, y: pub Field) { + basic_check(x, y); +} + +#[inline(never)] +fn basic_check(x: Field, y: Field) { + assert(x != y); +} diff --git a/test_programs/compile_success_empty/main_return/Nargo.toml b/test_programs/execution_success/main_return/Nargo.toml similarity index 100% rename from test_programs/compile_success_empty/main_return/Nargo.toml rename to test_programs/execution_success/main_return/Nargo.toml diff --git a/test_programs/compile_success_empty/main_return/Prover.toml b/test_programs/execution_success/main_return/Prover.toml similarity index 100% rename from test_programs/compile_success_empty/main_return/Prover.toml rename to test_programs/execution_success/main_return/Prover.toml diff --git a/test_programs/compile_success_empty/main_return/src/main.nr b/test_programs/execution_success/main_return/src/main.nr similarity index 100% rename from test_programs/compile_success_empty/main_return/src/main.nr rename to test_programs/execution_success/main_return/src/main.nr diff --git a/test_programs/execution_success/nested_array_dynamic_simple/Nargo.toml b/test_programs/execution_success/nested_array_dynamic_simple/Nargo.toml new file mode 100644 index 00000000000..50ba1d194a6 --- /dev/null +++ b/test_programs/execution_success/nested_array_dynamic_simple/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "nested_array_dynamic_simple" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/distinct_keyword/Prover.toml b/test_programs/execution_success/nested_array_dynamic_simple/Prover.toml similarity index 100% rename from test_programs/execution_success/distinct_keyword/Prover.toml rename to test_programs/execution_success/nested_array_dynamic_simple/Prover.toml diff --git a/test_programs/execution_success/nested_array_dynamic_simple/src/main.nr b/test_programs/execution_success/nested_array_dynamic_simple/src/main.nr new file mode 100644 index 00000000000..3b1908a463b --- /dev/null +++ b/test_programs/execution_success/nested_array_dynamic_simple/src/main.nr @@ -0,0 +1,9 @@ +fn main(x: Field) { + // x = 3 + let array: [[(Field, [Field; 1], [Field; 1]); 1]; 1] = [[(1, [2], [3])]]; + + let fetched_value = array[x - 3]; + assert(fetched_value[0].0 == 1); + assert(fetched_value[0].1[0] == 2); + assert(fetched_value[0].2[0] == 3); +} diff --git a/test_programs/execution_success/no_predicates_basic/Nargo.toml b/test_programs/execution_success/no_predicates_basic/Nargo.toml new file mode 100644 index 00000000000..bcefd550fb0 --- /dev/null +++ b/test_programs/execution_success/no_predicates_basic/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "no_predicates_basic" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/no_predicates_basic/Prover.toml b/test_programs/execution_success/no_predicates_basic/Prover.toml new file mode 100644 index 00000000000..f28f2f8cc48 --- /dev/null +++ b/test_programs/execution_success/no_predicates_basic/Prover.toml @@ -0,0 +1,2 @@ +x = "5" +y = "10" diff --git a/test_programs/execution_success/no_predicates_basic/src/main.nr b/test_programs/execution_success/no_predicates_basic/src/main.nr new file mode 100644 index 00000000000..d6037c2ab26 --- /dev/null +++ b/test_programs/execution_success/no_predicates_basic/src/main.nr @@ -0,0 +1,8 @@ +fn main(x: Field, y: pub Field) { + basic_check(x, y); +} + +#[no_predicates] +fn basic_check(x: Field, y: Field) { + assert(x != y); +} diff --git a/test_programs/execution_success/no_predicates_numeric_generic_poseidon/Nargo.toml b/test_programs/execution_success/no_predicates_numeric_generic_poseidon/Nargo.toml new file mode 100644 index 00000000000..1ce13c24287 --- /dev/null +++ b/test_programs/execution_success/no_predicates_numeric_generic_poseidon/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "no_predicates_numeric_generic_poseidon" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/no_predicates_numeric_generic_poseidon/Prover.toml b/test_programs/execution_success/no_predicates_numeric_generic_poseidon/Prover.toml new file mode 100644 index 00000000000..00e821cf89d --- /dev/null +++ b/test_programs/execution_success/no_predicates_numeric_generic_poseidon/Prover.toml @@ -0,0 +1,2 @@ +enable = [true, false] +to_hash = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] diff --git a/test_programs/execution_success/no_predicates_numeric_generic_poseidon/src/main.nr b/test_programs/execution_success/no_predicates_numeric_generic_poseidon/src/main.nr new file mode 100644 index 00000000000..dcb5e6bc5ca --- /dev/null +++ b/test_programs/execution_success/no_predicates_numeric_generic_poseidon/src/main.nr @@ -0,0 +1,33 @@ +use dep::std::hash::{pedersen_hash_with_separator, poseidon2::Poseidon2}; + +global NUM_HASHES = 2; +global HASH_LENGTH = 10; + +#[no_predicates] +pub fn poseidon_hash(inputs: [Field; N]) -> Field { + Poseidon2::hash(inputs, inputs.len()) +} + +fn main( + to_hash: [[Field; HASH_LENGTH]; NUM_HASHES], + enable: [bool; NUM_HASHES] +) -> pub [Field; NUM_HASHES + 1] { + let mut result = [0; NUM_HASHES + 1]; + for i in 0..NUM_HASHES { + let enable = enable[i]; + let to_hash = to_hash[i]; + if enable { + result[i] = poseidon_hash(to_hash); + } + } + + // We want to make sure that the function marked with `#[no_predicates]` with a numeric generic + // is monomorphized correctly. + let mut double_preimage = [0; 20]; + for i in 0..HASH_LENGTH * 2 { + double_preimage[i] = to_hash[0][i % HASH_LENGTH]; + } + result[NUM_HASHES] = poseidon_hash(double_preimage); + + result +} diff --git a/test_programs/execution_success/operator_overloading/src/main.nr b/test_programs/execution_success/operator_overloading/src/main.nr index d61e1da170e..3956ea5c577 100644 --- a/test_programs/execution_success/operator_overloading/src/main.nr +++ b/test_programs/execution_success/operator_overloading/src/main.nr @@ -20,8 +20,8 @@ fn main(x: u32, y: u32) { assert((wx | wy).inner == (ex | ey)); assert((wx ^ wy).inner == (ex ^ ey)); - assert((wy << wx).inner == (ey << ex)); - assert((wy >> wx).inner == (ey >> ex)); + assert((wy << x as u8).inner == (ey << ex as u8)); + assert((wy >> x as u8).inner == (ey >> ex as u8)); assert((wx == wy) == (ex == ey)); assert((wx < wy) == (ex < ey)); @@ -103,14 +103,14 @@ impl BitXor for Wrapper { } impl Shl for Wrapper { - fn shl(self, other: Self) -> Self { - Wrapper::new(self.inner << other.inner) + fn shl(self, other: u8) -> Self { + Wrapper::new(self.inner << other) } } impl Shr for Wrapper { - fn shr(self, other: Self) -> Self { - Wrapper::new(self.inner >> other.inner) + fn shr(self, other: u8) -> Self { + Wrapper::new(self.inner >> other) } } diff --git a/test_programs/execution_success/regression/src/main.nr b/test_programs/execution_success/regression/src/main.nr index c56f3ef4190..316c0d6bad6 100644 --- a/test_programs/execution_success/regression/src/main.nr +++ b/test_programs/execution_success/regression/src/main.nr @@ -87,7 +87,7 @@ fn bitshift_literal_4() -> u64 { bits } -fn bitshift_variable(idx: u64) -> u64 { +fn bitshift_variable(idx: u8) -> u64 { let mut bits: u64 = 0; bits |= 1 << idx; diff --git a/test_programs/execution_success/regression_3051/Nargo.toml b/test_programs/execution_success/regression_3051/Nargo.toml new file mode 100644 index 00000000000..844f74cdcb3 --- /dev/null +++ b/test_programs/execution_success/regression_3051/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_3051" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] diff --git a/test_programs/execution_success/regression_3051/src/main.nr b/test_programs/execution_success/regression_3051/src/main.nr new file mode 100644 index 00000000000..2e7d10fd7b0 --- /dev/null +++ b/test_programs/execution_success/regression_3051/src/main.nr @@ -0,0 +1,24 @@ +trait Foo { + fn foo(self) -> Field; +} + +impl Foo for Field { + fn foo(self) -> Field { + self + 1 + } +} + +trait Bar { + fn bar(self) -> u64; +} + +impl Bar for u64 { + fn bar(self) -> u64 { + self + 1 + } +} + +fn main() { + dep::std::println(1.foo()); + dep::std::println(1.bar()); +} diff --git a/test_programs/execution_success/regression_4383/Nargo.toml b/test_programs/execution_success/regression_4383/Nargo.toml new file mode 100644 index 00000000000..2ad8c208f24 --- /dev/null +++ b/test_programs/execution_success/regression_4383/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_4383" +type = "bin" +authors = [""] +compiler_version = ">=0.26.0" + +[dependencies] diff --git a/test_programs/execution_success/regression_4383/src/main.nr b/test_programs/execution_success/regression_4383/src/main.nr new file mode 100644 index 00000000000..fec63ea64a5 --- /dev/null +++ b/test_programs/execution_success/regression_4383/src/main.nr @@ -0,0 +1,3 @@ +fn main() { + assert([[1]] == [[1]]); +} diff --git a/test_programs/execution_success/scalar_mul/Nargo.toml b/test_programs/execution_success/regression_4709/Nargo.toml similarity index 68% rename from test_programs/execution_success/scalar_mul/Nargo.toml rename to test_programs/execution_success/regression_4709/Nargo.toml index 926114ec374..2e0ce3fb5af 100644 --- a/test_programs/execution_success/scalar_mul/Nargo.toml +++ b/test_programs/execution_success/regression_4709/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "scalar_mul" +name = "regression_4709" type = "bin" authors = [""] diff --git a/test_programs/execution_success/regression_4709/Prover.toml b/test_programs/execution_success/regression_4709/Prover.toml new file mode 100644 index 00000000000..dcfab705327 --- /dev/null +++ b/test_programs/execution_success/regression_4709/Prover.toml @@ -0,0 +1,2 @@ +x = 1 +y = 2 \ No newline at end of file diff --git a/test_programs/execution_success/regression_4709/src/main.nr b/test_programs/execution_success/regression_4709/src/main.nr new file mode 100644 index 00000000000..1df09c53b55 --- /dev/null +++ b/test_programs/execution_success/regression_4709/src/main.nr @@ -0,0 +1,271 @@ +// Regression test for issue #4709 +global EXPONENTIATE: [[Field; 257]; 257] = [ +[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], +[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], +[1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1], +[1, 3, 9, 27, 81, 243, 215, 131, 136, 151, 196, 74, 222, 152, 199, 83, 249, 233, 185, 41, 123, 112, 79, 237, 197, 77, 231, 179, 23, 69, 207, 107, 64, 192, 62, 186, 44, 132, 139, 160, 223, 155, 208, 110, 73, 219, 143, 172, 2, 6, 18, 54, 162, 229, 173, 5, 15, 45, 135, 148, 187, 47, 141, 166, 241, 209, 113, 82, 246, 224, 158, 217, 137, 154, 205, 101, 46, 138, 157, 214, 128, 127, 124, 115, 88, 7, 21, 63, 189, 53, 159, 220, 146, 181, 29, 87, 4, 12, 36, 108, 67, 201, 89, 10, 30, 90, 13, 39, 117, 94, 25, 75, 225, 161, 226, 164, 235, 191, 59, 177, 17, 51, 153, 202, 92, 19, 57, 171, 256, 254, 248, 230, 176, 14, 42, 126, 121, 106, 61, 183, 35, 105, 58, 174, 8, 24, 72, 216, 134, 145, 178, 20, 60, 180, 26, 78, 234, 188, 50, 150, 193, 65, 195, 71, 213, 125, 118, 97, 34, 102, 49, 147, 184, 38, 114, 85, 255, 251, 239, 203, 95, 28, 84, 252, 242, 212, 122, 109, 70, 210, 116, 91, 16, 48, 144, 175, 11, 33, 99, 40, 120, 103, 52, 156, 211, 119, 100, 43, 129, 130, 133, 142, 169, 250, 236, 194, 68, 204, 98, 37, 111, 76, 228, 170, 253, 245, 221, 149, 190, 56, 168, 247, 227, 167, 244, 218, 140, 163, 232, 182, 32, 96, 31, 93, 22, 66, 198, 80, 240, 206, 104, 55, 165, 238, 200, 86, 1], +[1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1], +[1, 5, 25, 125, 111, 41, 205, 254, 242, 182, 139, 181, 134, 156, 9, 45, 225, 97, 228, 112, 46, 230, 122, 96, 223, 87, 178, 119, 81, 148, 226, 102, 253, 237, 157, 14, 70, 93, 208, 12, 60, 43, 215, 47, 235, 147, 221, 77, 128, 126, 116, 66, 73, 108, 26, 130, 136, 166, 59, 38, 190, 179, 124, 106, 16, 80, 143, 201, 234, 142, 196, 209, 17, 85, 168, 69, 88, 183, 144, 206, 2, 10, 50, 250, 222, 82, 153, 251, 227, 107, 21, 105, 11, 55, 18, 90, 193, 194, 199, 224, 92, 203, 244, 192, 189, 174, 99, 238, 162, 39, 195, 204, 249, 217, 57, 28, 140, 186, 159, 24, 120, 86, 173, 94, 213, 37, 185, 154, 256, 252, 232, 132, 146, 216, 52, 3, 15, 75, 118, 76, 123, 101, 248, 212, 32, 160, 29, 145, 211, 27, 135, 161, 34, 170, 79, 138, 176, 109, 31, 155, 4, 20, 100, 243, 187, 164, 49, 245, 197, 214, 42, 210, 22, 110, 36, 180, 129, 131, 141, 191, 184, 149, 231, 127, 121, 91, 198, 219, 67, 78, 133, 151, 241, 177, 114, 56, 23, 115, 61, 48, 240, 172, 89, 188, 169, 74, 113, 51, 255, 247, 207, 7, 35, 175, 104, 6, 30, 150, 236, 152, 246, 202, 239, 167, 64, 63, 58, 33, 165, 54, 13, 65, 68, 83, 158, 19, 95, 218, 62, 53, 8, 40, 200, 229, 117, 71, 98, 233, 137, 171, 84, 163, 44, 220, 72, 103, 1], +[1, 6, 36, 216, 11, 66, 139, 63, 121, 212, 244, 179, 46, 19, 114, 170, 249, 209, 226, 71, 169, 243, 173, 10, 60, 103, 104, 110, 146, 105, 116, 182, 64, 127, 248, 203, 190, 112, 158, 177, 34, 204, 196, 148, 117, 188, 100, 86, 2, 12, 72, 175, 22, 132, 21, 126, 242, 167, 231, 101, 92, 38, 228, 83, 241, 161, 195, 142, 81, 229, 89, 20, 120, 206, 208, 220, 35, 210, 232, 107, 128, 254, 239, 149, 123, 224, 59, 97, 68, 151, 135, 39, 234, 119, 200, 172, 4, 24, 144, 93, 44, 7, 42, 252, 227, 77, 205, 202, 184, 76, 199, 166, 225, 65, 133, 27, 162, 201, 178, 40, 240, 155, 159, 183, 70, 163, 207, 214, 256, 251, 221, 41, 246, 191, 118, 194, 136, 45, 13, 78, 211, 238, 143, 87, 8, 48, 31, 186, 88, 14, 84, 247, 197, 154, 153, 147, 111, 152, 141, 75, 193, 130, 9, 54, 67, 145, 99, 80, 223, 53, 61, 109, 140, 69, 157, 171, 255, 245, 185, 82, 235, 125, 236, 131, 15, 90, 26, 156, 165, 219, 29, 174, 16, 96, 62, 115, 176, 28, 168, 237, 137, 51, 49, 37, 222, 47, 25, 150, 129, 3, 18, 108, 134, 33, 198, 160, 189, 106, 122, 218, 23, 138, 57, 85, 253, 233, 113, 164, 213, 250, 215, 5, 30, 180, 52, 55, 73, 181, 58, 91, 32, 192, 124, 230, 95, 56, 79, 217, 17, 102, 98, 74, 187, 94, 50, 43, 1], +[1, 7, 49, 86, 88, 102, 200, 115, 34, 238, 124, 97, 165, 127, 118, 55, 128, 125, 104, 214, 213, 206, 157, 71, 240, 138, 195, 80, 46, 65, 198, 101, 193, 66, 205, 150, 22, 154, 50, 93, 137, 188, 31, 217, 234, 96, 158, 78, 32, 224, 26, 182, 246, 180, 232, 82, 60, 163, 113, 20, 140, 209, 178, 218, 241, 145, 244, 166, 134, 167, 141, 216, 227, 47, 72, 247, 187, 24, 168, 148, 8, 56, 135, 174, 190, 45, 58, 149, 15, 105, 221, 5, 35, 245, 173, 183, 253, 229, 61, 170, 162, 106, 228, 54, 121, 76, 18, 126, 111, 6, 42, 37, 2, 14, 98, 172, 176, 204, 143, 230, 68, 219, 248, 194, 73, 254, 236, 110, 256, 250, 208, 171, 169, 155, 57, 142, 223, 19, 133, 160, 92, 130, 139, 202, 129, 132, 153, 43, 44, 51, 100, 186, 17, 119, 62, 177, 211, 192, 59, 156, 64, 191, 52, 107, 235, 103, 207, 164, 120, 69, 226, 40, 23, 161, 99, 179, 225, 33, 231, 75, 11, 77, 25, 175, 197, 94, 144, 237, 117, 48, 79, 39, 16, 112, 13, 91, 123, 90, 116, 41, 30, 210, 185, 10, 70, 233, 89, 109, 249, 201, 122, 83, 67, 212, 199, 108, 242, 152, 36, 252, 222, 12, 84, 74, 4, 28, 196, 87, 95, 151, 29, 203, 136, 181, 239, 131, 146, 251, 215, 220, 255, 243, 159, 85, 81, 53, 114, 27, 189, 38, 9, 63, 184, 3, 21, 147, 1], +[1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1], +[1, 9, 81, 215, 136, 196, 222, 199, 249, 185, 123, 79, 197, 231, 23, 207, 64, 62, 44, 139, 223, 208, 73, 143, 2, 18, 162, 173, 15, 135, 187, 141, 241, 113, 246, 158, 137, 205, 46, 157, 128, 124, 88, 21, 189, 159, 146, 29, 4, 36, 67, 89, 30, 13, 117, 25, 225, 226, 235, 59, 17, 153, 92, 57, 256, 248, 176, 42, 121, 61, 35, 58, 8, 72, 134, 178, 60, 26, 234, 50, 193, 195, 213, 118, 34, 49, 184, 114, 255, 239, 95, 84, 242, 122, 70, 116, 16, 144, 11, 99, 120, 52, 211, 100, 129, 133, 169, 236, 68, 98, 111, 228, 253, 221, 190, 168, 227, 244, 140, 232, 32, 31, 22, 198, 240, 104, 165, 200, 1, 9, 81, 215, 136, 196, 222, 199, 249, 185, 123, 79, 197, 231, 23, 207, 64, 62, 44, 139, 223, 208, 73, 143, 2, 18, 162, 173, 15, 135, 187, 141, 241, 113, 246, 158, 137, 205, 46, 157, 128, 124, 88, 21, 189, 159, 146, 29, 4, 36, 67, 89, 30, 13, 117, 25, 225, 226, 235, 59, 17, 153, 92, 57, 256, 248, 176, 42, 121, 61, 35, 58, 8, 72, 134, 178, 60, 26, 234, 50, 193, 195, 213, 118, 34, 49, 184, 114, 255, 239, 95, 84, 242, 122, 70, 116, 16, 144, 11, 99, 120, 52, 211, 100, 129, 133, 169, 236, 68, 98, 111, 228, 253, 221, 190, 168, 227, 244, 140, 232, 32, 31, 22, 198, 240, 104, 165, 200, 1], +[1, 10, 100, 229, 234, 27, 13, 130, 15, 150, 215, 94, 169, 148, 195, 151, 225, 194, 141, 125, 222, 164, 98, 209, 34, 83, 59, 76, 246, 147, 185, 51, 253, 217, 114, 112, 92, 149, 205, 251, 197, 171, 168, 138, 95, 179, 248, 167, 128, 252, 207, 14, 140, 115, 122, 192, 121, 182, 21, 210, 44, 183, 31, 53, 16, 160, 58, 66, 146, 175, 208, 24, 240, 87, 99, 219, 134, 55, 36, 103, 2, 20, 200, 201, 211, 54, 26, 3, 30, 43, 173, 188, 81, 39, 133, 45, 193, 131, 25, 250, 187, 71, 196, 161, 68, 166, 118, 152, 235, 37, 113, 102, 249, 177, 228, 224, 184, 41, 153, 245, 137, 85, 79, 19, 190, 101, 239, 77, 256, 247, 157, 28, 23, 230, 244, 127, 242, 107, 42, 163, 88, 109, 62, 106, 32, 63, 116, 132, 35, 93, 159, 48, 223, 174, 198, 181, 11, 110, 72, 206, 4, 40, 143, 145, 165, 108, 52, 6, 60, 86, 89, 119, 162, 78, 9, 90, 129, 5, 50, 243, 117, 142, 135, 65, 136, 75, 236, 47, 213, 74, 226, 204, 241, 97, 199, 191, 111, 82, 49, 233, 17, 170, 158, 38, 123, 202, 221, 154, 255, 237, 57, 56, 46, 203, 231, 254, 227, 214, 84, 69, 176, 218, 124, 212, 64, 126, 232, 7, 70, 186, 61, 96, 189, 91, 139, 105, 22, 220, 144, 155, 8, 80, 29, 33, 73, 216, 104, 12, 120, 172, 178, 238, 67, 156, 18, 180, 1], +[1, 11, 121, 46, 249, 169, 60, 146, 64, 190, 34, 117, 2, 22, 242, 92, 241, 81, 120, 35, 128, 123, 68, 234, 4, 44, 227, 184, 225, 162, 240, 70, 256, 246, 136, 211, 8, 88, 197, 111, 193, 67, 223, 140, 255, 235, 15, 165, 16, 176, 137, 222, 129, 134, 189, 23, 253, 213, 30, 73, 32, 95, 17, 187, 1, 11, 121, 46, 249, 169, 60, 146, 64, 190, 34, 117, 2, 22, 242, 92, 241, 81, 120, 35, 128, 123, 68, 234, 4, 44, 227, 184, 225, 162, 240, 70, 256, 246, 136, 211, 8, 88, 197, 111, 193, 67, 223, 140, 255, 235, 15, 165, 16, 176, 137, 222, 129, 134, 189, 23, 253, 213, 30, 73, 32, 95, 17, 187, 1, 11, 121, 46, 249, 169, 60, 146, 64, 190, 34, 117, 2, 22, 242, 92, 241, 81, 120, 35, 128, 123, 68, 234, 4, 44, 227, 184, 225, 162, 240, 70, 256, 246, 136, 211, 8, 88, 197, 111, 193, 67, 223, 140, 255, 235, 15, 165, 16, 176, 137, 222, 129, 134, 189, 23, 253, 213, 30, 73, 32, 95, 17, 187, 1, 11, 121, 46, 249, 169, 60, 146, 64, 190, 34, 117, 2, 22, 242, 92, 241, 81, 120, 35, 128, 123, 68, 234, 4, 44, 227, 184, 225, 162, 240, 70, 256, 246, 136, 211, 8, 88, 197, 111, 193, 67, 223, 140, 255, 235, 15, 165, 16, 176, 137, 222, 129, 134, 189, 23, 253, 213, 30, 73, 32, 95, 17, 187, 1], +[1, 12, 144, 186, 176, 56, 158, 97, 136, 90, 52, 110, 35, 163, 157, 85, 249, 161, 133, 54, 134, 66, 21, 252, 197, 51, 98, 148, 234, 238, 29, 91, 64, 254, 221, 82, 213, 243, 89, 40, 223, 106, 244, 101, 184, 152, 25, 43, 2, 24, 31, 115, 95, 112, 59, 194, 15, 180, 104, 220, 70, 69, 57, 170, 241, 65, 9, 108, 11, 132, 42, 247, 137, 102, 196, 39, 211, 219, 58, 182, 128, 251, 185, 164, 169, 229, 178, 80, 189, 212, 231, 202, 111, 47, 50, 86, 4, 48, 62, 230, 190, 224, 118, 131, 30, 103, 208, 183, 140, 138, 114, 83, 225, 130, 18, 216, 22, 7, 84, 237, 17, 204, 135, 78, 165, 181, 116, 107, 256, 245, 113, 71, 81, 201, 99, 160, 121, 167, 205, 147, 222, 94, 100, 172, 8, 96, 124, 203, 123, 191, 236, 5, 60, 206, 159, 109, 23, 19, 228, 166, 193, 3, 36, 175, 44, 14, 168, 217, 34, 151, 13, 156, 73, 105, 232, 214, 255, 233, 226, 142, 162, 145, 198, 63, 242, 77, 153, 37, 187, 188, 200, 87, 16, 192, 248, 149, 246, 125, 215, 10, 120, 155, 61, 218, 46, 38, 199, 75, 129, 6, 72, 93, 88, 28, 79, 177, 68, 45, 26, 55, 146, 210, 207, 171, 253, 209, 195, 27, 67, 33, 139, 126, 227, 154, 49, 74, 117, 119, 143, 174, 32, 127, 239, 41, 235, 250, 173, 20, 240, 53, 122, 179, 92, 76, 141, 150, 1], +[1, 13, 169, 141, 34, 185, 92, 168, 128, 122, 44, 58, 240, 36, 211, 173, 193, 196, 235, 228, 137, 239, 23, 42, 32, 159, 11, 143, 60, 9, 117, 236, 241, 49, 123, 57, 227, 124, 70, 139, 8, 104, 67, 100, 15, 195, 222, 59, 253, 205, 95, 207, 121, 31, 146, 99, 2, 26, 81, 25, 68, 113, 184, 79, 256, 244, 88, 116, 223, 72, 165, 89, 129, 135, 213, 199, 17, 221, 46, 84, 64, 61, 22, 29, 120, 18, 234, 215, 225, 98, 246, 114, 197, 248, 140, 21, 16, 208, 134, 200, 30, 133, 187, 118, 249, 153, 190, 157, 242, 62, 35, 198, 4, 52, 162, 50, 136, 226, 111, 158, 255, 231, 176, 232, 189, 144, 73, 178, 1, 13, 169, 141, 34, 185, 92, 168, 128, 122, 44, 58, 240, 36, 211, 173, 193, 196, 235, 228, 137, 239, 23, 42, 32, 159, 11, 143, 60, 9, 117, 236, 241, 49, 123, 57, 227, 124, 70, 139, 8, 104, 67, 100, 15, 195, 222, 59, 253, 205, 95, 207, 121, 31, 146, 99, 2, 26, 81, 25, 68, 113, 184, 79, 256, 244, 88, 116, 223, 72, 165, 89, 129, 135, 213, 199, 17, 221, 46, 84, 64, 61, 22, 29, 120, 18, 234, 215, 225, 98, 246, 114, 197, 248, 140, 21, 16, 208, 134, 200, 30, 133, 187, 118, 249, 153, 190, 157, 242, 62, 35, 198, 4, 52, 162, 50, 136, 226, 111, 158, 255, 231, 176, 232, 189, 144, 73, 178, 1], +[1, 14, 196, 174, 123, 180, 207, 71, 223, 38, 18, 252, 187, 48, 158, 156, 128, 250, 159, 170, 67, 167, 25, 93, 17, 238, 248, 131, 35, 233, 178, 179, 193, 132, 49, 172, 95, 45, 116, 82, 120, 138, 133, 63, 111, 12, 168, 39, 32, 191, 104, 171, 81, 106, 199, 216, 197, 188, 62, 97, 73, 251, 173, 109, 241, 33, 205, 43, 88, 204, 29, 149, 30, 163, 226, 80, 92, 3, 42, 74, 8, 112, 26, 107, 213, 155, 114, 54, 242, 47, 144, 217, 211, 127, 236, 220, 253, 201, 244, 75, 22, 51, 200, 230, 136, 105, 185, 20, 23, 65, 139, 147, 2, 28, 135, 91, 246, 103, 157, 142, 189, 76, 36, 247, 117, 96, 59, 55, 256, 243, 61, 83, 134, 77, 50, 186, 34, 219, 239, 5, 70, 209, 99, 101, 129, 7, 98, 87, 190, 90, 232, 164, 240, 19, 9, 126, 222, 24, 79, 78, 64, 125, 208, 85, 162, 212, 141, 175, 137, 119, 124, 194, 146, 245, 89, 218, 225, 66, 153, 86, 176, 151, 58, 41, 60, 69, 195, 160, 184, 6, 84, 148, 16, 224, 52, 214, 169, 53, 228, 108, 227, 94, 31, 177, 165, 254, 215, 183, 249, 145, 231, 150, 44, 102, 143, 203, 15, 210, 113, 40, 46, 130, 21, 37, 4, 56, 13, 182, 235, 206, 57, 27, 121, 152, 72, 237, 234, 192, 118, 110, 255, 229, 122, 166, 11, 154, 100, 115, 68, 181, 221, 10, 140, 161, 198, 202, 1], +[1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1], +[1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1], +[1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1], +[1, 18, 67, 178, 120, 104, 73, 29, 8, 144, 22, 139, 189, 61, 70, 232, 64, 124, 176, 84, 227, 231, 46, 57, 255, 221, 123, 158, 17, 49, 111, 199, 241, 226, 213, 236, 136, 135, 117, 50, 129, 9, 162, 89, 60, 52, 165, 143, 4, 72, 11, 198, 223, 159, 35, 116, 32, 62, 88, 42, 242, 244, 23, 157, 256, 239, 190, 79, 137, 153, 184, 228, 249, 113, 235, 118, 68, 196, 187, 25, 193, 133, 81, 173, 30, 26, 211, 200, 2, 36, 134, 99, 240, 208, 146, 58, 16, 31, 44, 21, 121, 122, 140, 207, 128, 248, 95, 168, 197, 205, 92, 114, 253, 185, 246, 59, 34, 98, 222, 141, 225, 195, 169, 215, 15, 13, 234, 100, 1, 18, 67, 178, 120, 104, 73, 29, 8, 144, 22, 139, 189, 61, 70, 232, 64, 124, 176, 84, 227, 231, 46, 57, 255, 221, 123, 158, 17, 49, 111, 199, 241, 226, 213, 236, 136, 135, 117, 50, 129, 9, 162, 89, 60, 52, 165, 143, 4, 72, 11, 198, 223, 159, 35, 116, 32, 62, 88, 42, 242, 244, 23, 157, 256, 239, 190, 79, 137, 153, 184, 228, 249, 113, 235, 118, 68, 196, 187, 25, 193, 133, 81, 173, 30, 26, 211, 200, 2, 36, 134, 99, 240, 208, 146, 58, 16, 31, 44, 21, 121, 122, 140, 207, 128, 248, 95, 168, 197, 205, 92, 114, 253, 185, 246, 59, 34, 98, 222, 141, 225, 195, 169, 215, 15, 13, 234, 100, 1], +[1, 19, 104, 177, 22, 161, 232, 39, 227, 201, 221, 87, 111, 53, 236, 115, 129, 138, 52, 217, 11, 209, 116, 148, 242, 229, 239, 172, 184, 155, 118, 186, 193, 69, 26, 237, 134, 233, 58, 74, 121, 243, 248, 86, 92, 206, 59, 93, 225, 163, 13, 247, 67, 245, 29, 37, 189, 250, 124, 43, 46, 103, 158, 175, 241, 210, 135, 252, 162, 251, 143, 147, 223, 125, 62, 150, 23, 180, 79, 216, 249, 105, 196, 126, 81, 254, 200, 202, 240, 191, 31, 75, 140, 90, 168, 108, 253, 181, 98, 63, 169, 127, 100, 101, 120, 224, 144, 166, 70, 45, 84, 54, 255, 219, 49, 160, 213, 192, 50, 179, 60, 112, 72, 83, 35, 151, 42, 27, 256, 238, 153, 80, 235, 96, 25, 218, 30, 56, 36, 170, 146, 204, 21, 142, 128, 119, 205, 40, 246, 48, 141, 109, 15, 28, 18, 85, 73, 102, 139, 71, 64, 188, 231, 20, 123, 24, 199, 183, 136, 14, 9, 171, 165, 51, 198, 164, 32, 94, 244, 10, 190, 12, 228, 220, 68, 7, 133, 214, 211, 154, 99, 82, 16, 47, 122, 5, 95, 6, 114, 110, 34, 132, 195, 107, 234, 77, 178, 41, 8, 152, 61, 131, 176, 3, 57, 55, 17, 66, 226, 182, 117, 167, 89, 149, 4, 76, 159, 194, 88, 130, 157, 156, 137, 33, 113, 91, 187, 212, 173, 203, 2, 38, 208, 97, 44, 65, 207, 78, 197, 145, 185, 174, 222, 106, 215, 230, 1], +[1, 20, 143, 33, 146, 93, 61, 192, 242, 214, 168, 19, 123, 147, 113, 204, 225, 131, 50, 229, 211, 108, 104, 24, 223, 91, 21, 163, 176, 179, 239, 154, 253, 177, 199, 125, 187, 142, 13, 3, 60, 172, 99, 181, 22, 183, 62, 212, 128, 247, 57, 112, 184, 82, 98, 161, 136, 150, 173, 119, 67, 55, 72, 155, 16, 63, 232, 14, 23, 203, 205, 245, 17, 83, 118, 47, 169, 39, 9, 180, 2, 40, 29, 66, 35, 186, 122, 127, 227, 171, 79, 38, 246, 37, 226, 151, 193, 5, 100, 201, 165, 216, 208, 48, 189, 182, 42, 69, 95, 101, 221, 51, 249, 97, 141, 250, 117, 27, 26, 6, 120, 87, 198, 105, 44, 109, 124, 167, 256, 237, 114, 224, 111, 164, 196, 65, 15, 43, 89, 238, 134, 110, 144, 53, 32, 126, 207, 28, 46, 149, 153, 233, 34, 166, 236, 94, 81, 78, 18, 103, 4, 80, 58, 132, 70, 115, 244, 254, 197, 85, 158, 76, 235, 74, 195, 45, 129, 10, 200, 145, 73, 175, 159, 96, 121, 107, 84, 138, 190, 202, 185, 102, 241, 194, 25, 243, 234, 54, 52, 12, 240, 174, 139, 210, 88, 218, 248, 77, 255, 217, 228, 191, 222, 71, 135, 130, 30, 86, 178, 219, 11, 220, 31, 106, 64, 252, 157, 56, 92, 41, 49, 209, 68, 75, 215, 188, 162, 156, 36, 206, 8, 160, 116, 7, 140, 230, 231, 251, 137, 170, 59, 152, 213, 148, 133, 90, 1], +[1, 21, 184, 9, 189, 114, 81, 159, 255, 215, 146, 239, 136, 29, 95, 196, 4, 84, 222, 36, 242, 199, 67, 122, 249, 89, 70, 185, 30, 116, 123, 13, 16, 79, 117, 144, 197, 25, 11, 231, 225, 99, 23, 226, 120, 207, 235, 52, 64, 59, 211, 62, 17, 100, 44, 153, 129, 139, 92, 133, 223, 57, 169, 208, 256, 236, 73, 248, 68, 143, 176, 98, 2, 42, 111, 18, 121, 228, 162, 61, 253, 173, 35, 221, 15, 58, 190, 135, 8, 168, 187, 72, 227, 141, 134, 244, 241, 178, 140, 113, 60, 232, 246, 26, 32, 158, 234, 31, 137, 50, 22, 205, 193, 198, 46, 195, 240, 157, 213, 104, 128, 118, 165, 124, 34, 200, 88, 49, 1, 21, 184, 9, 189, 114, 81, 159, 255, 215, 146, 239, 136, 29, 95, 196, 4, 84, 222, 36, 242, 199, 67, 122, 249, 89, 70, 185, 30, 116, 123, 13, 16, 79, 117, 144, 197, 25, 11, 231, 225, 99, 23, 226, 120, 207, 235, 52, 64, 59, 211, 62, 17, 100, 44, 153, 129, 139, 92, 133, 223, 57, 169, 208, 256, 236, 73, 248, 68, 143, 176, 98, 2, 42, 111, 18, 121, 228, 162, 61, 253, 173, 35, 221, 15, 58, 190, 135, 8, 168, 187, 72, 227, 141, 134, 244, 241, 178, 140, 113, 60, 232, 246, 26, 32, 158, 234, 31, 137, 50, 22, 205, 193, 198, 46, 195, 240, 157, 213, 104, 128, 118, 165, 124, 34, 200, 88, 49, 1], +[1, 22, 227, 111, 129, 11, 242, 184, 193, 134, 121, 92, 225, 67, 189, 46, 241, 162, 223, 23, 249, 81, 240, 140, 253, 169, 120, 70, 255, 213, 60, 35, 256, 235, 30, 146, 128, 246, 15, 73, 64, 123, 136, 165, 32, 190, 68, 211, 16, 95, 34, 234, 8, 176, 17, 117, 4, 88, 137, 187, 2, 44, 197, 222, 1, 22, 227, 111, 129, 11, 242, 184, 193, 134, 121, 92, 225, 67, 189, 46, 241, 162, 223, 23, 249, 81, 240, 140, 253, 169, 120, 70, 255, 213, 60, 35, 256, 235, 30, 146, 128, 246, 15, 73, 64, 123, 136, 165, 32, 190, 68, 211, 16, 95, 34, 234, 8, 176, 17, 117, 4, 88, 137, 187, 2, 44, 197, 222, 1, 22, 227, 111, 129, 11, 242, 184, 193, 134, 121, 92, 225, 67, 189, 46, 241, 162, 223, 23, 249, 81, 240, 140, 253, 169, 120, 70, 255, 213, 60, 35, 256, 235, 30, 146, 128, 246, 15, 73, 64, 123, 136, 165, 32, 190, 68, 211, 16, 95, 34, 234, 8, 176, 17, 117, 4, 88, 137, 187, 2, 44, 197, 222, 1, 22, 227, 111, 129, 11, 242, 184, 193, 134, 121, 92, 225, 67, 189, 46, 241, 162, 223, 23, 249, 81, 240, 140, 253, 169, 120, 70, 255, 213, 60, 35, 256, 235, 30, 146, 128, 246, 15, 73, 64, 123, 136, 165, 32, 190, 68, 211, 16, 95, 34, 234, 8, 176, 17, 117, 4, 88, 137, 187, 2, 44, 197, 222, 1], +[1, 23, 15, 88, 225, 35, 34, 11, 253, 165, 197, 162, 128, 117, 121, 213, 16, 111, 240, 123, 2, 46, 30, 176, 193, 70, 68, 22, 249, 73, 137, 67, 256, 234, 242, 169, 32, 222, 223, 246, 4, 92, 60, 95, 129, 140, 136, 44, 241, 146, 17, 134, 255, 211, 227, 81, 64, 187, 189, 235, 8, 184, 120, 190, 1, 23, 15, 88, 225, 35, 34, 11, 253, 165, 197, 162, 128, 117, 121, 213, 16, 111, 240, 123, 2, 46, 30, 176, 193, 70, 68, 22, 249, 73, 137, 67, 256, 234, 242, 169, 32, 222, 223, 246, 4, 92, 60, 95, 129, 140, 136, 44, 241, 146, 17, 134, 255, 211, 227, 81, 64, 187, 189, 235, 8, 184, 120, 190, 1, 23, 15, 88, 225, 35, 34, 11, 253, 165, 197, 162, 128, 117, 121, 213, 16, 111, 240, 123, 2, 46, 30, 176, 193, 70, 68, 22, 249, 73, 137, 67, 256, 234, 242, 169, 32, 222, 223, 246, 4, 92, 60, 95, 129, 140, 136, 44, 241, 146, 17, 134, 255, 211, 227, 81, 64, 187, 189, 235, 8, 184, 120, 190, 1, 23, 15, 88, 225, 35, 34, 11, 253, 165, 197, 162, 128, 117, 121, 213, 16, 111, 240, 123, 2, 46, 30, 176, 193, 70, 68, 22, 249, 73, 137, 67, 256, 234, 242, 169, 32, 222, 223, 246, 4, 92, 60, 95, 129, 140, 136, 44, 241, 146, 17, 134, 255, 211, 227, 81, 64, 187, 189, 235, 8, 184, 120, 190, 1], +[1, 24, 62, 203, 246, 250, 89, 80, 121, 77, 49, 148, 211, 181, 232, 171, 249, 65, 18, 175, 88, 56, 59, 131, 60, 155, 122, 101, 111, 94, 200, 174, 64, 251, 113, 142, 67, 66, 42, 237, 34, 45, 52, 220, 140, 19, 199, 150, 2, 48, 124, 149, 235, 243, 178, 160, 242, 154, 98, 39, 165, 105, 207, 85, 241, 130, 36, 93, 176, 112, 118, 5, 120, 53, 244, 202, 222, 188, 143, 91, 128, 245, 226, 27, 134, 132, 84, 217, 68, 90, 104, 183, 23, 38, 141, 43, 4, 96, 248, 41, 213, 229, 99, 63, 227, 51, 196, 78, 73, 210, 157, 170, 225, 3, 72, 186, 95, 224, 236, 10, 240, 106, 231, 147, 187, 119, 29, 182, 256, 233, 195, 54, 11, 7, 168, 177, 136, 180, 208, 109, 46, 76, 25, 86, 8, 192, 239, 82, 169, 201, 198, 126, 197, 102, 135, 156, 146, 163, 57, 83, 193, 6, 144, 115, 190, 191, 215, 20, 223, 212, 205, 37, 117, 238, 58, 107, 255, 209, 133, 108, 22, 14, 79, 97, 15, 103, 159, 218, 92, 152, 50, 172, 16, 127, 221, 164, 81, 145, 139, 252, 137, 204, 13, 55, 35, 69, 114, 166, 129, 12, 31, 230, 123, 125, 173, 40, 189, 167, 153, 74, 234, 219, 116, 214, 253, 161, 9, 216, 44, 28, 158, 194, 30, 206, 61, 179, 184, 47, 100, 87, 32, 254, 185, 71, 162, 33, 21, 247, 17, 151, 26, 110, 70, 138, 228, 75, 1], +[1, 25, 111, 205, 242, 139, 134, 9, 225, 228, 46, 122, 223, 178, 81, 226, 253, 157, 70, 208, 60, 215, 235, 221, 128, 116, 73, 26, 136, 59, 190, 124, 16, 143, 234, 196, 17, 168, 88, 144, 2, 50, 222, 153, 227, 21, 11, 18, 193, 199, 92, 244, 189, 99, 162, 195, 249, 57, 140, 159, 120, 173, 213, 185, 256, 232, 146, 52, 15, 118, 123, 248, 32, 29, 211, 135, 34, 79, 176, 31, 4, 100, 187, 49, 197, 42, 22, 36, 129, 141, 184, 231, 121, 198, 67, 133, 241, 114, 23, 61, 240, 89, 169, 113, 255, 207, 35, 104, 30, 236, 246, 239, 64, 58, 165, 13, 68, 158, 95, 62, 8, 200, 117, 98, 137, 84, 44, 72, 1, 25, 111, 205, 242, 139, 134, 9, 225, 228, 46, 122, 223, 178, 81, 226, 253, 157, 70, 208, 60, 215, 235, 221, 128, 116, 73, 26, 136, 59, 190, 124, 16, 143, 234, 196, 17, 168, 88, 144, 2, 50, 222, 153, 227, 21, 11, 18, 193, 199, 92, 244, 189, 99, 162, 195, 249, 57, 140, 159, 120, 173, 213, 185, 256, 232, 146, 52, 15, 118, 123, 248, 32, 29, 211, 135, 34, 79, 176, 31, 4, 100, 187, 49, 197, 42, 22, 36, 129, 141, 184, 231, 121, 198, 67, 133, 241, 114, 23, 61, 240, 89, 169, 113, 255, 207, 35, 104, 30, 236, 246, 239, 64, 58, 165, 13, 68, 158, 95, 62, 8, 200, 117, 98, 137, 84, 44, 72, 1], +[1, 26, 162, 100, 30, 9, 234, 173, 129, 13, 81, 50, 15, 133, 117, 215, 193, 135, 169, 25, 136, 195, 187, 236, 225, 196, 213, 141, 68, 226, 222, 118, 241, 98, 235, 199, 34, 113, 111, 59, 249, 49, 246, 228, 17, 185, 184, 158, 253, 153, 123, 114, 137, 221, 92, 79, 255, 205, 190, 57, 197, 239, 46, 168, 256, 231, 95, 157, 227, 248, 23, 84, 128, 244, 176, 207, 242, 124, 140, 42, 64, 122, 88, 232, 121, 62, 70, 21, 32, 61, 44, 116, 189, 31, 35, 139, 16, 159, 22, 58, 223, 144, 146, 198, 8, 208, 11, 29, 240, 72, 73, 99, 4, 104, 134, 143, 120, 36, 165, 178, 2, 52, 67, 200, 60, 18, 211, 89, 1, 26, 162, 100, 30, 9, 234, 173, 129, 13, 81, 50, 15, 133, 117, 215, 193, 135, 169, 25, 136, 195, 187, 236, 225, 196, 213, 141, 68, 226, 222, 118, 241, 98, 235, 199, 34, 113, 111, 59, 249, 49, 246, 228, 17, 185, 184, 158, 253, 153, 123, 114, 137, 221, 92, 79, 255, 205, 190, 57, 197, 239, 46, 168, 256, 231, 95, 157, 227, 248, 23, 84, 128, 244, 176, 207, 242, 124, 140, 42, 64, 122, 88, 232, 121, 62, 70, 21, 32, 61, 44, 116, 189, 31, 35, 139, 16, 159, 22, 58, 223, 144, 146, 198, 8, 208, 11, 29, 240, 72, 73, 99, 4, 104, 134, 143, 120, 36, 165, 178, 2, 52, 67, 200, 60, 18, 211, 89, 1], +[1, 27, 215, 151, 222, 83, 185, 112, 197, 179, 207, 192, 44, 160, 208, 219, 2, 54, 173, 45, 187, 166, 113, 224, 137, 101, 157, 127, 88, 63, 159, 181, 4, 108, 89, 90, 117, 75, 226, 191, 17, 202, 57, 254, 176, 126, 61, 105, 8, 216, 178, 180, 234, 150, 195, 125, 34, 147, 114, 251, 95, 252, 122, 210, 16, 175, 99, 103, 211, 43, 133, 250, 68, 37, 228, 245, 190, 247, 244, 163, 32, 93, 198, 206, 165, 86, 9, 243, 136, 74, 199, 233, 123, 237, 231, 69, 64, 186, 139, 155, 73, 172, 18, 229, 15, 148, 141, 209, 246, 217, 205, 138, 128, 115, 21, 53, 146, 87, 36, 201, 30, 39, 25, 161, 235, 177, 153, 19, 256, 230, 42, 106, 35, 174, 72, 145, 60, 78, 50, 65, 213, 97, 49, 38, 255, 203, 84, 212, 70, 91, 144, 33, 120, 156, 100, 130, 169, 194, 98, 76, 253, 149, 168, 167, 140, 182, 31, 66, 240, 55, 200, 3, 81, 131, 196, 152, 249, 41, 79, 77, 23, 107, 62, 132, 223, 110, 143, 6, 162, 5, 135, 47, 241, 82, 158, 154, 46, 214, 124, 7, 189, 220, 29, 12, 67, 10, 13, 94, 225, 164, 59, 51, 92, 171, 248, 14, 121, 183, 58, 24, 134, 20, 26, 188, 193, 71, 118, 102, 184, 85, 239, 28, 242, 109, 116, 48, 11, 40, 52, 119, 129, 142, 236, 204, 111, 170, 221, 56, 227, 218, 232, 96, 22, 80, 104, 238, 1], +[1, 28, 13, 107, 169, 106, 141, 93, 34, 181, 185, 40, 92, 6, 168, 78, 128, 243, 122, 75, 44, 204, 58, 82, 240, 38, 36, 237, 211, 254, 173, 218, 193, 7, 196, 91, 235, 155, 228, 216, 137, 238, 239, 10, 23, 130, 42, 148, 32, 125, 159, 83, 11, 51, 143, 149, 60, 138, 9, 252, 117, 192, 236, 183, 241, 66, 49, 87, 123, 103, 57, 54, 227, 188, 124, 131, 70, 161, 139, 37, 8, 224, 104, 85, 67, 77, 100, 230, 15, 163, 195, 63, 222, 48, 59, 110, 253, 145, 205, 86, 95, 90, 207, 142, 121, 47, 31, 97, 146, 233, 99, 202, 2, 56, 26, 214, 81, 212, 25, 186, 68, 105, 113, 80, 184, 12, 79, 156, 256, 229, 244, 150, 88, 151, 116, 164, 223, 76, 72, 217, 165, 251, 89, 179, 129, 14, 135, 182, 213, 53, 199, 175, 17, 219, 221, 20, 46, 3, 84, 39, 64, 250, 61, 166, 22, 102, 29, 41, 120, 19, 18, 247, 234, 127, 215, 109, 225, 132, 98, 174, 246, 206, 114, 108, 197, 119, 248, 5, 140, 65, 21, 74, 16, 191, 208, 170, 134, 154, 200, 203, 30, 69, 133, 126, 187, 96, 118, 220, 249, 33, 153, 172, 190, 180, 157, 27, 242, 94, 62, 194, 35, 209, 198, 147, 4, 112, 52, 171, 162, 167, 50, 115, 136, 210, 226, 160, 111, 24, 158, 55, 255, 201, 231, 43, 176, 45, 232, 71, 189, 152, 144, 177, 73, 245, 178, 101, 1], +[1, 29, 70, 231, 17, 236, 162, 72, 32, 157, 184, 196, 30, 99, 44, 248, 253, 141, 234, 104, 189, 84, 123, 226, 129, 143, 35, 244, 137, 118, 81, 36, 16, 207, 92, 98, 15, 178, 22, 124, 255, 199, 117, 52, 223, 42, 190, 113, 193, 200, 146, 122, 197, 59, 169, 18, 8, 232, 46, 49, 136, 89, 11, 62, 256, 228, 187, 26, 240, 21, 95, 185, 225, 100, 73, 61, 227, 158, 213, 9, 4, 116, 23, 153, 68, 173, 134, 31, 128, 114, 222, 13, 120, 139, 176, 221, 241, 50, 165, 159, 242, 79, 235, 133, 2, 58, 140, 205, 34, 215, 67, 144, 64, 57, 111, 135, 60, 198, 88, 239, 249, 25, 211, 208, 121, 168, 246, 195, 1, 29, 70, 231, 17, 236, 162, 72, 32, 157, 184, 196, 30, 99, 44, 248, 253, 141, 234, 104, 189, 84, 123, 226, 129, 143, 35, 244, 137, 118, 81, 36, 16, 207, 92, 98, 15, 178, 22, 124, 255, 199, 117, 52, 223, 42, 190, 113, 193, 200, 146, 122, 197, 59, 169, 18, 8, 232, 46, 49, 136, 89, 11, 62, 256, 228, 187, 26, 240, 21, 95, 185, 225, 100, 73, 61, 227, 158, 213, 9, 4, 116, 23, 153, 68, 173, 134, 31, 128, 114, 222, 13, 120, 139, 176, 221, 241, 50, 165, 159, 242, 79, 235, 133, 2, 58, 140, 205, 34, 215, 67, 144, 64, 57, 111, 135, 60, 198, 88, 239, 249, 25, 211, 208, 121, 168, 246, 195, 1], +[1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1], +[1, 31, 190, 236, 120, 122, 184, 50, 8, 248, 235, 89, 189, 205, 187, 143, 64, 185, 81, 198, 227, 98, 211, 116, 255, 195, 134, 42, 17, 13, 146, 157, 241, 18, 44, 79, 136, 104, 140, 228, 129, 144, 95, 118, 60, 61, 92, 25, 4, 124, 246, 173, 223, 231, 222, 200, 32, 221, 169, 99, 242, 49, 234, 58, 256, 226, 67, 21, 137, 135, 73, 207, 249, 9, 22, 168, 68, 52, 70, 114, 193, 72, 176, 59, 30, 159, 46, 141, 2, 62, 123, 215, 240, 244, 111, 100, 16, 239, 213, 178, 121, 153, 117, 29, 128, 113, 162, 139, 197, 196, 165, 232, 253, 133, 11, 84, 34, 26, 35, 57, 225, 36, 88, 158, 15, 208, 23, 199, 1, 31, 190, 236, 120, 122, 184, 50, 8, 248, 235, 89, 189, 205, 187, 143, 64, 185, 81, 198, 227, 98, 211, 116, 255, 195, 134, 42, 17, 13, 146, 157, 241, 18, 44, 79, 136, 104, 140, 228, 129, 144, 95, 118, 60, 61, 92, 25, 4, 124, 246, 173, 223, 231, 222, 200, 32, 221, 169, 99, 242, 49, 234, 58, 256, 226, 67, 21, 137, 135, 73, 207, 249, 9, 22, 168, 68, 52, 70, 114, 193, 72, 176, 59, 30, 159, 46, 141, 2, 62, 123, 215, 240, 244, 111, 100, 16, 239, 213, 178, 121, 153, 117, 29, 128, 113, 162, 139, 197, 196, 165, 232, 253, 133, 11, 84, 34, 26, 35, 57, 225, 36, 88, 158, 15, 208, 23, 199, 1], +[1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1], +[1, 33, 61, 214, 123, 204, 50, 108, 223, 163, 239, 177, 187, 3, 99, 183, 128, 112, 98, 150, 67, 155, 232, 203, 17, 47, 9, 40, 35, 127, 79, 37, 193, 201, 208, 182, 95, 51, 141, 27, 120, 105, 124, 237, 111, 65, 89, 110, 32, 28, 153, 166, 81, 103, 58, 115, 197, 76, 195, 10, 73, 96, 84, 202, 241, 243, 52, 174, 88, 77, 228, 71, 30, 219, 31, 252, 92, 209, 215, 156, 8, 7, 231, 170, 213, 90, 143, 93, 242, 19, 113, 131, 211, 24, 21, 179, 253, 125, 13, 172, 22, 212, 57, 82, 136, 119, 72, 63, 23, 245, 118, 39, 2, 66, 122, 171, 246, 151, 100, 216, 189, 69, 221, 97, 117, 6, 198, 109, 256, 224, 196, 43, 134, 53, 207, 149, 34, 94, 18, 80, 70, 254, 158, 74, 129, 145, 159, 107, 190, 102, 25, 54, 240, 210, 248, 217, 222, 130, 178, 220, 64, 56, 49, 75, 162, 206, 116, 230, 137, 152, 133, 20, 146, 192, 168, 147, 225, 229, 104, 91, 176, 154, 199, 142, 60, 181, 62, 247, 184, 161, 173, 55, 16, 14, 205, 83, 169, 180, 29, 186, 227, 38, 226, 5, 165, 48, 42, 101, 249, 250, 26, 87, 44, 167, 114, 164, 15, 238, 144, 126, 46, 233, 236, 78, 4, 132, 244, 85, 235, 45, 200, 175, 121, 138, 185, 194, 234, 12, 139, 218, 255, 191, 135, 86, 11, 106, 157, 41, 68, 188, 36, 160, 140, 251, 59, 148, 1], +[1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1], +[1, 35, 197, 213, 2, 70, 137, 169, 4, 140, 17, 81, 8, 23, 34, 162, 16, 46, 68, 67, 32, 92, 136, 134, 64, 184, 15, 11, 128, 111, 30, 22, 256, 222, 60, 44, 255, 187, 120, 88, 253, 117, 240, 176, 249, 234, 223, 95, 241, 211, 189, 190, 225, 165, 121, 123, 193, 73, 242, 246, 129, 146, 227, 235, 1, 35, 197, 213, 2, 70, 137, 169, 4, 140, 17, 81, 8, 23, 34, 162, 16, 46, 68, 67, 32, 92, 136, 134, 64, 184, 15, 11, 128, 111, 30, 22, 256, 222, 60, 44, 255, 187, 120, 88, 253, 117, 240, 176, 249, 234, 223, 95, 241, 211, 189, 190, 225, 165, 121, 123, 193, 73, 242, 246, 129, 146, 227, 235, 1, 35, 197, 213, 2, 70, 137, 169, 4, 140, 17, 81, 8, 23, 34, 162, 16, 46, 68, 67, 32, 92, 136, 134, 64, 184, 15, 11, 128, 111, 30, 22, 256, 222, 60, 44, 255, 187, 120, 88, 253, 117, 240, 176, 249, 234, 223, 95, 241, 211, 189, 190, 225, 165, 121, 123, 193, 73, 242, 246, 129, 146, 227, 235, 1, 35, 197, 213, 2, 70, 137, 169, 4, 140, 17, 81, 8, 23, 34, 162, 16, 46, 68, 67, 32, 92, 136, 134, 64, 184, 15, 11, 128, 111, 30, 22, 256, 222, 60, 44, 255, 187, 120, 88, 253, 117, 240, 176, 249, 234, 223, 95, 241, 211, 189, 190, 225, 165, 121, 123, 193, 73, 242, 246, 129, 146, 227, 235, 1], +[1, 36, 11, 139, 121, 244, 46, 114, 249, 226, 169, 173, 60, 104, 146, 116, 64, 248, 190, 158, 34, 196, 117, 100, 2, 72, 22, 21, 242, 231, 92, 228, 241, 195, 81, 89, 120, 208, 35, 232, 128, 239, 123, 59, 68, 135, 234, 200, 4, 144, 44, 42, 227, 205, 184, 199, 225, 133, 162, 178, 240, 159, 70, 207, 256, 221, 246, 118, 136, 13, 211, 143, 8, 31, 88, 84, 197, 153, 111, 141, 193, 9, 67, 99, 223, 61, 140, 157, 255, 185, 235, 236, 15, 26, 165, 29, 16, 62, 176, 168, 137, 49, 222, 25, 129, 18, 134, 198, 189, 122, 23, 57, 253, 113, 213, 215, 30, 52, 73, 58, 32, 124, 95, 79, 17, 98, 187, 50, 1, 36, 11, 139, 121, 244, 46, 114, 249, 226, 169, 173, 60, 104, 146, 116, 64, 248, 190, 158, 34, 196, 117, 100, 2, 72, 22, 21, 242, 231, 92, 228, 241, 195, 81, 89, 120, 208, 35, 232, 128, 239, 123, 59, 68, 135, 234, 200, 4, 144, 44, 42, 227, 205, 184, 199, 225, 133, 162, 178, 240, 159, 70, 207, 256, 221, 246, 118, 136, 13, 211, 143, 8, 31, 88, 84, 197, 153, 111, 141, 193, 9, 67, 99, 223, 61, 140, 157, 255, 185, 235, 236, 15, 26, 165, 29, 16, 62, 176, 168, 137, 49, 222, 25, 129, 18, 134, 198, 189, 122, 23, 57, 253, 113, 213, 215, 30, 52, 73, 58, 32, 124, 95, 79, 17, 98, 187, 50, 1], +[1, 37, 84, 24, 117, 217, 62, 238, 68, 203, 58, 90, 246, 107, 104, 250, 255, 183, 89, 209, 23, 80, 133, 38, 121, 108, 141, 77, 22, 43, 49, 14, 4, 148, 79, 96, 211, 97, 248, 181, 15, 41, 232, 103, 213, 171, 159, 229, 249, 218, 99, 65, 92, 63, 18, 152, 227, 175, 50, 51, 88, 172, 196, 56, 16, 78, 59, 127, 73, 131, 221, 210, 60, 164, 157, 155, 81, 170, 122, 145, 225, 101, 139, 3, 111, 252, 72, 94, 137, 186, 200, 204, 95, 174, 13, 224, 64, 55, 236, 251, 35, 10, 113, 69, 240, 142, 114, 106, 67, 166, 231, 66, 129, 147, 42, 12, 187, 237, 31, 119, 34, 230, 29, 45, 123, 182, 52, 125, 256, 220, 173, 233, 140, 40, 195, 19, 189, 54, 199, 167, 11, 150, 153, 7, 2, 74, 168, 48, 234, 177, 124, 219, 136, 149, 116, 180, 235, 214, 208, 243, 253, 109, 178, 161, 46, 160, 9, 76, 242, 216, 25, 154, 44, 86, 98, 28, 8, 39, 158, 192, 165, 194, 239, 105, 30, 82, 207, 206, 169, 85, 61, 201, 241, 179, 198, 130, 184, 126, 36, 47, 197, 93, 100, 102, 176, 87, 135, 112, 32, 156, 118, 254, 146, 5, 185, 163, 120, 71, 57, 53, 162, 83, 244, 33, 193, 202, 21, 6, 222, 247, 144, 188, 17, 115, 143, 151, 190, 91, 26, 191, 128, 110, 215, 245, 70, 20, 226, 138, 223, 27, 228, 212, 134, 75, 205, 132, 1], +[1, 38, 159, 131, 95, 12, 199, 109, 30, 112, 144, 75, 23, 103, 59, 186, 129, 19, 208, 194, 176, 6, 228, 183, 15, 56, 72, 166, 140, 180, 158, 93, 193, 138, 104, 97, 88, 3, 114, 220, 136, 28, 36, 83, 70, 90, 79, 175, 225, 69, 52, 177, 44, 130, 57, 110, 68, 14, 18, 170, 35, 45, 168, 216, 241, 163, 26, 217, 22, 65, 157, 55, 34, 7, 9, 85, 146, 151, 84, 108, 249, 210, 13, 237, 11, 161, 207, 156, 17, 132, 133, 171, 73, 204, 42, 54, 253, 105, 135, 247, 134, 209, 232, 78, 137, 66, 195, 214, 165, 102, 21, 27, 255, 181, 196, 252, 67, 233, 116, 39, 197, 33, 226, 107, 211, 51, 139, 142, 256, 219, 98, 126, 162, 245, 58, 148, 227, 145, 113, 182, 234, 154, 198, 71, 128, 238, 49, 63, 81, 251, 29, 74, 242, 201, 185, 91, 117, 77, 99, 164, 64, 119, 153, 160, 169, 254, 143, 37, 121, 229, 221, 174, 187, 167, 178, 82, 32, 188, 205, 80, 213, 127, 200, 147, 189, 243, 239, 87, 222, 212, 89, 41, 16, 94, 231, 40, 235, 192, 100, 202, 223, 250, 248, 172, 111, 106, 173, 149, 8, 47, 244, 20, 246, 96, 50, 101, 240, 125, 124, 86, 184, 53, 215, 203, 4, 152, 122, 10, 123, 48, 25, 179, 120, 191, 62, 43, 92, 155, 236, 230, 2, 76, 61, 5, 190, 24, 141, 218, 60, 224, 31, 150, 46, 206, 118, 115, 1], +[1, 39, 236, 209, 184, 237, 248, 163, 189, 175, 143, 180, 81, 75, 98, 224, 255, 179, 42, 96, 146, 40, 18, 188, 136, 164, 228, 154, 95, 107, 61, 66, 4, 156, 173, 65, 222, 177, 221, 138, 242, 186, 58, 206, 67, 43, 135, 125, 249, 202, 168, 127, 70, 160, 72, 238, 30, 142, 141, 102, 123, 171, 244, 7, 16, 110, 178, 3, 117, 194, 113, 38, 197, 230, 232, 53, 11, 172, 26, 243, 225, 37, 158, 251, 23, 126, 31, 181, 120, 54, 50, 151, 235, 170, 205, 28, 64, 183, 198, 12, 211, 5, 195, 152, 17, 149, 157, 212, 44, 174, 104, 201, 129, 148, 118, 233, 92, 247, 124, 210, 223, 216, 200, 90, 169, 166, 49, 112, 256, 218, 21, 48, 73, 20, 9, 94, 68, 82, 114, 77, 176, 182, 159, 33, 2, 78, 215, 161, 111, 217, 239, 69, 121, 93, 29, 103, 162, 150, 196, 191, 253, 101, 84, 192, 35, 80, 36, 119, 15, 71, 199, 51, 190, 214, 122, 132, 8, 55, 89, 130, 187, 97, 185, 19, 227, 115, 116, 155, 134, 86, 13, 250, 241, 147, 79, 254, 140, 63, 144, 219, 60, 27, 25, 204, 246, 85, 231, 14, 32, 220, 99, 6, 234, 131, 226, 76, 137, 203, 207, 106, 22, 87, 52, 229, 193, 74, 59, 245, 46, 252, 62, 105, 240, 108, 100, 45, 213, 83, 153, 56, 128, 109, 139, 24, 165, 10, 133, 47, 34, 41, 57, 167, 88, 91, 208, 145, 1], +[1, 40, 58, 7, 23, 149, 49, 161, 15, 86, 99, 105, 88, 179, 221, 102, 225, 5, 200, 33, 35, 115, 231, 245, 34, 75, 173, 238, 11, 183, 124, 77, 253, 97, 25, 229, 165, 175, 61, 127, 197, 170, 118, 94, 162, 55, 144, 106, 128, 237, 228, 125, 117, 54, 104, 48, 121, 214, 79, 76, 213, 39, 18, 206, 16, 126, 157, 112, 111, 71, 13, 6, 240, 91, 42, 138, 123, 37, 195, 90, 2, 80, 116, 14, 46, 41, 98, 65, 30, 172, 198, 210, 176, 101, 185, 204, 193, 10, 143, 66, 70, 230, 205, 233, 68, 150, 89, 219, 22, 109, 248, 154, 249, 194, 50, 201, 73, 93, 122, 254, 137, 83, 236, 188, 67, 110, 31, 212, 256, 217, 199, 250, 234, 108, 208, 96, 242, 171, 158, 152, 169, 78, 36, 155, 32, 252, 57, 224, 222, 142, 26, 12, 223, 182, 84, 19, 246, 74, 133, 180, 4, 160, 232, 28, 92, 82, 196, 130, 60, 87, 139, 163, 95, 202, 113, 151, 129, 20, 29, 132, 140, 203, 153, 209, 136, 43, 178, 181, 44, 218, 239, 51, 241, 131, 100, 145, 146, 186, 244, 251, 17, 166, 215, 119, 134, 220, 62, 167, 255, 177, 141, 243, 211, 216, 159, 192, 227, 85, 59, 47, 81, 156, 72, 53, 64, 247, 114, 191, 187, 27, 52, 24, 189, 107, 168, 38, 235, 148, 9, 103, 8, 63, 207, 56, 184, 164, 135, 3, 120, 174, 21, 69, 190, 147, 226, 45, 1], +[1, 41, 139, 45, 46, 87, 226, 14, 60, 147, 116, 130, 190, 80, 196, 69, 2, 82, 21, 90, 92, 174, 195, 28, 120, 37, 232, 3, 123, 160, 135, 138, 4, 164, 42, 180, 184, 91, 133, 56, 240, 74, 207, 6, 246, 63, 13, 19, 8, 71, 84, 103, 111, 182, 9, 112, 223, 148, 157, 12, 235, 126, 26, 38, 16, 142, 168, 206, 222, 107, 18, 224, 189, 39, 57, 24, 213, 252, 52, 76, 32, 27, 79, 155, 187, 214, 36, 191, 121, 78, 114, 48, 169, 247, 104, 152, 64, 54, 158, 53, 117, 171, 72, 125, 242, 156, 228, 96, 81, 237, 208, 47, 128, 108, 59, 106, 234, 85, 144, 250, 227, 55, 199, 192, 162, 217, 159, 94, 256, 216, 118, 212, 211, 170, 31, 243, 197, 110, 141, 127, 67, 177, 61, 188, 255, 175, 236, 167, 165, 83, 62, 229, 137, 220, 25, 254, 134, 97, 122, 119, 253, 93, 215, 77, 73, 166, 124, 201, 17, 183, 50, 251, 11, 194, 244, 238, 249, 186, 173, 154, 146, 75, 248, 145, 34, 109, 100, 245, 22, 131, 231, 219, 241, 115, 89, 51, 35, 150, 239, 33, 68, 218, 200, 233, 44, 5, 205, 181, 225, 230, 178, 102, 70, 43, 221, 66, 136, 179, 143, 209, 88, 10, 153, 105, 193, 203, 99, 204, 140, 86, 185, 132, 15, 101, 29, 161, 176, 20, 49, 210, 129, 149, 198, 151, 23, 172, 113, 7, 30, 202, 58, 65, 95, 40, 98, 163, 1], +[1, 42, 222, 72, 197, 50, 44, 49, 2, 84, 187, 144, 137, 100, 88, 98, 4, 168, 117, 31, 17, 200, 176, 196, 8, 79, 234, 62, 34, 143, 95, 135, 16, 158, 211, 124, 68, 29, 190, 13, 32, 59, 165, 248, 136, 58, 123, 26, 64, 118, 73, 239, 15, 116, 246, 52, 128, 236, 146, 221, 30, 232, 235, 104, 256, 215, 35, 185, 60, 207, 213, 208, 255, 173, 70, 113, 120, 157, 169, 159, 253, 89, 140, 226, 240, 57, 81, 61, 249, 178, 23, 195, 223, 114, 162, 122, 241, 99, 46, 133, 189, 228, 67, 244, 225, 198, 92, 9, 121, 199, 134, 231, 193, 139, 184, 18, 242, 141, 11, 205, 129, 21, 111, 36, 227, 25, 22, 153, 1, 42, 222, 72, 197, 50, 44, 49, 2, 84, 187, 144, 137, 100, 88, 98, 4, 168, 117, 31, 17, 200, 176, 196, 8, 79, 234, 62, 34, 143, 95, 135, 16, 158, 211, 124, 68, 29, 190, 13, 32, 59, 165, 248, 136, 58, 123, 26, 64, 118, 73, 239, 15, 116, 246, 52, 128, 236, 146, 221, 30, 232, 235, 104, 256, 215, 35, 185, 60, 207, 213, 208, 255, 173, 70, 113, 120, 157, 169, 159, 253, 89, 140, 226, 240, 57, 81, 61, 249, 178, 23, 195, 223, 114, 162, 122, 241, 99, 46, 133, 189, 228, 67, 244, 225, 198, 92, 9, 121, 199, 134, 231, 193, 139, 184, 18, 242, 141, 11, 205, 129, 21, 111, 36, 227, 25, 22, 153, 1], +[1, 43, 50, 94, 187, 74, 98, 102, 17, 217, 79, 56, 95, 230, 124, 192, 32, 91, 58, 181, 73, 55, 52, 180, 30, 5, 215, 250, 213, 164, 113, 233, 253, 85, 57, 138, 23, 218, 122, 106, 189, 160, 198, 33, 134, 108, 18, 3, 129, 150, 25, 47, 222, 37, 49, 51, 137, 237, 168, 28, 176, 115, 62, 96, 16, 174, 29, 219, 165, 156, 26, 90, 15, 131, 236, 125, 235, 82, 185, 245, 255, 171, 157, 69, 140, 109, 61, 53, 223, 80, 99, 145, 67, 54, 9, 130, 193, 75, 141, 152, 111, 147, 153, 154, 197, 247, 84, 14, 88, 186, 31, 48, 8, 87, 143, 238, 211, 78, 13, 45, 136, 194, 118, 191, 246, 41, 221, 251, 256, 214, 207, 163, 70, 183, 159, 155, 240, 40, 178, 201, 162, 27, 133, 65, 225, 166, 199, 76, 184, 202, 205, 77, 227, 252, 42, 7, 44, 93, 144, 24, 4, 172, 200, 119, 234, 39, 135, 151, 68, 97, 59, 224, 123, 149, 239, 254, 128, 107, 232, 210, 35, 220, 208, 206, 120, 20, 89, 229, 81, 142, 195, 161, 241, 83, 228, 38, 92, 101, 231, 167, 242, 126, 21, 132, 22, 175, 72, 12, 2, 86, 100, 188, 117, 148, 196, 204, 34, 177, 158, 112, 190, 203, 248, 127, 64, 182, 116, 105, 146, 110, 104, 103, 60, 10, 173, 243, 169, 71, 226, 209, 249, 170, 114, 19, 46, 179, 244, 212, 121, 63, 139, 66, 11, 216, 36, 6, 1], +[1, 44, 137, 117, 8, 95, 68, 165, 64, 246, 30, 35, 255, 169, 240, 23, 241, 67, 121, 184, 129, 22, 197, 187, 4, 176, 34, 211, 32, 123, 15, 146, 256, 213, 120, 140, 249, 162, 189, 92, 193, 11, 227, 222, 2, 88, 17, 234, 16, 190, 136, 73, 128, 235, 60, 70, 253, 81, 223, 46, 225, 134, 242, 111, 1, 44, 137, 117, 8, 95, 68, 165, 64, 246, 30, 35, 255, 169, 240, 23, 241, 67, 121, 184, 129, 22, 197, 187, 4, 176, 34, 211, 32, 123, 15, 146, 256, 213, 120, 140, 249, 162, 189, 92, 193, 11, 227, 222, 2, 88, 17, 234, 16, 190, 136, 73, 128, 235, 60, 70, 253, 81, 223, 46, 225, 134, 242, 111, 1, 44, 137, 117, 8, 95, 68, 165, 64, 246, 30, 35, 255, 169, 240, 23, 241, 67, 121, 184, 129, 22, 197, 187, 4, 176, 34, 211, 32, 123, 15, 146, 256, 213, 120, 140, 249, 162, 189, 92, 193, 11, 227, 222, 2, 88, 17, 234, 16, 190, 136, 73, 128, 235, 60, 70, 253, 81, 223, 46, 225, 134, 242, 111, 1, 44, 137, 117, 8, 95, 68, 165, 64, 246, 30, 35, 255, 169, 240, 23, 241, 67, 121, 184, 129, 22, 197, 187, 4, 176, 34, 211, 32, 123, 15, 146, 256, 213, 120, 140, 249, 162, 189, 92, 193, 11, 227, 222, 2, 88, 17, 234, 16, 190, 136, 73, 128, 235, 60, 70, 253, 81, 223, 46, 225, 134, 242, 111, 1], +[1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207, 63, 8, 103, 9, 148, 235, 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247, 64, 53, 72, 156, 81, 47, 59, 85, 227, 192, 159, 216, 211, 243, 141, 177, 255, 167, 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131, 241, 51, 239, 218, 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, 20, 129, 151, 113, 202, 95, 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160, 4, 180, 133, 74, 246, 19, 84, 182, 223, 12, 26, 142, 222, 224, 57, 252, 32, 155, 36, 78, 169, 152, 158, 171, 242, 96, 208, 108, 234, 250, 199, 217, 256, 212, 31, 110, 67, 188, 236, 83, 137, 254, 122, 93, 73, 201, 50, 194, 249, 154, 248, 109, 22, 219, 89, 150, 68, 233, 205, 230, 70, 66, 143, 10, 193, 204, 185, 101, 176, 210, 198, 172, 30, 65, 98, 41, 46, 14, 116, 80, 2, 90, 195, 37, 123, 138, 42, 91, 240, 6, 13, 71, 111, 112, 157, 126, 16, 206, 18, 39, 213, 76, 79, 214, 121, 48, 104, 54, 117, 125, 228, 237, 128, 106, 144, 55, 162, 94, 118, 170, 197, 127, 61, 175, 165, 229, 25, 97, 253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35, 33, 200, 5, 225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7, 58, 40, 1], +[1, 46, 60, 190, 2, 92, 120, 123, 4, 184, 240, 246, 8, 111, 223, 235, 16, 222, 189, 213, 32, 187, 121, 169, 64, 117, 242, 81, 128, 234, 227, 162, 256, 211, 197, 67, 255, 165, 137, 134, 253, 73, 17, 11, 249, 146, 34, 22, 241, 35, 68, 44, 225, 70, 136, 88, 193, 140, 15, 176, 129, 23, 30, 95, 1, 46, 60, 190, 2, 92, 120, 123, 4, 184, 240, 246, 8, 111, 223, 235, 16, 222, 189, 213, 32, 187, 121, 169, 64, 117, 242, 81, 128, 234, 227, 162, 256, 211, 197, 67, 255, 165, 137, 134, 253, 73, 17, 11, 249, 146, 34, 22, 241, 35, 68, 44, 225, 70, 136, 88, 193, 140, 15, 176, 129, 23, 30, 95, 1, 46, 60, 190, 2, 92, 120, 123, 4, 184, 240, 246, 8, 111, 223, 235, 16, 222, 189, 213, 32, 187, 121, 169, 64, 117, 242, 81, 128, 234, 227, 162, 256, 211, 197, 67, 255, 165, 137, 134, 253, 73, 17, 11, 249, 146, 34, 22, 241, 35, 68, 44, 225, 70, 136, 88, 193, 140, 15, 176, 129, 23, 30, 95, 1, 46, 60, 190, 2, 92, 120, 123, 4, 184, 240, 246, 8, 111, 223, 235, 16, 222, 189, 213, 32, 187, 121, 169, 64, 117, 242, 81, 128, 234, 227, 162, 256, 211, 197, 67, 255, 165, 137, 134, 253, 73, 17, 11, 249, 146, 34, 22, 241, 35, 68, 44, 225, 70, 136, 88, 193, 140, 15, 176, 129, 23, 30, 95, 1], +[1, 47, 153, 252, 22, 6, 25, 147, 227, 132, 36, 150, 111, 77, 21, 216, 129, 152, 205, 126, 11, 3, 141, 202, 242, 66, 18, 75, 184, 167, 139, 108, 193, 76, 231, 63, 134, 130, 199, 101, 121, 33, 9, 166, 92, 212, 198, 54, 225, 38, 244, 160, 67, 65, 228, 179, 189, 145, 133, 83, 46, 106, 99, 27, 241, 19, 122, 80, 162, 161, 114, 218, 223, 201, 195, 170, 23, 53, 178, 142, 249, 138, 61, 40, 81, 209, 57, 109, 240, 229, 226, 85, 140, 155, 89, 71, 253, 69, 159, 20, 169, 233, 157, 183, 120, 243, 113, 171, 70, 206, 173, 164, 255, 163, 208, 10, 213, 245, 207, 220, 60, 250, 185, 214, 35, 103, 215, 82, 256, 210, 104, 5, 235, 251, 232, 110, 30, 125, 221, 107, 146, 180, 236, 41, 128, 105, 52, 131, 246, 254, 116, 55, 15, 191, 239, 182, 73, 90, 118, 149, 64, 181, 26, 194, 123, 127, 58, 156, 136, 224, 248, 91, 165, 45, 59, 203, 32, 219, 13, 97, 190, 192, 29, 78, 68, 112, 124, 174, 211, 151, 158, 230, 16, 238, 135, 177, 95, 96, 143, 39, 34, 56, 62, 87, 234, 204, 79, 115, 8, 119, 196, 217, 176, 48, 200, 148, 17, 28, 31, 172, 117, 102, 168, 186, 4, 188, 98, 237, 88, 24, 100, 74, 137, 14, 144, 86, 187, 51, 84, 93, 2, 94, 49, 247, 44, 12, 50, 37, 197, 7, 72, 43, 222, 154, 42, 175, 1], +[1, 48, 248, 82, 81, 33, 42, 217, 136, 103, 61, 101, 222, 119, 58, 214, 249, 130, 72, 115, 123, 250, 178, 63, 197, 204, 26, 220, 23, 76, 50, 87, 64, 245, 195, 108, 44, 56, 118, 10, 223, 167, 49, 39, 73, 163, 114, 75, 2, 96, 239, 164, 162, 66, 84, 177, 15, 206, 122, 202, 187, 238, 116, 171, 241, 3, 144, 230, 246, 243, 99, 126, 137, 151, 52, 183, 46, 152, 100, 174, 128, 233, 133, 216, 88, 112, 236, 20, 189, 77, 98, 78, 146, 69, 228, 150, 4, 192, 221, 71, 67, 132, 168, 97, 30, 155, 244, 147, 117, 219, 232, 85, 225, 6, 31, 203, 235, 229, 198, 252, 17, 45, 104, 109, 92, 47, 200, 91, 256, 209, 9, 175, 176, 224, 215, 40, 121, 154, 196, 156, 35, 138, 199, 43, 8, 127, 185, 142, 134, 7, 79, 194, 60, 53, 231, 37, 234, 181, 207, 170, 193, 12, 62, 149, 213, 201, 139, 247, 34, 90, 208, 218, 184, 94, 143, 182, 255, 161, 18, 93, 95, 191, 173, 80, 242, 51, 135, 55, 70, 19, 141, 86, 16, 254, 113, 27, 11, 14, 158, 131, 120, 106, 205, 74, 211, 105, 157, 83, 129, 24, 124, 41, 169, 145, 21, 237, 68, 180, 159, 179, 111, 188, 29, 107, 253, 65, 36, 186, 190, 125, 89, 160, 227, 102, 13, 110, 140, 38, 25, 172, 32, 251, 226, 54, 22, 28, 59, 5, 240, 212, 153, 148, 165, 210, 57, 166, 1], +[1, 49, 88, 200, 34, 124, 165, 118, 128, 104, 213, 157, 240, 195, 46, 198, 193, 205, 22, 50, 137, 31, 234, 158, 32, 26, 246, 232, 60, 113, 140, 178, 241, 244, 134, 141, 227, 72, 187, 168, 8, 135, 190, 58, 15, 221, 35, 173, 253, 61, 162, 228, 121, 18, 111, 42, 2, 98, 176, 143, 68, 248, 73, 236, 256, 208, 169, 57, 223, 133, 92, 139, 129, 153, 44, 100, 17, 62, 211, 59, 64, 52, 235, 207, 120, 226, 23, 99, 225, 231, 11, 25, 197, 144, 117, 79, 16, 13, 123, 116, 30, 185, 70, 89, 249, 122, 67, 199, 242, 36, 222, 84, 4, 196, 95, 29, 136, 239, 146, 215, 255, 159, 81, 114, 189, 9, 184, 21, 1, 49, 88, 200, 34, 124, 165, 118, 128, 104, 213, 157, 240, 195, 46, 198, 193, 205, 22, 50, 137, 31, 234, 158, 32, 26, 246, 232, 60, 113, 140, 178, 241, 244, 134, 141, 227, 72, 187, 168, 8, 135, 190, 58, 15, 221, 35, 173, 253, 61, 162, 228, 121, 18, 111, 42, 2, 98, 176, 143, 68, 248, 73, 236, 256, 208, 169, 57, 223, 133, 92, 139, 129, 153, 44, 100, 17, 62, 211, 59, 64, 52, 235, 207, 120, 226, 23, 99, 225, 231, 11, 25, 197, 144, 117, 79, 16, 13, 123, 116, 30, 185, 70, 89, 249, 122, 67, 199, 242, 36, 222, 84, 4, 196, 95, 29, 136, 239, 146, 215, 255, 159, 81, 114, 189, 9, 184, 21, 1], +[1, 50, 187, 98, 17, 79, 95, 124, 32, 58, 73, 52, 30, 215, 213, 113, 253, 57, 23, 122, 189, 198, 134, 18, 129, 25, 222, 49, 137, 168, 176, 62, 16, 29, 165, 26, 15, 236, 235, 185, 255, 157, 140, 61, 223, 99, 67, 9, 193, 141, 111, 153, 197, 84, 88, 31, 8, 143, 211, 13, 136, 118, 246, 221, 256, 207, 70, 159, 240, 178, 162, 133, 225, 199, 184, 205, 227, 42, 44, 144, 4, 200, 234, 135, 68, 59, 123, 239, 128, 232, 35, 208, 120, 89, 81, 195, 241, 228, 92, 231, 242, 21, 22, 72, 2, 100, 117, 196, 34, 158, 190, 248, 64, 116, 146, 104, 60, 173, 169, 226, 249, 114, 46, 244, 121, 139, 11, 36, 1, 50, 187, 98, 17, 79, 95, 124, 32, 58, 73, 52, 30, 215, 213, 113, 253, 57, 23, 122, 189, 198, 134, 18, 129, 25, 222, 49, 137, 168, 176, 62, 16, 29, 165, 26, 15, 236, 235, 185, 255, 157, 140, 61, 223, 99, 67, 9, 193, 141, 111, 153, 197, 84, 88, 31, 8, 143, 211, 13, 136, 118, 246, 221, 256, 207, 70, 159, 240, 178, 162, 133, 225, 199, 184, 205, 227, 42, 44, 144, 4, 200, 234, 135, 68, 59, 123, 239, 128, 232, 35, 208, 120, 89, 81, 195, 241, 228, 92, 231, 242, 21, 22, 72, 2, 100, 117, 196, 34, 158, 190, 248, 64, 116, 146, 104, 60, 173, 169, 226, 249, 114, 46, 244, 121, 139, 11, 36, 1], +[1, 51, 31, 39, 190, 181, 236, 214, 120, 209, 122, 54, 184, 132, 50, 237, 8, 151, 248, 55, 235, 163, 89, 170, 189, 130, 205, 175, 187, 28, 143, 97, 64, 180, 185, 183, 81, 19, 198, 75, 227, 12, 98, 115, 211, 224, 116, 5, 255, 155, 195, 179, 134, 152, 42, 86, 17, 96, 13, 149, 146, 250, 157, 40, 241, 212, 18, 147, 44, 188, 79, 174, 136, 254, 104, 164, 140, 201, 228, 63, 129, 154, 144, 148, 95, 219, 118, 107, 60, 233, 61, 27, 92, 66, 25, 247, 4, 204, 124, 156, 246, 210, 173, 85, 223, 65, 231, 216, 222, 14, 200, 177, 32, 90, 221, 220, 169, 138, 99, 166, 242, 6, 49, 186, 234, 112, 58, 131, 256, 206, 226, 218, 67, 76, 21, 43, 137, 48, 135, 203, 73, 125, 207, 20, 249, 106, 9, 202, 22, 94, 168, 87, 68, 127, 52, 82, 70, 229, 114, 160, 193, 77, 72, 74, 176, 238, 59, 182, 30, 245, 159, 142, 46, 33, 141, 252, 2, 102, 62, 78, 123, 105, 215, 171, 240, 161, 244, 108, 111, 7, 100, 217, 16, 45, 239, 110, 213, 69, 178, 83, 121, 3, 153, 93, 117, 56, 29, 194, 128, 103, 113, 109, 162, 38, 139, 150, 197, 24, 196, 230, 165, 191, 232, 10, 253, 53, 133, 101, 11, 47, 84, 172, 34, 192, 26, 41, 35, 243, 57, 80, 225, 167, 36, 37, 88, 119, 158, 91, 15, 251, 208, 71, 23, 145, 199, 126, 1], +[1, 52, 134, 29, 223, 31, 70, 42, 128, 231, 190, 114, 17, 113, 222, 236, 193, 13, 162, 200, 120, 72, 146, 139, 32, 122, 176, 157, 197, 221, 184, 59, 241, 196, 169, 50, 30, 18, 165, 99, 8, 159, 44, 232, 242, 248, 46, 79, 253, 49, 235, 141, 136, 133, 234, 89, 2, 104, 11, 58, 189, 62, 140, 84, 256, 205, 123, 228, 34, 226, 187, 215, 129, 26, 67, 143, 240, 144, 35, 21, 64, 244, 95, 57, 137, 185, 111, 118, 225, 135, 81, 100, 60, 36, 73, 198, 16, 61, 88, 207, 227, 239, 92, 158, 249, 98, 213, 25, 15, 9, 211, 178, 4, 208, 22, 116, 121, 124, 23, 168, 255, 153, 246, 199, 68, 195, 117, 173, 1, 52, 134, 29, 223, 31, 70, 42, 128, 231, 190, 114, 17, 113, 222, 236, 193, 13, 162, 200, 120, 72, 146, 139, 32, 122, 176, 157, 197, 221, 184, 59, 241, 196, 169, 50, 30, 18, 165, 99, 8, 159, 44, 232, 242, 248, 46, 79, 253, 49, 235, 141, 136, 133, 234, 89, 2, 104, 11, 58, 189, 62, 140, 84, 256, 205, 123, 228, 34, 226, 187, 215, 129, 26, 67, 143, 240, 144, 35, 21, 64, 244, 95, 57, 137, 185, 111, 118, 225, 135, 81, 100, 60, 36, 73, 198, 16, 61, 88, 207, 227, 239, 92, 158, 249, 98, 213, 25, 15, 9, 211, 178, 4, 208, 22, 116, 121, 124, 23, 168, 255, 153, 246, 199, 68, 195, 117, 173, 1], +[1, 53, 239, 74, 67, 210, 79, 75, 120, 192, 153, 142, 73, 14, 228, 5, 8, 167, 113, 78, 22, 138, 118, 86, 189, 251, 196, 108, 70, 112, 25, 40, 64, 51, 133, 110, 176, 76, 173, 174, 227, 209, 26, 93, 46, 125, 200, 63, 255, 151, 36, 109, 123, 94, 99, 107, 17, 130, 208, 230, 111, 229, 58, 247, 241, 180, 31, 101, 213, 238, 21, 85, 136, 12, 122, 41, 117, 33, 207, 177, 129, 155, 248, 37, 162, 105, 168, 166, 60, 96, 205, 71, 165, 7, 114, 131, 4, 212, 185, 39, 11, 69, 59, 43, 223, 254, 98, 54, 35, 56, 141, 20, 32, 154, 195, 55, 88, 38, 215, 87, 242, 233, 13, 175, 23, 191, 100, 160, 256, 204, 18, 183, 190, 47, 178, 182, 137, 65, 104, 115, 184, 243, 29, 252, 249, 90, 144, 179, 235, 119, 139, 171, 68, 6, 61, 149, 187, 145, 232, 217, 193, 206, 124, 147, 81, 181, 84, 83, 30, 48, 231, 164, 211, 132, 57, 194, 2, 106, 221, 148, 134, 163, 158, 150, 240, 127, 49, 27, 146, 28, 199, 10, 16, 77, 226, 156, 44, 19, 236, 172, 121, 245, 135, 216, 140, 224, 50, 80, 128, 102, 9, 220, 95, 152, 89, 91, 197, 161, 52, 186, 92, 250, 143, 126, 253, 45, 72, 218, 246, 188, 198, 214, 34, 3, 159, 203, 222, 201, 116, 237, 225, 103, 62, 202, 169, 219, 42, 170, 15, 24, 244, 82, 234, 66, 157, 97, 1], +[1, 54, 89, 180, 211, 86, 18, 201, 60, 156, 200, 6, 67, 20, 52, 238, 2, 108, 178, 103, 165, 172, 36, 145, 120, 55, 143, 12, 134, 40, 104, 219, 4, 216, 99, 206, 73, 87, 72, 33, 240, 110, 29, 24, 11, 80, 208, 181, 8, 175, 198, 155, 146, 174, 144, 66, 223, 220, 58, 48, 22, 160, 159, 105, 16, 93, 139, 53, 35, 91, 31, 132, 189, 183, 116, 96, 44, 63, 61, 210, 32, 186, 21, 106, 70, 182, 62, 7, 121, 109, 232, 192, 88, 126, 122, 163, 64, 115, 42, 212, 140, 107, 124, 14, 242, 218, 207, 127, 176, 252, 244, 69, 128, 230, 84, 167, 23, 214, 248, 28, 227, 179, 157, 254, 95, 247, 231, 138, 256, 203, 168, 77, 46, 171, 239, 56, 197, 101, 57, 251, 190, 237, 205, 19, 255, 149, 79, 154, 92, 85, 221, 112, 137, 202, 114, 245, 123, 217, 153, 38, 253, 41, 158, 51, 184, 170, 185, 224, 17, 147, 228, 233, 246, 177, 49, 76, 249, 82, 59, 102, 111, 83, 113, 191, 34, 37, 199, 209, 235, 97, 98, 152, 241, 164, 118, 204, 222, 166, 226, 125, 68, 74, 141, 161, 213, 194, 196, 47, 225, 71, 236, 151, 187, 75, 195, 250, 136, 148, 25, 65, 169, 131, 135, 94, 193, 142, 215, 45, 117, 150, 133, 243, 15, 39, 50, 130, 81, 5, 13, 188, 129, 27, 173, 90, 234, 43, 9, 229, 30, 78, 100, 3, 162, 10, 26, 119, 1], +[1, 55, 198, 96, 140, 247, 221, 76, 68, 142, 100, 103, 11, 91, 122, 28, 255, 147, 118, 65, 234, 20, 72, 105, 121, 230, 57, 51, 235, 75, 13, 201, 4, 220, 21, 127, 46, 217, 113, 47, 15, 54, 143, 155, 44, 107, 231, 112, 249, 74, 215, 3, 165, 80, 31, 163, 227, 149, 228, 204, 169, 43, 52, 33, 16, 109, 84, 251, 184, 97, 195, 188, 60, 216, 58, 106, 176, 171, 153, 191, 225, 39, 89, 12, 146, 63, 124, 138, 137, 82, 141, 45, 162, 172, 208, 132, 64, 179, 79, 233, 222, 131, 9, 238, 240, 93, 232, 167, 190, 170, 98, 250, 129, 156, 99, 48, 70, 252, 239, 38, 34, 71, 50, 180, 134, 174, 61, 14, 256, 202, 59, 161, 117, 10, 36, 181, 189, 115, 157, 154, 246, 166, 135, 229, 2, 110, 139, 192, 23, 237, 185, 152, 136, 27, 200, 206, 22, 182, 244, 56, 253, 37, 236, 130, 211, 40, 144, 210, 242, 203, 114, 102, 213, 150, 26, 145, 8, 183, 42, 254, 92, 177, 226, 94, 30, 108, 29, 53, 88, 214, 205, 224, 241, 148, 173, 6, 73, 160, 62, 69, 197, 41, 199, 151, 81, 86, 104, 66, 32, 218, 168, 245, 111, 194, 133, 119, 120, 175, 116, 212, 95, 85, 49, 125, 193, 78, 178, 24, 35, 126, 248, 19, 17, 164, 25, 90, 67, 87, 159, 7, 128, 101, 158, 209, 187, 5, 18, 219, 223, 186, 207, 77, 123, 83, 196, 243, 1], +[1, 56, 52, 85, 134, 51, 29, 82, 223, 152, 31, 194, 70, 65, 42, 39, 128, 229, 231, 86, 190, 103, 114, 216, 17, 181, 113, 160, 222, 96, 236, 109, 193, 14, 13, 214, 162, 77, 200, 149, 120, 38, 72, 177, 146, 209, 139, 74, 32, 250, 122, 150, 176, 90, 157, 54, 197, 238, 221, 40, 184, 24, 59, 220, 241, 132, 196, 182, 169, 212, 50, 230, 30, 138, 18, 237, 165, 245, 99, 147, 8, 191, 159, 166, 44, 151, 232, 142, 242, 188, 248, 10, 46, 6, 79, 55, 253, 33, 49, 174, 235, 53, 141, 186, 136, 163, 133, 252, 234, 254, 89, 101, 2, 112, 104, 170, 11, 102, 58, 164, 189, 47, 62, 131, 140, 130, 84, 78, 256, 201, 205, 172, 123, 206, 228, 175, 34, 105, 226, 63, 187, 192, 215, 218, 129, 28, 26, 171, 67, 154, 143, 41, 240, 76, 144, 97, 35, 161, 21, 148, 64, 243, 244, 43, 95, 180, 57, 108, 137, 219, 185, 80, 111, 48, 118, 183, 225, 7, 135, 107, 81, 167, 100, 203, 60, 19, 36, 217, 73, 233, 198, 37, 16, 125, 61, 75, 88, 45, 207, 27, 227, 119, 239, 20, 92, 12, 158, 110, 249, 66, 98, 91, 213, 106, 25, 115, 15, 69, 9, 247, 211, 251, 178, 202, 4, 224, 208, 83, 22, 204, 116, 71, 121, 94, 124, 5, 23, 3, 168, 156, 255, 145, 153, 87, 246, 155, 199, 93, 68, 210, 195, 126, 117, 127, 173, 179, 1], +[1, 57, 165, 153, 240, 59, 22, 226, 32, 25, 140, 13, 227, 89, 190, 36, 253, 29, 111, 159, 68, 21, 169, 124, 129, 157, 211, 205, 120, 158, 11, 113, 16, 141, 70, 135, 242, 173, 95, 18, 255, 143, 184, 208, 34, 139, 213, 62, 193, 207, 234, 231, 60, 79, 134, 185, 8, 199, 35, 196, 121, 215, 176, 9, 256, 200, 92, 104, 17, 198, 235, 31, 225, 232, 117, 244, 30, 168, 67, 221, 4, 228, 146, 98, 189, 236, 88, 133, 128, 100, 46, 52, 137, 99, 246, 144, 241, 116, 187, 122, 15, 84, 162, 239, 2, 114, 73, 49, 223, 118, 44, 195, 64, 50, 23, 26, 197, 178, 123, 72, 249, 58, 222, 61, 136, 42, 81, 248, 1, 57, 165, 153, 240, 59, 22, 226, 32, 25, 140, 13, 227, 89, 190, 36, 253, 29, 111, 159, 68, 21, 169, 124, 129, 157, 211, 205, 120, 158, 11, 113, 16, 141, 70, 135, 242, 173, 95, 18, 255, 143, 184, 208, 34, 139, 213, 62, 193, 207, 234, 231, 60, 79, 134, 185, 8, 199, 35, 196, 121, 215, 176, 9, 256, 200, 92, 104, 17, 198, 235, 31, 225, 232, 117, 244, 30, 168, 67, 221, 4, 228, 146, 98, 189, 236, 88, 133, 128, 100, 46, 52, 137, 99, 246, 144, 241, 116, 187, 122, 15, 84, 162, 239, 2, 114, 73, 49, 223, 118, 44, 195, 64, 50, 23, 26, 197, 178, 123, 72, 249, 58, 222, 61, 136, 42, 81, 248, 1], +[1, 58, 23, 49, 15, 99, 88, 221, 225, 200, 35, 231, 34, 173, 11, 124, 253, 25, 165, 61, 197, 118, 162, 144, 128, 228, 117, 104, 121, 79, 213, 18, 16, 157, 111, 13, 240, 42, 123, 195, 2, 116, 46, 98, 30, 198, 176, 185, 193, 143, 70, 205, 68, 89, 22, 248, 249, 50, 73, 122, 137, 236, 67, 31, 256, 199, 234, 208, 242, 158, 169, 36, 32, 57, 222, 26, 223, 84, 246, 133, 4, 232, 92, 196, 60, 139, 95, 113, 129, 29, 140, 153, 136, 178, 44, 239, 241, 100, 146, 244, 17, 215, 134, 62, 255, 141, 211, 159, 227, 59, 81, 72, 64, 114, 187, 52, 189, 168, 235, 9, 8, 207, 184, 135, 120, 21, 190, 226, 1, 58, 23, 49, 15, 99, 88, 221, 225, 200, 35, 231, 34, 173, 11, 124, 253, 25, 165, 61, 197, 118, 162, 144, 128, 228, 117, 104, 121, 79, 213, 18, 16, 157, 111, 13, 240, 42, 123, 195, 2, 116, 46, 98, 30, 198, 176, 185, 193, 143, 70, 205, 68, 89, 22, 248, 249, 50, 73, 122, 137, 236, 67, 31, 256, 199, 234, 208, 242, 158, 169, 36, 32, 57, 222, 26, 223, 84, 246, 133, 4, 232, 92, 196, 60, 139, 95, 113, 129, 29, 140, 153, 136, 178, 44, 239, 241, 100, 146, 244, 17, 215, 134, 62, 255, 141, 211, 159, 227, 59, 81, 72, 64, 114, 187, 52, 189, 168, 235, 9, 8, 207, 184, 135, 120, 21, 190, 226, 1], +[1, 59, 140, 36, 68, 157, 11, 135, 255, 139, 234, 185, 121, 200, 235, 244, 4, 236, 46, 144, 15, 114, 44, 26, 249, 42, 165, 226, 227, 29, 169, 205, 16, 173, 184, 62, 60, 199, 176, 104, 225, 168, 146, 133, 137, 116, 162, 49, 64, 178, 222, 248, 240, 25, 190, 159, 129, 158, 70, 18, 34, 207, 134, 196, 256, 198, 117, 221, 189, 100, 246, 122, 2, 118, 23, 72, 136, 57, 22, 13, 253, 21, 211, 113, 242, 143, 213, 231, 8, 215, 92, 31, 30, 228, 88, 52, 241, 84, 73, 195, 197, 58, 81, 153, 32, 89, 111, 124, 120, 141, 95, 208, 193, 79, 35, 9, 17, 232, 67, 98, 128, 99, 187, 239, 223, 50, 123, 61, 1, 59, 140, 36, 68, 157, 11, 135, 255, 139, 234, 185, 121, 200, 235, 244, 4, 236, 46, 144, 15, 114, 44, 26, 249, 42, 165, 226, 227, 29, 169, 205, 16, 173, 184, 62, 60, 199, 176, 104, 225, 168, 146, 133, 137, 116, 162, 49, 64, 178, 222, 248, 240, 25, 190, 159, 129, 158, 70, 18, 34, 207, 134, 196, 256, 198, 117, 221, 189, 100, 246, 122, 2, 118, 23, 72, 136, 57, 22, 13, 253, 21, 211, 113, 242, 143, 213, 231, 8, 215, 92, 31, 30, 228, 88, 52, 241, 84, 73, 195, 197, 58, 81, 153, 32, 89, 111, 124, 120, 141, 95, 208, 193, 79, 35, 9, 17, 232, 67, 98, 128, 99, 187, 239, 223, 50, 123, 61, 1], +[1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1], +[1, 61, 123, 50, 223, 239, 187, 99, 128, 98, 67, 232, 17, 9, 35, 79, 193, 208, 95, 141, 120, 124, 111, 89, 32, 153, 81, 58, 197, 195, 73, 84, 241, 52, 88, 228, 30, 31, 92, 215, 8, 231, 213, 143, 242, 113, 211, 21, 253, 13, 22, 57, 136, 72, 23, 118, 2, 122, 246, 100, 189, 221, 117, 198, 256, 196, 134, 207, 34, 18, 70, 158, 129, 159, 190, 25, 240, 248, 222, 178, 64, 49, 162, 116, 137, 133, 146, 168, 225, 104, 176, 199, 60, 62, 184, 173, 16, 205, 169, 29, 227, 226, 165, 42, 249, 26, 44, 114, 15, 144, 46, 236, 4, 244, 235, 200, 121, 185, 234, 139, 255, 135, 11, 157, 68, 36, 140, 59, 1, 61, 123, 50, 223, 239, 187, 99, 128, 98, 67, 232, 17, 9, 35, 79, 193, 208, 95, 141, 120, 124, 111, 89, 32, 153, 81, 58, 197, 195, 73, 84, 241, 52, 88, 228, 30, 31, 92, 215, 8, 231, 213, 143, 242, 113, 211, 21, 253, 13, 22, 57, 136, 72, 23, 118, 2, 122, 246, 100, 189, 221, 117, 198, 256, 196, 134, 207, 34, 18, 70, 158, 129, 159, 190, 25, 240, 248, 222, 178, 64, 49, 162, 116, 137, 133, 146, 168, 225, 104, 176, 199, 60, 62, 184, 173, 16, 205, 169, 29, 227, 226, 165, 42, 249, 26, 44, 114, 15, 144, 46, 236, 4, 244, 235, 200, 121, 185, 234, 139, 255, 135, 11, 157, 68, 36, 140, 59, 1], +[1, 62, 246, 89, 121, 49, 211, 232, 249, 18, 88, 59, 60, 122, 111, 200, 64, 113, 67, 42, 34, 52, 140, 199, 2, 124, 235, 178, 242, 98, 165, 207, 241, 36, 176, 118, 120, 244, 222, 143, 128, 226, 134, 84, 68, 104, 23, 141, 4, 248, 213, 99, 227, 196, 73, 157, 225, 72, 95, 236, 240, 231, 187, 29, 256, 195, 11, 168, 136, 208, 46, 25, 8, 239, 169, 198, 197, 135, 146, 57, 193, 144, 190, 215, 223, 205, 117, 58, 255, 133, 22, 79, 15, 159, 92, 50, 16, 221, 81, 139, 137, 13, 35, 114, 129, 31, 123, 173, 189, 153, 234, 116, 253, 9, 44, 158, 30, 61, 184, 100, 32, 185, 162, 21, 17, 26, 70, 228, 1, 62, 246, 89, 121, 49, 211, 232, 249, 18, 88, 59, 60, 122, 111, 200, 64, 113, 67, 42, 34, 52, 140, 199, 2, 124, 235, 178, 242, 98, 165, 207, 241, 36, 176, 118, 120, 244, 222, 143, 128, 226, 134, 84, 68, 104, 23, 141, 4, 248, 213, 99, 227, 196, 73, 157, 225, 72, 95, 236, 240, 231, 187, 29, 256, 195, 11, 168, 136, 208, 46, 25, 8, 239, 169, 198, 197, 135, 146, 57, 193, 144, 190, 215, 223, 205, 117, 58, 255, 133, 22, 79, 15, 159, 92, 50, 16, 221, 81, 139, 137, 13, 35, 114, 129, 31, 123, 173, 189, 153, 234, 116, 253, 9, 44, 158, 30, 61, 184, 100, 32, 185, 162, 21, 17, 26, 70, 228, 1], +[1, 63, 114, 243, 146, 203, 196, 12, 242, 83, 89, 210, 123, 39, 144, 77, 225, 40, 207, 191, 211, 186, 153, 130, 223, 171, 236, 219, 176, 37, 18, 106, 253, 5, 58, 56, 187, 216, 244, 209, 60, 182, 158, 188, 22, 101, 195, 206, 128, 97, 200, 7, 184, 27, 159, 251, 136, 87, 84, 152, 67, 109, 185, 90, 16, 237, 25, 33, 23, 164, 52, 192, 17, 43, 139, 19, 169, 110, 248, 204, 2, 126, 228, 229, 35, 149, 135, 24, 227, 166, 178, 163, 246, 78, 31, 154, 193, 80, 157, 125, 165, 115, 49, 3, 189, 85, 215, 181, 95, 74, 36, 212, 249, 10, 116, 112, 117, 175, 231, 161, 120, 107, 59, 119, 44, 202, 133, 155, 256, 194, 143, 14, 111, 54, 61, 245, 15, 174, 168, 47, 134, 218, 113, 180, 32, 217, 50, 66, 46, 71, 104, 127, 34, 86, 21, 38, 81, 220, 239, 151, 4, 252, 199, 201, 70, 41, 13, 48, 197, 75, 99, 69, 235, 156, 62, 51, 129, 160, 57, 250, 73, 230, 98, 6, 121, 170, 173, 105, 190, 148, 72, 167, 241, 20, 232, 224, 234, 93, 205, 65, 240, 214, 118, 238, 88, 147, 9, 53, 255, 131, 29, 28, 222, 108, 122, 233, 30, 91, 79, 94, 11, 179, 226, 103, 64, 177, 100, 132, 92, 142, 208, 254, 68, 172, 42, 76, 162, 183, 221, 45, 8, 247, 141, 145, 140, 82, 26, 96, 137, 150, 198, 138, 213, 55, 124, 102, 1], +[1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1], +[1, 65, 113, 149, 176, 132, 99, 10, 136, 102, 205, 218, 35, 219, 100, 75, 249, 251, 124, 93, 134, 229, 236, 177, 197, 212, 159, 55, 234, 47, 228, 171, 64, 48, 36, 27, 213, 224, 168, 126, 223, 103, 13, 74, 184, 138, 232, 174, 2, 130, 226, 41, 95, 7, 198, 20, 15, 204, 153, 179, 70, 181, 200, 150, 241, 245, 248, 186, 11, 201, 215, 97, 137, 167, 61, 110, 211, 94, 199, 85, 128, 96, 72, 54, 169, 191, 79, 252, 189, 206, 26, 148, 111, 19, 207, 91, 4, 3, 195, 82, 190, 14, 139, 40, 30, 151, 49, 101, 140, 105, 143, 43, 225, 233, 239, 115, 22, 145, 173, 194, 17, 77, 122, 220, 165, 188, 141, 170, 256, 192, 144, 108, 81, 125, 158, 247, 121, 155, 52, 39, 222, 38, 157, 182, 8, 6, 133, 164, 123, 28, 21, 80, 60, 45, 98, 202, 23, 210, 29, 86, 193, 209, 221, 230, 44, 33, 89, 131, 34, 154, 244, 183, 73, 119, 25, 83, 255, 127, 31, 216, 162, 250, 59, 237, 242, 53, 104, 78, 187, 76, 57, 107, 16, 12, 9, 71, 246, 56, 42, 160, 120, 90, 196, 147, 46, 163, 58, 172, 129, 161, 185, 203, 88, 66, 178, 5, 68, 51, 231, 109, 146, 238, 50, 166, 253, 254, 62, 175, 67, 243, 118, 217, 227, 106, 208, 156, 117, 152, 114, 214, 32, 24, 18, 142, 235, 112, 84, 63, 240, 180, 135, 37, 92, 69, 116, 87, 1], +[1, 66, 244, 170, 169, 103, 116, 203, 34, 188, 72, 126, 92, 161, 89, 220, 128, 224, 135, 172, 44, 77, 199, 27, 240, 163, 221, 194, 211, 48, 84, 147, 193, 145, 61, 171, 235, 90, 29, 115, 137, 47, 18, 160, 23, 233, 215, 55, 32, 56, 98, 43, 11, 212, 114, 71, 60, 105, 248, 177, 117, 12, 21, 101, 241, 229, 208, 107, 123, 151, 200, 93, 227, 76, 133, 40, 70, 251, 118, 78, 8, 14, 153, 75, 67, 53, 157, 82, 15, 219, 62, 237, 222, 3, 198, 218, 253, 250, 52, 91, 95, 102, 50, 216, 121, 19, 226, 10, 146, 127, 158, 148, 2, 132, 231, 83, 81, 206, 232, 149, 68, 119, 144, 252, 184, 65, 178, 183, 256, 191, 13, 87, 88, 154, 141, 54, 223, 69, 185, 131, 165, 96, 168, 37, 129, 33, 122, 85, 213, 180, 58, 230, 17, 94, 36, 63, 46, 209, 173, 110, 64, 112, 196, 86, 22, 167, 228, 142, 120, 210, 239, 97, 234, 24, 42, 202, 225, 201, 159, 214, 246, 45, 143, 186, 197, 152, 9, 80, 140, 245, 236, 156, 16, 28, 49, 150, 134, 106, 57, 164, 30, 181, 124, 217, 187, 6, 139, 179, 249, 243, 104, 182, 190, 204, 100, 175, 242, 38, 195, 20, 35, 254, 59, 39, 4, 7, 205, 166, 162, 155, 207, 41, 136, 238, 31, 247, 111, 130, 99, 109, 255, 125, 26, 174, 176, 51, 25, 108, 189, 138, 113, 5, 73, 192, 79, 74, 1], +[1, 67, 120, 73, 8, 22, 189, 70, 64, 176, 227, 46, 255, 123, 17, 111, 241, 213, 136, 117, 129, 162, 60, 165, 4, 11, 223, 35, 32, 88, 242, 23, 256, 190, 137, 184, 249, 235, 68, 187, 193, 81, 30, 211, 2, 134, 240, 146, 16, 44, 121, 140, 128, 95, 197, 92, 253, 246, 34, 222, 225, 169, 15, 234, 1, 67, 120, 73, 8, 22, 189, 70, 64, 176, 227, 46, 255, 123, 17, 111, 241, 213, 136, 117, 129, 162, 60, 165, 4, 11, 223, 35, 32, 88, 242, 23, 256, 190, 137, 184, 249, 235, 68, 187, 193, 81, 30, 211, 2, 134, 240, 146, 16, 44, 121, 140, 128, 95, 197, 92, 253, 246, 34, 222, 225, 169, 15, 234, 1, 67, 120, 73, 8, 22, 189, 70, 64, 176, 227, 46, 255, 123, 17, 111, 241, 213, 136, 117, 129, 162, 60, 165, 4, 11, 223, 35, 32, 88, 242, 23, 256, 190, 137, 184, 249, 235, 68, 187, 193, 81, 30, 211, 2, 134, 240, 146, 16, 44, 121, 140, 128, 95, 197, 92, 253, 246, 34, 222, 225, 169, 15, 234, 1, 67, 120, 73, 8, 22, 189, 70, 64, 176, 227, 46, 255, 123, 17, 111, 241, 213, 136, 117, 129, 162, 60, 165, 4, 11, 223, 35, 32, 88, 242, 23, 256, 190, 137, 184, 249, 235, 68, 187, 193, 81, 30, 211, 2, 134, 240, 146, 16, 44, 121, 140, 128, 95, 197, 92, 253, 246, 34, 222, 225, 169, 15, 234, 1], +[1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1], +[1, 69, 135, 63, 235, 24, 114, 156, 227, 243, 62, 166, 146, 51, 178, 203, 129, 163, 196, 160, 246, 12, 57, 78, 242, 250, 31, 83, 73, 154, 89, 230, 193, 210, 98, 80, 123, 6, 157, 39, 121, 125, 144, 170, 165, 77, 173, 115, 225, 105, 49, 40, 190, 3, 207, 148, 189, 191, 72, 85, 211, 167, 215, 186, 241, 181, 153, 20, 95, 130, 232, 74, 223, 224, 36, 171, 234, 212, 236, 93, 249, 219, 205, 10, 176, 65, 116, 37, 240, 112, 18, 214, 117, 106, 118, 175, 253, 238, 231, 5, 88, 161, 58, 147, 120, 56, 9, 107, 187, 53, 59, 216, 255, 119, 244, 131, 44, 209, 29, 202, 60, 28, 133, 182, 222, 155, 158, 108, 256, 188, 122, 194, 22, 233, 143, 101, 30, 14, 195, 91, 111, 206, 79, 54, 128, 94, 61, 97, 11, 245, 200, 179, 15, 7, 226, 174, 184, 103, 168, 27, 64, 47, 159, 177, 134, 251, 100, 218, 136, 132, 113, 87, 92, 180, 84, 142, 32, 152, 208, 217, 67, 254, 50, 109, 68, 66, 185, 172, 46, 90, 42, 71, 16, 76, 104, 237, 162, 127, 25, 183, 34, 33, 221, 86, 23, 45, 21, 164, 8, 38, 52, 247, 81, 192, 141, 220, 17, 145, 239, 43, 140, 151, 139, 82, 4, 19, 26, 252, 169, 96, 199, 110, 137, 201, 248, 150, 70, 204, 198, 41, 2, 138, 13, 126, 213, 48, 228, 55, 197, 229, 124, 75, 35, 102, 99, 149, 1], +[1, 70, 17, 162, 32, 184, 30, 44, 253, 234, 189, 123, 129, 35, 137, 81, 16, 92, 15, 22, 255, 117, 223, 190, 193, 146, 197, 169, 8, 46, 136, 11, 256, 187, 240, 95, 225, 73, 227, 213, 4, 23, 68, 134, 128, 222, 120, 176, 241, 165, 242, 235, 2, 140, 34, 67, 64, 111, 60, 88, 249, 211, 121, 246, 1, 70, 17, 162, 32, 184, 30, 44, 253, 234, 189, 123, 129, 35, 137, 81, 16, 92, 15, 22, 255, 117, 223, 190, 193, 146, 197, 169, 8, 46, 136, 11, 256, 187, 240, 95, 225, 73, 227, 213, 4, 23, 68, 134, 128, 222, 120, 176, 241, 165, 242, 235, 2, 140, 34, 67, 64, 111, 60, 88, 249, 211, 121, 246, 1, 70, 17, 162, 32, 184, 30, 44, 253, 234, 189, 123, 129, 35, 137, 81, 16, 92, 15, 22, 255, 117, 223, 190, 193, 146, 197, 169, 8, 46, 136, 11, 256, 187, 240, 95, 225, 73, 227, 213, 4, 23, 68, 134, 128, 222, 120, 176, 241, 165, 242, 235, 2, 140, 34, 67, 64, 111, 60, 88, 249, 211, 121, 246, 1, 70, 17, 162, 32, 184, 30, 44, 253, 234, 189, 123, 129, 35, 137, 81, 16, 92, 15, 22, 255, 117, 223, 190, 193, 146, 197, 169, 8, 46, 136, 11, 256, 187, 240, 95, 225, 73, 227, 213, 4, 23, 68, 134, 128, 222, 120, 176, 241, 165, 242, 235, 2, 140, 34, 67, 64, 111, 60, 88, 249, 211, 121, 246, 1], +[1, 71, 158, 167, 35, 172, 133, 191, 197, 109, 29, 3, 213, 217, 244, 105, 2, 142, 59, 77, 70, 87, 9, 125, 137, 218, 58, 6, 169, 177, 231, 210, 4, 27, 118, 154, 140, 174, 18, 250, 17, 179, 116, 12, 81, 97, 205, 163, 8, 54, 236, 51, 23, 91, 36, 243, 34, 101, 232, 24, 162, 194, 153, 69, 16, 108, 215, 102, 46, 182, 72, 229, 68, 202, 207, 48, 67, 131, 49, 138, 32, 216, 173, 204, 92, 107, 144, 201, 136, 147, 157, 96, 134, 5, 98, 19, 64, 175, 89, 151, 184, 214, 31, 145, 15, 37, 57, 192, 11, 10, 196, 38, 128, 93, 178, 45, 111, 171, 62, 33, 30, 74, 114, 127, 22, 20, 135, 76, 256, 186, 99, 90, 222, 85, 124, 66, 60, 148, 228, 254, 44, 40, 13, 152, 255, 115, 198, 180, 187, 170, 248, 132, 120, 39, 199, 251, 88, 80, 26, 47, 253, 230, 139, 103, 117, 83, 239, 7, 240, 78, 141, 245, 176, 160, 52, 94, 249, 203, 21, 206, 234, 166, 221, 14, 223, 156, 25, 233, 95, 63, 104, 188, 241, 149, 42, 155, 211, 75, 185, 28, 189, 55, 50, 209, 190, 126, 208, 119, 225, 41, 84, 53, 165, 150, 113, 56, 121, 110, 100, 161, 123, 252, 159, 238, 193, 82, 168, 106, 73, 43, 226, 112, 242, 220, 200, 65, 246, 247, 61, 219, 129, 164, 79, 212, 146, 86, 195, 224, 227, 183, 143, 130, 235, 237, 122, 181, 1], +[1, 72, 44, 84, 137, 98, 117, 200, 8, 62, 95, 158, 68, 13, 165, 58, 64, 239, 246, 236, 30, 104, 35, 207, 255, 113, 169, 89, 240, 61, 23, 114, 241, 133, 67, 198, 121, 231, 184, 141, 129, 36, 22, 42, 197, 49, 187, 100, 4, 31, 176, 79, 34, 135, 211, 29, 32, 248, 123, 118, 15, 52, 146, 232, 256, 185, 213, 173, 120, 159, 140, 57, 249, 195, 162, 99, 189, 244, 92, 199, 193, 18, 11, 21, 227, 153, 222, 50, 2, 144, 88, 168, 17, 196, 234, 143, 16, 124, 190, 59, 136, 26, 73, 116, 128, 221, 235, 215, 60, 208, 70, 157, 253, 226, 81, 178, 223, 122, 46, 228, 225, 9, 134, 139, 242, 205, 111, 25, 1, 72, 44, 84, 137, 98, 117, 200, 8, 62, 95, 158, 68, 13, 165, 58, 64, 239, 246, 236, 30, 104, 35, 207, 255, 113, 169, 89, 240, 61, 23, 114, 241, 133, 67, 198, 121, 231, 184, 141, 129, 36, 22, 42, 197, 49, 187, 100, 4, 31, 176, 79, 34, 135, 211, 29, 32, 248, 123, 118, 15, 52, 146, 232, 256, 185, 213, 173, 120, 159, 140, 57, 249, 195, 162, 99, 189, 244, 92, 199, 193, 18, 11, 21, 227, 153, 222, 50, 2, 144, 88, 168, 17, 196, 234, 143, 16, 124, 190, 59, 136, 26, 73, 116, 128, 221, 235, 215, 60, 208, 70, 157, 253, 226, 81, 178, 223, 122, 46, 228, 225, 9, 134, 139, 242, 205, 111, 25, 1], +[1, 73, 189, 176, 255, 111, 136, 162, 4, 35, 242, 190, 249, 187, 30, 134, 16, 140, 197, 246, 225, 234, 120, 22, 64, 46, 17, 213, 129, 165, 223, 88, 256, 184, 68, 81, 2, 146, 121, 95, 253, 222, 15, 67, 8, 70, 227, 123, 241, 117, 60, 11, 32, 23, 137, 235, 193, 211, 240, 44, 128, 92, 34, 169, 1, 73, 189, 176, 255, 111, 136, 162, 4, 35, 242, 190, 249, 187, 30, 134, 16, 140, 197, 246, 225, 234, 120, 22, 64, 46, 17, 213, 129, 165, 223, 88, 256, 184, 68, 81, 2, 146, 121, 95, 253, 222, 15, 67, 8, 70, 227, 123, 241, 117, 60, 11, 32, 23, 137, 235, 193, 211, 240, 44, 128, 92, 34, 169, 1, 73, 189, 176, 255, 111, 136, 162, 4, 35, 242, 190, 249, 187, 30, 134, 16, 140, 197, 246, 225, 234, 120, 22, 64, 46, 17, 213, 129, 165, 223, 88, 256, 184, 68, 81, 2, 146, 121, 95, 253, 222, 15, 67, 8, 70, 227, 123, 241, 117, 60, 11, 32, 23, 137, 235, 193, 211, 240, 44, 128, 92, 34, 169, 1, 73, 189, 176, 255, 111, 136, 162, 4, 35, 242, 190, 249, 187, 30, 134, 16, 140, 197, 246, 225, 234, 120, 22, 64, 46, 17, 213, 129, 165, 223, 88, 256, 184, 68, 81, 2, 146, 121, 95, 253, 222, 15, 67, 8, 70, 227, 123, 241, 117, 60, 11, 32, 23, 137, 235, 193, 211, 240, 44, 128, 92, 34, 169, 1], +[1, 74, 79, 192, 73, 5, 113, 138, 189, 108, 25, 51, 176, 174, 26, 125, 255, 109, 99, 130, 111, 247, 31, 238, 136, 41, 207, 155, 162, 166, 205, 7, 4, 39, 59, 254, 35, 20, 195, 38, 242, 175, 100, 204, 190, 182, 104, 243, 249, 179, 139, 6, 187, 217, 124, 181, 30, 164, 57, 106, 134, 150, 49, 28, 16, 156, 236, 245, 140, 80, 9, 152, 197, 186, 143, 45, 246, 214, 159, 201, 225, 202, 42, 24, 234, 97, 239, 210, 120, 142, 228, 167, 22, 86, 196, 112, 64, 110, 173, 209, 46, 63, 36, 94, 17, 230, 58, 180, 213, 85, 122, 33, 129, 37, 168, 96, 165, 131, 185, 69, 223, 54, 141, 154, 88, 87, 13, 191, 256, 183, 178, 65, 184, 252, 144, 119, 68, 149, 232, 206, 81, 83, 231, 132, 2, 148, 158, 127, 146, 10, 226, 19, 121, 216, 50, 102, 95, 91, 52, 250, 253, 218, 198, 3, 222, 237, 62, 219, 15, 82, 157, 53, 67, 75, 153, 14, 8, 78, 118, 251, 70, 40, 133, 76, 227, 93, 200, 151, 123, 107, 208, 229, 241, 101, 21, 12, 117, 177, 248, 105, 60, 71, 114, 212, 11, 43, 98, 56, 32, 55, 215, 233, 23, 160, 18, 47, 137, 115, 29, 90, 235, 171, 61, 145, 193, 147, 84, 48, 211, 194, 221, 163, 240, 27, 199, 77, 44, 172, 135, 224, 128, 220, 89, 161, 92, 126, 72, 188, 34, 203, 116, 103, 169, 170, 244, 66, 1], +[1, 75, 228, 138, 70, 110, 26, 151, 17, 247, 21, 33, 162, 71, 185, 254, 32, 87, 100, 47, 184, 179, 61, 206, 30, 194, 158, 28, 44, 216, 9, 161, 253, 214, 116, 219, 234, 74, 153, 167, 189, 40, 173, 125, 123, 230, 31, 12, 129, 166, 114, 69, 35, 55, 13, 204, 137, 252, 139, 145, 81, 164, 221, 127, 16, 172, 50, 152, 92, 218, 159, 103, 15, 97, 79, 14, 22, 108, 133, 209, 255, 107, 58, 238, 117, 37, 205, 212, 223, 20, 215, 191, 190, 115, 144, 6, 193, 83, 57, 163, 146, 156, 135, 102, 197, 126, 198, 201, 169, 82, 239, 192, 8, 86, 25, 76, 46, 109, 208, 180, 136, 177, 168, 7, 11, 54, 195, 233, 256, 182, 29, 119, 187, 147, 231, 106, 240, 10, 236, 224, 95, 186, 72, 3, 225, 170, 157, 210, 73, 78, 196, 51, 227, 63, 99, 229, 213, 41, 248, 96, 4, 43, 141, 38, 23, 183, 104, 90, 68, 217, 84, 132, 134, 27, 226, 245, 128, 91, 143, 188, 222, 202, 244, 53, 120, 5, 118, 112, 176, 93, 36, 130, 241, 85, 207, 105, 165, 39, 98, 154, 242, 160, 178, 243, 235, 149, 124, 48, 2, 150, 199, 19, 140, 220, 52, 45, 34, 237, 42, 66, 67, 142, 113, 251, 64, 174, 200, 94, 111, 101, 122, 155, 60, 131, 59, 56, 88, 175, 18, 65, 249, 171, 232, 181, 211, 148, 49, 77, 121, 80, 89, 250, 246, 203, 62, 24, 1], +[1, 76, 122, 20, 235, 127, 143, 74, 227, 33, 195, 171, 146, 45, 79, 93, 129, 38, 61, 10, 246, 192, 200, 37, 242, 145, 226, 214, 73, 151, 168, 175, 193, 19, 159, 5, 123, 96, 100, 147, 121, 201, 113, 107, 165, 204, 84, 216, 225, 138, 208, 131, 190, 48, 50, 202, 189, 229, 185, 182, 211, 102, 42, 108, 241, 69, 104, 194, 95, 24, 25, 101, 223, 243, 221, 91, 234, 51, 21, 54, 249, 163, 52, 97, 176, 12, 141, 179, 240, 250, 239, 174, 117, 154, 139, 27, 253, 210, 26, 177, 88, 6, 199, 218, 120, 125, 248, 87, 187, 77, 198, 142, 255, 105, 13, 217, 44, 3, 228, 109, 60, 191, 124, 172, 222, 167, 99, 71, 256, 181, 135, 237, 22, 130, 114, 183, 30, 224, 62, 86, 111, 212, 178, 164, 128, 219, 196, 247, 11, 65, 57, 220, 15, 112, 31, 43, 184, 106, 89, 82, 64, 238, 98, 252, 134, 161, 157, 110, 136, 56, 144, 150, 92, 53, 173, 41, 32, 119, 49, 126, 67, 209, 207, 55, 68, 28, 72, 75, 46, 155, 215, 149, 16, 188, 153, 63, 162, 233, 232, 156, 34, 14, 36, 166, 23, 206, 236, 203, 8, 94, 205, 160, 81, 245, 116, 78, 17, 7, 18, 83, 140, 103, 118, 230, 4, 47, 231, 80, 169, 251, 58, 39, 137, 132, 9, 170, 70, 180, 59, 115, 2, 152, 244, 40, 213, 254, 29, 148, 197, 66, 133, 85, 35, 90, 158, 186, 1], +[1, 77, 18, 101, 67, 19, 178, 85, 120, 245, 104, 41, 73, 224, 29, 177, 8, 102, 144, 37, 22, 152, 139, 166, 189, 161, 61, 71, 70, 250, 232, 131, 64, 45, 124, 39, 176, 188, 84, 43, 227, 3, 231, 54, 46, 201, 57, 20, 255, 103, 221, 55, 123, 219, 158, 87, 17, 24, 49, 175, 111, 66, 199, 160, 241, 53, 226, 183, 213, 210, 236, 182, 136, 192, 135, 115, 117, 14, 50, 252, 129, 167, 9, 179, 162, 138, 89, 171, 60, 251, 52, 149, 165, 112, 143, 217, 4, 51, 72, 147, 11, 76, 198, 83, 223, 209, 159, 164, 35, 125, 116, 194, 32, 151, 62, 148, 88, 94, 42, 150, 242, 130, 244, 27, 23, 229, 157, 10, 256, 180, 239, 156, 190, 238, 79, 172, 137, 12, 153, 216, 184, 33, 228, 80, 249, 155, 113, 220, 235, 105, 118, 91, 68, 96, 196, 186, 187, 7, 25, 126, 193, 212, 133, 218, 81, 69, 173, 214, 30, 254, 26, 203, 211, 56, 200, 237, 2, 154, 36, 202, 134, 38, 99, 170, 240, 233, 208, 82, 146, 191, 58, 97, 16, 204, 31, 74, 44, 47, 21, 75, 121, 65, 122, 142, 140, 243, 207, 5, 128, 90, 248, 78, 95, 119, 168, 86, 197, 6, 205, 108, 92, 145, 114, 40, 253, 206, 185, 110, 246, 181, 59, 174, 34, 48, 98, 93, 222, 132, 141, 63, 225, 106, 195, 109, 169, 163, 215, 107, 15, 127, 13, 230, 234, 28, 100, 247, 1], +[1, 78, 173, 130, 117, 131, 195, 47, 68, 164, 199, 102, 246, 170, 153, 112, 255, 101, 168, 254, 23, 252, 124, 163, 121, 186, 116, 53, 22, 174, 208, 33, 4, 55, 178, 6, 211, 10, 9, 188, 15, 142, 25, 151, 213, 166, 98, 191, 249, 147, 158, 245, 92, 237, 239, 138, 227, 230, 207, 212, 88, 182, 61, 132, 16, 220, 198, 24, 73, 40, 36, 238, 60, 54, 100, 90, 81, 150, 135, 250, 225, 74, 118, 209, 111, 177, 185, 38, 137, 149, 57, 77, 95, 214, 244, 14, 64, 109, 21, 96, 35, 160, 144, 181, 240, 216, 143, 103, 67, 86, 26, 229, 129, 39, 215, 65, 187, 194, 226, 152, 34, 82, 228, 51, 123, 85, 205, 56, 256, 179, 84, 127, 140, 126, 62, 210, 189, 93, 58, 155, 11, 87, 104, 145, 2, 156, 89, 3, 234, 5, 133, 94, 136, 71, 141, 204, 235, 83, 49, 224, 253, 202, 79, 251, 46, 247, 248, 69, 242, 115, 232, 106, 44, 91, 159, 66, 8, 110, 99, 12, 165, 20, 18, 119, 30, 27, 50, 45, 169, 75, 196, 125, 241, 37, 59, 233, 184, 217, 221, 19, 197, 203, 157, 167, 176, 107, 122, 7, 32, 183, 139, 48, 146, 80, 72, 219, 120, 108, 200, 180, 162, 43, 13, 243, 193, 148, 236, 161, 222, 97, 113, 76, 17, 41, 114, 154, 190, 171, 231, 28, 128, 218, 42, 192, 70, 63, 31, 105, 223, 175, 29, 206, 134, 172, 52, 201, 1], +[1, 79, 73, 113, 189, 25, 176, 26, 255, 99, 111, 31, 136, 207, 162, 205, 4, 59, 35, 195, 242, 100, 190, 104, 249, 139, 187, 124, 30, 57, 134, 49, 16, 236, 140, 9, 197, 143, 246, 159, 225, 42, 234, 239, 120, 228, 22, 196, 64, 173, 46, 36, 17, 58, 213, 122, 129, 168, 165, 185, 223, 141, 88, 13, 256, 178, 184, 144, 68, 232, 81, 231, 2, 158, 146, 226, 121, 50, 95, 52, 253, 198, 222, 62, 15, 157, 67, 153, 8, 118, 70, 133, 227, 200, 123, 208, 241, 21, 117, 248, 60, 114, 11, 98, 32, 215, 23, 18, 137, 29, 235, 61, 193, 84, 211, 221, 240, 199, 44, 135, 128, 89, 92, 72, 34, 116, 169, 244, 1, 79, 73, 113, 189, 25, 176, 26, 255, 99, 111, 31, 136, 207, 162, 205, 4, 59, 35, 195, 242, 100, 190, 104, 249, 139, 187, 124, 30, 57, 134, 49, 16, 236, 140, 9, 197, 143, 246, 159, 225, 42, 234, 239, 120, 228, 22, 196, 64, 173, 46, 36, 17, 58, 213, 122, 129, 168, 165, 185, 223, 141, 88, 13, 256, 178, 184, 144, 68, 232, 81, 231, 2, 158, 146, 226, 121, 50, 95, 52, 253, 198, 222, 62, 15, 157, 67, 153, 8, 118, 70, 133, 227, 200, 123, 208, 241, 21, 117, 248, 60, 114, 11, 98, 32, 215, 23, 18, 137, 29, 235, 61, 193, 84, 211, 221, 240, 199, 44, 135, 128, 89, 92, 72, 34, 116, 169, 244, 1], +[1, 80, 232, 56, 111, 142, 52, 48, 242, 85, 118, 188, 134, 183, 248, 51, 225, 10, 29, 7, 46, 82, 135, 6, 223, 107, 79, 152, 81, 55, 31, 167, 253, 194, 100, 33, 70, 203, 49, 65, 60, 174, 42, 19, 235, 39, 36, 53, 128, 217, 141, 229, 73, 186, 231, 233, 136, 86, 198, 163, 190, 37, 133, 103, 16, 252, 114, 125, 234, 216, 61, 254, 17, 75, 89, 181, 88, 101, 113, 45, 2, 160, 207, 112, 222, 27, 104, 96, 227, 170, 236, 119, 11, 109, 239, 102, 193, 20, 58, 14, 92, 164, 13, 12, 189, 214, 158, 47, 162, 110, 62, 77, 249, 131, 200, 66, 140, 149, 98, 130, 120, 91, 84, 38, 213, 78, 72, 106, 256, 177, 25, 201, 146, 115, 205, 209, 15, 172, 139, 69, 123, 74, 9, 206, 32, 247, 228, 250, 211, 175, 122, 251, 34, 150, 178, 105, 176, 202, 226, 90, 4, 63, 157, 224, 187, 54, 208, 192, 197, 83, 215, 238, 22, 218, 221, 204, 129, 40, 116, 28, 184, 71, 26, 24, 121, 171, 59, 94, 67, 220, 124, 154, 241, 5, 143, 132, 23, 41, 196, 3, 240, 182, 168, 76, 169, 156, 144, 212, 255, 97, 50, 145, 35, 230, 153, 161, 30, 87, 21, 138, 246, 148, 18, 155, 64, 237, 199, 243, 165, 93, 244, 245, 68, 43, 99, 210, 95, 147, 195, 180, 8, 126, 57, 191, 117, 108, 159, 127, 137, 166, 173, 219, 44, 179, 185, 151, 1], +[1, 81, 136, 222, 249, 123, 197, 23, 64, 44, 223, 73, 2, 162, 15, 187, 241, 246, 137, 46, 128, 88, 189, 146, 4, 67, 30, 117, 225, 235, 17, 92, 256, 176, 121, 35, 8, 134, 60, 234, 193, 213, 34, 184, 255, 95, 242, 70, 16, 11, 120, 211, 129, 169, 68, 111, 253, 190, 227, 140, 32, 22, 240, 165, 1, 81, 136, 222, 249, 123, 197, 23, 64, 44, 223, 73, 2, 162, 15, 187, 241, 246, 137, 46, 128, 88, 189, 146, 4, 67, 30, 117, 225, 235, 17, 92, 256, 176, 121, 35, 8, 134, 60, 234, 193, 213, 34, 184, 255, 95, 242, 70, 16, 11, 120, 211, 129, 169, 68, 111, 253, 190, 227, 140, 32, 22, 240, 165, 1, 81, 136, 222, 249, 123, 197, 23, 64, 44, 223, 73, 2, 162, 15, 187, 241, 246, 137, 46, 128, 88, 189, 146, 4, 67, 30, 117, 225, 235, 17, 92, 256, 176, 121, 35, 8, 134, 60, 234, 193, 213, 34, 184, 255, 95, 242, 70, 16, 11, 120, 211, 129, 169, 68, 111, 253, 190, 227, 140, 32, 22, 240, 165, 1, 81, 136, 222, 249, 123, 197, 23, 64, 44, 223, 73, 2, 162, 15, 187, 241, 246, 137, 46, 128, 88, 189, 146, 4, 67, 30, 117, 225, 235, 17, 92, 256, 176, 121, 35, 8, 134, 60, 234, 193, 213, 34, 184, 255, 95, 242, 70, 16, 11, 120, 211, 129, 169, 68, 111, 253, 190, 227, 140, 32, 22, 240, 165, 1], +[1, 82, 42, 103, 222, 214, 72, 250, 197, 220, 50, 245, 44, 10, 49, 163, 2, 164, 84, 206, 187, 171, 144, 243, 137, 183, 100, 233, 88, 20, 98, 69, 4, 71, 168, 155, 117, 85, 31, 229, 17, 109, 200, 209, 176, 40, 196, 138, 8, 142, 79, 53, 234, 170, 62, 201, 34, 218, 143, 161, 95, 80, 135, 19, 16, 27, 158, 106, 211, 83, 124, 145, 68, 179, 29, 65, 190, 160, 13, 38, 32, 54, 59, 212, 165, 166, 248, 33, 136, 101, 58, 130, 123, 63, 26, 76, 64, 108, 118, 167, 73, 75, 239, 66, 15, 202, 116, 3, 246, 126, 52, 152, 128, 216, 236, 77, 146, 150, 221, 132, 30, 147, 232, 6, 235, 252, 104, 47, 256, 175, 215, 154, 35, 43, 185, 7, 60, 37, 207, 12, 213, 247, 208, 94, 255, 93, 173, 51, 70, 86, 113, 14, 120, 74, 157, 24, 169, 237, 159, 188, 253, 186, 89, 102, 140, 172, 226, 28, 240, 148, 57, 48, 81, 217, 61, 119, 249, 115, 178, 204, 23, 87, 195, 56, 223, 39, 114, 96, 162, 177, 122, 238, 241, 230, 99, 151, 46, 174, 133, 112, 189, 78, 228, 192, 67, 97, 244, 219, 225, 203, 198, 45, 92, 91, 9, 224, 121, 156, 199, 127, 134, 194, 231, 181, 193, 149, 139, 90, 184, 182, 18, 191, 242, 55, 141, 254, 11, 131, 205, 105, 129, 41, 21, 180, 111, 107, 36, 125, 227, 110, 25, 251, 22, 5, 153, 210, 1], +[1, 83, 207, 219, 187, 101, 159, 90, 17, 126, 178, 125, 95, 175, 133, 245, 32, 86, 199, 69, 73, 148, 205, 53, 30, 177, 42, 145, 213, 203, 144, 130, 253, 182, 200, 152, 23, 110, 135, 154, 189, 10, 59, 14, 134, 71, 239, 48, 129, 170, 232, 238, 222, 179, 208, 45, 137, 63, 89, 191, 176, 216, 195, 251, 16, 43, 228, 163, 165, 74, 231, 155, 15, 217, 21, 201, 235, 230, 72, 65, 255, 91, 100, 76, 140, 55, 196, 77, 223, 5, 158, 7, 67, 164, 248, 24, 193, 85, 116, 119, 111, 218, 104, 151, 197, 160, 173, 224, 88, 108, 226, 254, 8, 150, 114, 210, 211, 37, 244, 206, 136, 237, 139, 229, 246, 115, 36, 161, 256, 174, 50, 38, 70, 156, 98, 167, 240, 131, 79, 132, 162, 82, 124, 12, 225, 171, 58, 188, 184, 109, 52, 204, 227, 80, 215, 112, 44, 54, 113, 127, 4, 75, 57, 105, 234, 147, 122, 103, 68, 247, 198, 243, 123, 186, 18, 209, 128, 87, 25, 19, 35, 78, 49, 212, 120, 194, 168, 66, 81, 41, 62, 6, 241, 214, 29, 94, 92, 183, 26, 102, 242, 40, 236, 56, 22, 27, 185, 192, 2, 166, 157, 181, 117, 202, 61, 180, 34, 252, 99, 250, 190, 93, 9, 233, 64, 172, 141, 138, 146, 39, 153, 106, 60, 97, 84, 33, 169, 149, 31, 3, 249, 107, 143, 47, 46, 220, 13, 51, 121, 20, 118, 28, 11, 142, 221, 96, 1], +[1, 84, 117, 62, 68, 58, 246, 104, 255, 89, 23, 133, 121, 141, 22, 49, 4, 79, 211, 248, 15, 232, 213, 159, 249, 99, 92, 18, 227, 50, 88, 196, 16, 59, 73, 221, 60, 157, 81, 122, 225, 139, 111, 72, 137, 200, 95, 13, 64, 236, 35, 113, 240, 114, 67, 231, 129, 42, 187, 31, 34, 29, 123, 52, 256, 173, 140, 195, 189, 199, 11, 153, 2, 168, 234, 124, 136, 116, 235, 208, 253, 178, 46, 9, 242, 25, 44, 98, 8, 158, 165, 239, 30, 207, 169, 61, 241, 198, 184, 36, 197, 100, 176, 135, 32, 118, 146, 185, 120, 57, 162, 244, 193, 21, 222, 144, 17, 143, 190, 26, 128, 215, 70, 226, 223, 228, 134, 205, 1, 84, 117, 62, 68, 58, 246, 104, 255, 89, 23, 133, 121, 141, 22, 49, 4, 79, 211, 248, 15, 232, 213, 159, 249, 99, 92, 18, 227, 50, 88, 196, 16, 59, 73, 221, 60, 157, 81, 122, 225, 139, 111, 72, 137, 200, 95, 13, 64, 236, 35, 113, 240, 114, 67, 231, 129, 42, 187, 31, 34, 29, 123, 52, 256, 173, 140, 195, 189, 199, 11, 153, 2, 168, 234, 124, 136, 116, 235, 208, 253, 178, 46, 9, 242, 25, 44, 98, 8, 158, 165, 239, 30, 207, 169, 61, 241, 198, 184, 36, 197, 100, 176, 135, 32, 118, 146, 185, 120, 57, 162, 244, 193, 21, 222, 144, 17, 143, 190, 26, 128, 215, 70, 226, 223, 228, 134, 205, 1], +[1, 85, 29, 152, 70, 39, 231, 103, 17, 160, 236, 14, 162, 149, 72, 209, 32, 150, 157, 238, 184, 220, 196, 212, 30, 237, 99, 191, 44, 142, 248, 6, 253, 174, 141, 163, 234, 101, 104, 102, 189, 131, 84, 201, 123, 175, 226, 192, 129, 171, 143, 76, 35, 148, 244, 180, 137, 80, 118, 7, 81, 203, 36, 233, 16, 75, 207, 119, 92, 110, 98, 106, 15, 247, 178, 224, 22, 71, 124, 3, 255, 87, 199, 210, 117, 179, 52, 51, 223, 194, 42, 229, 190, 216, 113, 96, 193, 214, 200, 38, 146, 74, 122, 90, 197, 40, 59, 132, 169, 230, 18, 245, 8, 166, 232, 188, 46, 55, 49, 53, 136, 252, 89, 112, 11, 164, 62, 130, 256, 172, 228, 105, 187, 218, 26, 154, 240, 97, 21, 243, 95, 108, 185, 48, 225, 107, 100, 19, 73, 37, 61, 45, 227, 20, 158, 66, 213, 115, 9, 251, 4, 83, 116, 94, 23, 156, 153, 155, 68, 126, 173, 56, 134, 82, 31, 65, 128, 86, 114, 181, 222, 109, 13, 77, 120, 177, 139, 250, 176, 54, 221, 24, 241, 182, 50, 138, 165, 147, 159, 151, 242, 10, 79, 33, 235, 186, 133, 254, 2, 170, 58, 47, 140, 78, 205, 206, 34, 63, 215, 28, 67, 41, 144, 161, 64, 43, 57, 219, 111, 183, 135, 167, 60, 217, 198, 125, 88, 27, 239, 12, 249, 91, 25, 69, 211, 202, 208, 204, 121, 5, 168, 145, 246, 93, 195, 127, 1], +[1, 86, 200, 238, 165, 55, 104, 206, 240, 80, 198, 66, 22, 93, 31, 96, 32, 182, 232, 163, 140, 218, 244, 167, 227, 247, 168, 56, 190, 149, 221, 245, 253, 170, 228, 76, 111, 37, 98, 204, 68, 194, 236, 250, 169, 142, 133, 130, 129, 43, 100, 119, 211, 156, 52, 103, 120, 40, 99, 33, 11, 175, 144, 48, 16, 91, 116, 210, 70, 109, 122, 212, 242, 252, 84, 28, 95, 203, 239, 251, 255, 85, 114, 38, 184, 147, 49, 102, 34, 97, 118, 125, 213, 71, 195, 65, 193, 150, 50, 188, 234, 78, 26, 180, 60, 20, 178, 145, 134, 216, 72, 24, 8, 174, 58, 105, 35, 183, 61, 106, 121, 126, 42, 14, 176, 230, 248, 254, 256, 171, 57, 19, 92, 202, 153, 51, 17, 177, 59, 191, 235, 164, 226, 161, 225, 75, 25, 94, 117, 39, 13, 90, 30, 10, 89, 201, 67, 108, 36, 12, 4, 87, 29, 181, 146, 220, 159, 53, 189, 63, 21, 7, 88, 115, 124, 127, 128, 214, 157, 138, 46, 101, 205, 154, 137, 217, 158, 224, 246, 82, 113, 209, 241, 166, 141, 47, 187, 148, 135, 45, 15, 5, 173, 229, 162, 54, 18, 6, 2, 172, 143, 219, 73, 110, 208, 155, 223, 160, 139, 132, 44, 186, 62, 192, 64, 107, 207, 69, 23, 179, 231, 77, 197, 237, 79, 112, 123, 41, 185, 233, 249, 83, 199, 152, 222, 74, 196, 151, 136, 131, 215, 243, 81, 27, 9, 3, 1], +[1, 87, 116, 69, 92, 37, 135, 180, 240, 63, 84, 112, 235, 142, 18, 24, 32, 214, 114, 152, 117, 156, 208, 106, 227, 217, 118, 243, 67, 175, 62, 254, 253, 166, 50, 238, 146, 109, 231, 51, 68, 5, 178, 66, 88, 203, 185, 161, 129, 172, 58, 163, 46, 147, 196, 90, 120, 160, 42, 56, 246, 71, 9, 12, 16, 107, 57, 76, 187, 78, 104, 53, 242, 237, 59, 250, 162, 216, 31, 127, 255, 83, 25, 119, 73, 183, 244, 154, 34, 131, 89, 33, 44, 230, 221, 209, 193, 86, 29, 210, 23, 202, 98, 45, 60, 80, 21, 28, 123, 164, 133, 6, 8, 182, 157, 38, 222, 39, 52, 155, 121, 247, 158, 125, 81, 108, 144, 192, 256, 170, 141, 188, 165, 220, 122, 77, 17, 194, 173, 145, 22, 115, 239, 233, 225, 43, 143, 105, 140, 101, 49, 151, 30, 40, 139, 14, 190, 82, 195, 3, 4, 91, 207, 19, 111, 148, 26, 206, 189, 252, 79, 191, 169, 54, 72, 96, 128, 85, 199, 94, 211, 110, 61, 167, 137, 97, 215, 201, 11, 186, 248, 245, 241, 150, 200, 181, 70, 179, 153, 204, 15, 20, 198, 7, 95, 41, 226, 130, 2, 174, 232, 138, 184, 74, 13, 103, 223, 126, 168, 224, 213, 27, 36, 48, 64, 171, 228, 47, 234, 55, 159, 212, 197, 177, 236, 229, 134, 93, 124, 251, 249, 75, 100, 219, 35, 218, 205, 102, 136, 10, 99, 132, 176, 149, 113, 65, 1], +[1, 88, 34, 165, 128, 213, 240, 46, 193, 22, 137, 234, 32, 246, 60, 140, 241, 134, 227, 187, 8, 190, 15, 35, 253, 162, 121, 111, 2, 176, 68, 73, 256, 169, 223, 92, 129, 44, 17, 211, 64, 235, 120, 23, 225, 11, 197, 117, 16, 123, 30, 70, 249, 67, 242, 222, 4, 95, 136, 146, 255, 81, 189, 184, 1, 88, 34, 165, 128, 213, 240, 46, 193, 22, 137, 234, 32, 246, 60, 140, 241, 134, 227, 187, 8, 190, 15, 35, 253, 162, 121, 111, 2, 176, 68, 73, 256, 169, 223, 92, 129, 44, 17, 211, 64, 235, 120, 23, 225, 11, 197, 117, 16, 123, 30, 70, 249, 67, 242, 222, 4, 95, 136, 146, 255, 81, 189, 184, 1, 88, 34, 165, 128, 213, 240, 46, 193, 22, 137, 234, 32, 246, 60, 140, 241, 134, 227, 187, 8, 190, 15, 35, 253, 162, 121, 111, 2, 176, 68, 73, 256, 169, 223, 92, 129, 44, 17, 211, 64, 235, 120, 23, 225, 11, 197, 117, 16, 123, 30, 70, 249, 67, 242, 222, 4, 95, 136, 146, 255, 81, 189, 184, 1, 88, 34, 165, 128, 213, 240, 46, 193, 22, 137, 234, 32, 246, 60, 140, 241, 134, 227, 187, 8, 190, 15, 35, 253, 162, 121, 111, 2, 176, 68, 73, 256, 169, 223, 92, 129, 44, 17, 211, 64, 235, 120, 23, 225, 11, 197, 117, 16, 123, 30, 70, 249, 67, 242, 222, 4, 95, 136, 146, 255, 81, 189, 184, 1], +[1, 89, 211, 18, 60, 200, 67, 52, 2, 178, 165, 36, 120, 143, 134, 104, 4, 99, 73, 72, 240, 29, 11, 208, 8, 198, 146, 144, 223, 58, 22, 159, 16, 139, 35, 31, 189, 116, 44, 61, 32, 21, 70, 62, 121, 232, 88, 122, 64, 42, 140, 124, 242, 207, 176, 244, 128, 84, 23, 248, 227, 157, 95, 231, 256, 168, 46, 239, 197, 57, 190, 205, 255, 79, 92, 221, 137, 114, 123, 153, 253, 158, 184, 185, 17, 228, 246, 49, 249, 59, 111, 113, 34, 199, 235, 98, 241, 118, 222, 226, 68, 141, 213, 196, 225, 236, 187, 195, 136, 25, 169, 135, 193, 215, 117, 133, 15, 50, 81, 13, 129, 173, 234, 9, 30, 100, 162, 26, 1, 89, 211, 18, 60, 200, 67, 52, 2, 178, 165, 36, 120, 143, 134, 104, 4, 99, 73, 72, 240, 29, 11, 208, 8, 198, 146, 144, 223, 58, 22, 159, 16, 139, 35, 31, 189, 116, 44, 61, 32, 21, 70, 62, 121, 232, 88, 122, 64, 42, 140, 124, 242, 207, 176, 244, 128, 84, 23, 248, 227, 157, 95, 231, 256, 168, 46, 239, 197, 57, 190, 205, 255, 79, 92, 221, 137, 114, 123, 153, 253, 158, 184, 185, 17, 228, 246, 49, 249, 59, 111, 113, 34, 199, 235, 98, 241, 118, 222, 226, 68, 141, 213, 196, 225, 236, 187, 195, 136, 25, 169, 135, 193, 215, 117, 133, 15, 50, 81, 13, 129, 173, 234, 9, 30, 100, 162, 26, 1], +[1, 90, 133, 148, 213, 152, 59, 170, 137, 251, 231, 230, 140, 7, 116, 160, 8, 206, 36, 156, 162, 188, 215, 75, 68, 209, 49, 41, 92, 56, 157, 252, 64, 106, 31, 220, 11, 219, 178, 86, 30, 130, 135, 71, 222, 191, 228, 217, 255, 77, 248, 218, 88, 210, 139, 174, 240, 12, 52, 54, 234, 243, 25, 194, 241, 102, 185, 202, 190, 138, 84, 107, 121, 96, 159, 175, 73, 145, 200, 10, 129, 45, 195, 74, 235, 76, 158, 85, 197, 254, 244, 115, 70, 132, 58, 80, 4, 103, 18, 78, 81, 94, 236, 166, 34, 233, 153, 149, 46, 28, 207, 126, 32, 53, 144, 110, 134, 238, 89, 43, 15, 65, 196, 164, 111, 224, 114, 237, 256, 167, 124, 109, 44, 105, 198, 87, 120, 6, 26, 27, 117, 250, 141, 97, 249, 51, 221, 101, 95, 69, 42, 182, 189, 48, 208, 216, 165, 201, 100, 5, 193, 151, 226, 37, 246, 38, 79, 171, 227, 127, 122, 186, 35, 66, 29, 40, 2, 180, 9, 39, 169, 47, 118, 83, 17, 245, 205, 203, 23, 14, 232, 63, 16, 155, 72, 55, 67, 119, 173, 150, 136, 161, 98, 82, 184, 112, 57, 247, 128, 212, 62, 183, 22, 181, 99, 172, 60, 3, 13, 142, 187, 125, 199, 177, 253, 154, 239, 179, 176, 163, 21, 91, 223, 24, 104, 108, 211, 229, 50, 131, 225, 204, 113, 147, 123, 19, 168, 214, 242, 192, 61, 93, 146, 33, 143, 20, 1], +[1, 91, 57, 47, 165, 109, 153, 45, 240, 252, 59, 229, 22, 203, 226, 6, 32, 85, 25, 219, 140, 147, 13, 155, 227, 97, 89, 132, 190, 71, 36, 192, 253, 150, 29, 69, 111, 78, 159, 77, 68, 20, 21, 112, 169, 216, 124, 233, 129, 174, 157, 152, 211, 183, 205, 151, 120, 126, 158, 243, 11, 230, 113, 3, 16, 171, 141, 238, 70, 202, 135, 206, 242, 177, 173, 66, 95, 164, 18, 96, 255, 75, 143, 163, 184, 39, 208, 167, 34, 10, 139, 56, 213, 108, 62, 245, 193, 87, 207, 76, 234, 220, 231, 204, 60, 63, 79, 250, 134, 115, 185, 130, 8, 214, 199, 119, 35, 101, 196, 103, 121, 217, 215, 33, 176, 82, 9, 48, 256, 166, 200, 210, 92, 148, 104, 212, 17, 5, 198, 28, 235, 54, 31, 251, 225, 172, 232, 38, 117, 110, 244, 102, 30, 160, 168, 125, 67, 186, 221, 65, 4, 107, 228, 188, 146, 179, 98, 180, 189, 237, 236, 145, 88, 41, 133, 24, 128, 83, 100, 105, 46, 74, 52, 106, 137, 131, 99, 14, 246, 27, 144, 254, 241, 86, 116, 19, 187, 55, 122, 51, 15, 80, 84, 191, 162, 93, 239, 161, 2, 182, 114, 94, 73, 218, 49, 90, 223, 247, 118, 201, 44, 149, 195, 12, 64, 170, 50, 181, 23, 37, 26, 53, 197, 194, 178, 7, 123, 142, 72, 127, 249, 43, 58, 138, 222, 156, 61, 154, 136, 40, 42, 224, 81, 175, 248, 209, 1], +[1, 92, 240, 235, 32, 117, 227, 67, 253, 146, 68, 88, 129, 46, 120, 246, 16, 187, 242, 162, 255, 73, 34, 44, 193, 23, 60, 123, 8, 222, 121, 81, 256, 165, 17, 22, 225, 140, 30, 190, 4, 111, 189, 169, 128, 211, 137, 11, 241, 70, 15, 95, 2, 184, 223, 213, 64, 234, 197, 134, 249, 35, 136, 176, 1, 92, 240, 235, 32, 117, 227, 67, 253, 146, 68, 88, 129, 46, 120, 246, 16, 187, 242, 162, 255, 73, 34, 44, 193, 23, 60, 123, 8, 222, 121, 81, 256, 165, 17, 22, 225, 140, 30, 190, 4, 111, 189, 169, 128, 211, 137, 11, 241, 70, 15, 95, 2, 184, 223, 213, 64, 234, 197, 134, 249, 35, 136, 176, 1, 92, 240, 235, 32, 117, 227, 67, 253, 146, 68, 88, 129, 46, 120, 246, 16, 187, 242, 162, 255, 73, 34, 44, 193, 23, 60, 123, 8, 222, 121, 81, 256, 165, 17, 22, 225, 140, 30, 190, 4, 111, 189, 169, 128, 211, 137, 11, 241, 70, 15, 95, 2, 184, 223, 213, 64, 234, 197, 134, 249, 35, 136, 176, 1, 92, 240, 235, 32, 117, 227, 67, 253, 146, 68, 88, 129, 46, 120, 246, 16, 187, 242, 162, 255, 73, 34, 44, 193, 23, 60, 123, 8, 222, 121, 81, 256, 165, 17, 22, 225, 140, 30, 190, 4, 111, 189, 169, 128, 211, 137, 11, 241, 70, 15, 95, 2, 184, 223, 213, 64, 234, 197, 134, 249, 35, 136, 176, 1], +[1, 93, 168, 204, 211, 91, 239, 125, 60, 183, 57, 161, 67, 63, 205, 47, 2, 186, 79, 151, 165, 182, 221, 250, 120, 109, 114, 65, 134, 126, 153, 94, 4, 115, 158, 45, 73, 107, 185, 243, 240, 218, 228, 130, 11, 252, 49, 188, 8, 230, 59, 90, 146, 214, 113, 229, 223, 179, 199, 3, 22, 247, 98, 119, 16, 203, 118, 180, 35, 171, 226, 201, 189, 101, 141, 6, 44, 237, 196, 238, 32, 149, 236, 103, 70, 85, 195, 145, 121, 202, 25, 12, 88, 217, 135, 219, 64, 41, 215, 206, 140, 170, 133, 33, 242, 147, 50, 24, 176, 177, 13, 181, 128, 82, 173, 155, 23, 83, 9, 66, 227, 37, 100, 48, 95, 97, 26, 105, 256, 164, 89, 53, 46, 166, 18, 132, 197, 74, 200, 96, 190, 194, 52, 210, 255, 71, 178, 106, 92, 75, 36, 7, 137, 148, 143, 192, 123, 131, 104, 163, 253, 142, 99, 212, 184, 150, 72, 14, 17, 39, 29, 127, 246, 5, 208, 69, 249, 27, 198, 167, 111, 43, 144, 28, 34, 78, 58, 254, 235, 10, 159, 138, 241, 54, 139, 77, 222, 86, 31, 56, 68, 156, 116, 251, 213, 20, 61, 19, 225, 108, 21, 154, 187, 172, 62, 112, 136, 55, 232, 245, 169, 40, 122, 38, 193, 216, 42, 51, 117, 87, 124, 224, 15, 110, 207, 233, 81, 80, 244, 76, 129, 175, 84, 102, 234, 174, 248, 191, 30, 220, 157, 209, 162, 160, 231, 152, 1], +[1, 94, 98, 217, 95, 192, 58, 55, 30, 250, 113, 85, 23, 106, 198, 108, 129, 47, 49, 237, 176, 96, 29, 156, 15, 125, 185, 171, 140, 53, 99, 54, 193, 152, 153, 247, 88, 48, 143, 78, 136, 191, 221, 214, 70, 155, 178, 27, 225, 76, 205, 252, 44, 24, 200, 39, 68, 224, 239, 107, 35, 206, 89, 142, 241, 38, 231, 126, 22, 12, 100, 148, 34, 112, 248, 182, 146, 103, 173, 71, 249, 19, 244, 63, 11, 6, 50, 74, 17, 56, 124, 91, 73, 180, 215, 164, 253, 138, 122, 160, 134, 3, 25, 37, 137, 28, 62, 174, 165, 90, 236, 82, 255, 69, 61, 80, 67, 130, 141, 147, 197, 14, 31, 87, 211, 45, 118, 41, 256, 163, 159, 40, 162, 65, 199, 202, 227, 7, 144, 172, 234, 151, 59, 149, 128, 210, 208, 20, 81, 161, 228, 101, 242, 132, 72, 86, 117, 204, 158, 203, 64, 105, 104, 10, 169, 209, 114, 179, 121, 66, 36, 43, 187, 102, 79, 230, 32, 181, 52, 5, 213, 233, 57, 218, 189, 33, 18, 150, 222, 51, 168, 115, 16, 219, 26, 131, 235, 245, 157, 109, 223, 145, 9, 75, 111, 154, 84, 186, 8, 238, 13, 194, 246, 251, 207, 183, 240, 201, 133, 166, 184, 77, 42, 93, 4, 119, 135, 97, 123, 254, 232, 220, 120, 229, 195, 83, 92, 167, 21, 175, 2, 188, 196, 177, 190, 127, 116, 110, 60, 243, 226, 170, 46, 212, 139, 216, 1], +[1, 95, 30, 23, 129, 176, 15, 140, 193, 88, 136, 70, 225, 44, 68, 35, 241, 22, 34, 146, 249, 11, 17, 73, 253, 134, 137, 165, 255, 67, 197, 211, 256, 162, 227, 234, 128, 81, 242, 117, 64, 169, 121, 187, 32, 213, 189, 222, 16, 235, 223, 111, 8, 246, 240, 184, 4, 123, 120, 92, 2, 190, 60, 46, 1, 95, 30, 23, 129, 176, 15, 140, 193, 88, 136, 70, 225, 44, 68, 35, 241, 22, 34, 146, 249, 11, 17, 73, 253, 134, 137, 165, 255, 67, 197, 211, 256, 162, 227, 234, 128, 81, 242, 117, 64, 169, 121, 187, 32, 213, 189, 222, 16, 235, 223, 111, 8, 246, 240, 184, 4, 123, 120, 92, 2, 190, 60, 46, 1, 95, 30, 23, 129, 176, 15, 140, 193, 88, 136, 70, 225, 44, 68, 35, 241, 22, 34, 146, 249, 11, 17, 73, 253, 134, 137, 165, 255, 67, 197, 211, 256, 162, 227, 234, 128, 81, 242, 117, 64, 169, 121, 187, 32, 213, 189, 222, 16, 235, 223, 111, 8, 246, 240, 184, 4, 123, 120, 92, 2, 190, 60, 46, 1, 95, 30, 23, 129, 176, 15, 140, 193, 88, 136, 70, 225, 44, 68, 35, 241, 22, 34, 146, 249, 11, 17, 73, 253, 134, 137, 165, 255, 67, 197, 211, 256, 162, 227, 234, 128, 81, 242, 117, 64, 169, 121, 187, 32, 213, 189, 222, 16, 235, 223, 111, 8, 246, 240, 184, 4, 123, 120, 92, 2, 190, 60, 46, 1], +[1, 96, 221, 142, 11, 28, 118, 20, 121, 51, 13, 220, 46, 47, 143, 107, 249, 3, 31, 149, 169, 33, 84, 97, 60, 106, 153, 39, 146, 138, 141, 172, 64, 233, 9, 93, 190, 250, 99, 252, 34, 180, 61, 202, 117, 181, 157, 166, 2, 192, 185, 27, 22, 56, 236, 40, 242, 102, 26, 183, 92, 94, 29, 214, 241, 6, 62, 41, 81, 66, 168, 194, 120, 212, 49, 78, 35, 19, 25, 87, 128, 209, 18, 186, 123, 243, 198, 247, 68, 103, 122, 147, 234, 105, 57, 75, 4, 127, 113, 54, 44, 112, 215, 80, 227, 204, 52, 109, 184, 188, 58, 171, 225, 12, 124, 82, 162, 132, 79, 131, 240, 167, 98, 156, 70, 38, 50, 174, 256, 161, 36, 115, 246, 229, 139, 237, 136, 206, 244, 37, 211, 210, 114, 150, 8, 254, 226, 108, 88, 224, 173, 160, 197, 151, 104, 218, 111, 119, 116, 85, 193, 24, 248, 164, 67, 7, 158, 5, 223, 77, 196, 55, 140, 76, 100, 91, 255, 65, 72, 230, 235, 201, 21, 217, 15, 155, 231, 74, 165, 163, 228, 43, 16, 251, 195, 216, 176, 191, 89, 63, 137, 45, 208, 179, 222, 238, 232, 170, 129, 48, 239, 71, 134, 14, 59, 10, 189, 154, 135, 110, 23, 152, 200, 182, 253, 130, 144, 203, 213, 145, 42, 177, 30, 53, 205, 148, 73, 69, 199, 86, 32, 245, 133, 175, 95, 125, 178, 126, 17, 90, 159, 101, 187, 219, 207, 83, 1], +[1, 97, 157, 66, 234, 82, 244, 24, 15, 170, 42, 219, 169, 202, 62, 103, 225, 237, 116, 201, 222, 203, 159, 3, 34, 214, 198, 188, 246, 218, 72, 45, 253, 126, 143, 250, 92, 186, 52, 161, 197, 91, 89, 152, 95, 220, 9, 102, 128, 80, 50, 224, 140, 216, 135, 245, 121, 172, 236, 19, 44, 156, 226, 77, 16, 10, 199, 28, 146, 27, 49, 127, 240, 150, 158, 163, 134, 148, 221, 106, 2, 194, 57, 132, 211, 164, 231, 48, 30, 83, 84, 181, 81, 147, 124, 206, 193, 217, 232, 145, 187, 149, 61, 6, 68, 171, 139, 119, 235, 179, 144, 90, 249, 252, 29, 243, 184, 115, 104, 65, 137, 182, 178, 47, 190, 183, 18, 204, 256, 160, 100, 191, 23, 175, 13, 233, 242, 87, 215, 38, 88, 55, 195, 154, 32, 20, 141, 56, 35, 54, 98, 254, 223, 43, 59, 69, 11, 39, 185, 212, 4, 131, 114, 7, 165, 71, 205, 96, 60, 166, 168, 105, 162, 37, 248, 155, 129, 177, 207, 33, 117, 41, 122, 12, 136, 85, 21, 238, 213, 101, 31, 180, 241, 247, 58, 229, 111, 230, 208, 130, 17, 107, 99, 94, 123, 109, 36, 151, 255, 63, 200, 125, 46, 93, 26, 209, 227, 174, 173, 76, 176, 110, 133, 51, 64, 40, 25, 112, 70, 108, 196, 251, 189, 86, 118, 138, 22, 78, 113, 167, 8, 5, 228, 14, 73, 142, 153, 192, 120, 75, 79, 210, 67, 74, 239, 53, 1], +[1, 98, 95, 58, 30, 113, 23, 198, 129, 49, 176, 29, 15, 185, 140, 99, 193, 153, 88, 143, 136, 221, 70, 178, 225, 205, 44, 200, 68, 239, 35, 89, 241, 231, 22, 100, 34, 248, 146, 173, 249, 244, 11, 50, 17, 124, 73, 215, 253, 122, 134, 25, 137, 62, 165, 236, 255, 61, 67, 141, 197, 31, 211, 118, 256, 159, 162, 199, 227, 144, 234, 59, 128, 208, 81, 228, 242, 72, 117, 158, 64, 104, 169, 114, 121, 36, 187, 79, 32, 52, 213, 57, 189, 18, 222, 168, 16, 26, 235, 157, 223, 9, 111, 84, 8, 13, 246, 207, 240, 133, 184, 42, 4, 135, 123, 232, 120, 195, 92, 21, 2, 196, 190, 116, 60, 226, 46, 139, 1, 98, 95, 58, 30, 113, 23, 198, 129, 49, 176, 29, 15, 185, 140, 99, 193, 153, 88, 143, 136, 221, 70, 178, 225, 205, 44, 200, 68, 239, 35, 89, 241, 231, 22, 100, 34, 248, 146, 173, 249, 244, 11, 50, 17, 124, 73, 215, 253, 122, 134, 25, 137, 62, 165, 236, 255, 61, 67, 141, 197, 31, 211, 118, 256, 159, 162, 199, 227, 144, 234, 59, 128, 208, 81, 228, 242, 72, 117, 158, 64, 104, 169, 114, 121, 36, 187, 79, 32, 52, 213, 57, 189, 18, 222, 168, 16, 26, 235, 157, 223, 9, 111, 84, 8, 13, 246, 207, 240, 133, 184, 42, 4, 135, 123, 232, 120, 195, 92, 21, 2, 196, 190, 116, 60, 226, 46, 139, 1], +[1, 99, 35, 124, 197, 228, 213, 13, 2, 198, 70, 248, 137, 199, 169, 26, 4, 139, 140, 239, 17, 141, 81, 52, 8, 21, 23, 221, 34, 25, 162, 104, 16, 42, 46, 185, 68, 50, 67, 208, 32, 84, 92, 113, 136, 100, 134, 159, 64, 168, 184, 226, 15, 200, 11, 61, 128, 79, 111, 195, 30, 143, 22, 122, 256, 158, 222, 133, 60, 29, 44, 244, 255, 59, 187, 9, 120, 58, 88, 231, 253, 118, 117, 18, 240, 116, 176, 205, 249, 236, 234, 36, 223, 232, 95, 153, 241, 215, 211, 72, 189, 207, 190, 49, 225, 173, 165, 144, 121, 157, 123, 98, 193, 89, 73, 31, 242, 57, 246, 196, 129, 178, 146, 62, 227, 114, 235, 135, 1, 99, 35, 124, 197, 228, 213, 13, 2, 198, 70, 248, 137, 199, 169, 26, 4, 139, 140, 239, 17, 141, 81, 52, 8, 21, 23, 221, 34, 25, 162, 104, 16, 42, 46, 185, 68, 50, 67, 208, 32, 84, 92, 113, 136, 100, 134, 159, 64, 168, 184, 226, 15, 200, 11, 61, 128, 79, 111, 195, 30, 143, 22, 122, 256, 158, 222, 133, 60, 29, 44, 244, 255, 59, 187, 9, 120, 58, 88, 231, 253, 118, 117, 18, 240, 116, 176, 205, 249, 236, 234, 36, 223, 232, 95, 153, 241, 215, 211, 72, 189, 207, 190, 49, 225, 173, 165, 144, 121, 157, 123, 98, 193, 89, 73, 31, 242, 57, 246, 196, 129, 178, 146, 62, 227, 114, 235, 135, 1], +[1, 100, 234, 13, 15, 215, 169, 195, 225, 141, 222, 98, 34, 59, 246, 185, 253, 114, 92, 205, 197, 168, 95, 248, 128, 207, 140, 122, 121, 21, 44, 31, 16, 58, 146, 208, 240, 99, 134, 36, 2, 200, 211, 26, 30, 173, 81, 133, 193, 25, 187, 196, 68, 118, 235, 113, 249, 228, 184, 153, 137, 79, 190, 239, 256, 157, 23, 244, 242, 42, 88, 62, 32, 116, 35, 159, 223, 198, 11, 72, 4, 143, 165, 52, 60, 89, 162, 9, 129, 50, 117, 135, 136, 236, 213, 226, 241, 199, 111, 49, 17, 158, 123, 221, 255, 57, 46, 231, 227, 84, 176, 124, 64, 232, 70, 61, 189, 139, 22, 144, 8, 29, 73, 104, 120, 178, 67, 18, 1, 100, 234, 13, 15, 215, 169, 195, 225, 141, 222, 98, 34, 59, 246, 185, 253, 114, 92, 205, 197, 168, 95, 248, 128, 207, 140, 122, 121, 21, 44, 31, 16, 58, 146, 208, 240, 99, 134, 36, 2, 200, 211, 26, 30, 173, 81, 133, 193, 25, 187, 196, 68, 118, 235, 113, 249, 228, 184, 153, 137, 79, 190, 239, 256, 157, 23, 244, 242, 42, 88, 62, 32, 116, 35, 159, 223, 198, 11, 72, 4, 143, 165, 52, 60, 89, 162, 9, 129, 50, 117, 135, 136, 236, 213, 226, 241, 199, 111, 49, 17, 158, 123, 221, 255, 57, 46, 231, 227, 84, 176, 124, 64, 232, 70, 61, 189, 139, 22, 144, 8, 29, 73, 104, 120, 178, 67, 18, 1], +[1, 101, 178, 245, 73, 177, 144, 152, 189, 71, 232, 45, 176, 43, 231, 201, 255, 55, 158, 24, 111, 160, 226, 210, 136, 115, 50, 167, 162, 171, 52, 112, 4, 147, 198, 209, 35, 194, 62, 94, 242, 27, 157, 180, 190, 172, 153, 33, 249, 220, 118, 96, 187, 126, 133, 69, 30, 203, 200, 154, 134, 170, 208, 191, 16, 74, 21, 65, 140, 5, 248, 119, 197, 108, 114, 206, 246, 174, 98, 132, 225, 109, 215, 127, 234, 247, 18, 19, 120, 41, 29, 102, 22, 166, 61, 250, 64, 39, 84, 3, 46, 20, 221, 219, 17, 175, 199, 53, 213, 182, 135, 14, 129, 179, 89, 251, 165, 217, 72, 76, 223, 164, 116, 151, 88, 150, 244, 229, 256, 156, 79, 12, 184, 80, 113, 105, 68, 186, 25, 212, 81, 214, 26, 56, 2, 202, 99, 233, 146, 97, 31, 47, 121, 142, 207, 90, 95, 86, 205, 145, 253, 110, 59, 48, 222, 63, 195, 163, 15, 230, 100, 77, 67, 85, 104, 224, 8, 37, 139, 161, 70, 131, 124, 188, 227, 54, 57, 103, 123, 87, 49, 66, 241, 183, 236, 192, 117, 252, 9, 138, 60, 149, 143, 51, 11, 83, 159, 125, 32, 148, 42, 130, 23, 10, 239, 238, 137, 216, 228, 155, 235, 91, 196, 7, 193, 218, 173, 254, 211, 237, 36, 38, 240, 82, 58, 204, 44, 75, 122, 243, 128, 78, 168, 6, 92, 40, 185, 181, 34, 93, 141, 106, 169, 107, 13, 28, 1], +[1, 102, 124, 55, 213, 138, 198, 150, 137, 96, 26, 82, 140, 145, 141, 247, 8, 45, 221, 183, 162, 76, 42, 172, 68, 254, 208, 142, 92, 132, 100, 177, 64, 103, 226, 179, 11, 94, 79, 91, 30, 233, 122, 108, 222, 28, 29, 131, 255, 53, 9, 147, 88, 238, 118, 214, 240, 65, 205, 93, 234, 224, 232, 20, 241, 167, 72, 148, 190, 105, 173, 170, 121, 6, 98, 230, 73, 250, 57, 160, 129, 51, 62, 156, 235, 69, 99, 75, 197, 48, 13, 41, 70, 201, 199, 252, 4, 151, 239, 220, 81, 38, 21, 86, 34, 127, 104, 71, 46, 66, 50, 217, 32, 180, 113, 218, 134, 47, 168, 174, 15, 245, 61, 54, 111, 14, 143, 194, 256, 155, 133, 202, 44, 119, 59, 107, 120, 161, 231, 175, 117, 112, 116, 10, 249, 212, 36, 74, 95, 181, 215, 85, 189, 3, 49, 115, 165, 125, 157, 80, 193, 154, 31, 78, 246, 163, 178, 166, 227, 24, 135, 149, 35, 229, 228, 126, 2, 204, 248, 110, 169, 19, 139, 43, 17, 192, 52, 164, 23, 33, 25, 237, 16, 90, 185, 109, 67, 152, 84, 87, 136, 251, 159, 27, 184, 7, 200, 97, 128, 206, 195, 101, 22, 188, 158, 182, 60, 209, 244, 216, 187, 56, 58, 5, 253, 106, 18, 37, 176, 219, 236, 171, 223, 130, 153, 186, 211, 191, 207, 40, 225, 77, 144, 39, 123, 210, 89, 83, 242, 12, 196, 203, 146, 243, 114, 63, 1], +[1, 103, 72, 220, 44, 163, 84, 171, 137, 233, 98, 71, 117, 229, 200, 40, 8, 53, 62, 218, 95, 19, 158, 83, 68, 65, 13, 54, 165, 33, 58, 63, 64, 167, 239, 202, 246, 152, 236, 150, 30, 6, 104, 175, 35, 7, 207, 247, 255, 51, 113, 74, 169, 188, 89, 172, 240, 48, 61, 115, 23, 56, 114, 177, 241, 151, 133, 78, 67, 219, 198, 91, 121, 127, 231, 149, 184, 191, 141, 131, 129, 180, 36, 110, 22, 210, 42, 214, 197, 245, 49, 164, 187, 243, 100, 20, 4, 155, 31, 109, 176, 138, 79, 170, 34, 161, 135, 27, 211, 145, 29, 160, 32, 212, 248, 101, 123, 76, 118, 75, 15, 3, 52, 216, 146, 132, 232, 252, 256, 154, 185, 37, 213, 94, 173, 86, 120, 24, 159, 186, 140, 28, 57, 217, 249, 204, 195, 39, 162, 238, 99, 174, 189, 192, 244, 203, 92, 224, 199, 194, 193, 90, 18, 55, 11, 105, 21, 107, 227, 251, 153, 82, 222, 250, 50, 10, 2, 206, 144, 183, 88, 69, 168, 85, 17, 209, 196, 142, 234, 201, 143, 80, 16, 106, 124, 179, 190, 38, 59, 166, 136, 130, 26, 108, 73, 66, 116, 126, 128, 77, 221, 147, 235, 47, 215, 43, 60, 12, 208, 93, 70, 14, 157, 237, 253, 102, 226, 148, 81, 119, 178, 87, 223, 96, 122, 230, 46, 112, 228, 97, 225, 45, 9, 156, 134, 181, 139, 182, 242, 254, 205, 41, 111, 125, 25, 5, 1], +[1, 104, 22, 232, 227, 221, 111, 236, 129, 52, 11, 116, 242, 239, 184, 118, 193, 26, 134, 58, 121, 248, 92, 59, 225, 13, 67, 29, 189, 124, 46, 158, 241, 135, 162, 143, 223, 62, 23, 79, 249, 196, 81, 200, 240, 31, 140, 168, 253, 98, 169, 100, 120, 144, 70, 84, 255, 49, 213, 50, 60, 72, 35, 42, 256, 153, 235, 25, 30, 36, 146, 21, 128, 205, 246, 141, 15, 18, 73, 139, 64, 231, 123, 199, 136, 9, 165, 198, 32, 244, 190, 228, 68, 133, 211, 99, 16, 122, 95, 114, 34, 195, 234, 178, 8, 61, 176, 57, 17, 226, 117, 89, 4, 159, 88, 157, 137, 113, 187, 173, 2, 208, 44, 207, 197, 185, 222, 215, 1, 104, 22, 232, 227, 221, 111, 236, 129, 52, 11, 116, 242, 239, 184, 118, 193, 26, 134, 58, 121, 248, 92, 59, 225, 13, 67, 29, 189, 124, 46, 158, 241, 135, 162, 143, 223, 62, 23, 79, 249, 196, 81, 200, 240, 31, 140, 168, 253, 98, 169, 100, 120, 144, 70, 84, 255, 49, 213, 50, 60, 72, 35, 42, 256, 153, 235, 25, 30, 36, 146, 21, 128, 205, 246, 141, 15, 18, 73, 139, 64, 231, 123, 199, 136, 9, 165, 198, 32, 244, 190, 228, 68, 133, 211, 99, 16, 122, 95, 114, 34, 195, 234, 178, 8, 61, 176, 57, 17, 226, 117, 89, 4, 159, 88, 157, 137, 113, 187, 173, 2, 208, 44, 207, 197, 185, 222, 215, 1], +[1, 105, 231, 97, 162, 48, 157, 37, 30, 66, 248, 83, 234, 155, 84, 82, 129, 181, 244, 177, 81, 24, 207, 147, 15, 33, 124, 170, 117, 206, 42, 41, 193, 219, 122, 217, 169, 12, 232, 202, 136, 145, 62, 85, 187, 103, 21, 149, 225, 238, 61, 237, 213, 6, 116, 101, 68, 201, 31, 171, 222, 180, 139, 203, 241, 119, 159, 247, 235, 3, 58, 179, 34, 229, 144, 214, 111, 90, 198, 230, 249, 188, 208, 252, 246, 130, 29, 218, 17, 243, 72, 107, 184, 45, 99, 115, 253, 94, 104, 126, 123, 65, 143, 109, 137, 250, 36, 182, 92, 151, 178, 186, 255, 47, 52, 63, 190, 161, 200, 183, 197, 125, 18, 91, 46, 204, 89, 93, 256, 152, 26, 160, 95, 209, 100, 220, 227, 191, 9, 174, 23, 102, 173, 175, 128, 76, 13, 80, 176, 233, 50, 110, 242, 224, 133, 87, 140, 51, 215, 216, 64, 38, 135, 40, 88, 245, 25, 55, 121, 112, 195, 172, 70, 154, 236, 108, 32, 19, 196, 20, 44, 251, 141, 156, 189, 56, 226, 86, 35, 77, 118, 54, 16, 138, 98, 10, 22, 254, 199, 78, 223, 28, 113, 43, 146, 167, 59, 27, 8, 69, 49, 5, 11, 127, 228, 39, 240, 14, 185, 150, 73, 212, 158, 142, 4, 163, 153, 131, 134, 192, 114, 148, 120, 7, 221, 75, 165, 106, 79, 71, 2, 210, 205, 194, 67, 96, 57, 74, 60, 132, 239, 166, 211, 53, 168, 164, 1], +[1, 106, 185, 78, 44, 38, 173, 91, 137, 130, 159, 149, 117, 66, 57, 131, 8, 77, 195, 110, 95, 47, 99, 214, 68, 12, 244, 164, 165, 14, 199, 20, 64, 102, 18, 109, 246, 119, 21, 170, 30, 96, 153, 27, 35, 112, 50, 160, 255, 45, 144, 101, 169, 181, 168, 75, 240, 254, 196, 216, 23, 125, 143, 252, 241, 103, 124, 37, 67, 163, 59, 86, 121, 233, 26, 186, 184, 229, 116, 217, 129, 53, 221, 39, 22, 19, 215, 174, 197, 65, 208, 203, 187, 33, 157, 194, 4, 167, 226, 55, 176, 152, 178, 107, 34, 6, 122, 82, 211, 7, 228, 10, 32, 51, 9, 183, 123, 188, 139, 85, 15, 48, 205, 142, 146, 56, 25, 80, 256, 151, 72, 179, 213, 219, 84, 166, 120, 127, 98, 108, 140, 191, 200, 126, 249, 180, 62, 147, 162, 210, 158, 43, 189, 245, 13, 93, 92, 243, 58, 237, 193, 155, 239, 148, 11, 138, 236, 87, 227, 161, 104, 230, 222, 145, 207, 97, 2, 212, 113, 156, 88, 76, 89, 182, 17, 3, 61, 41, 234, 132, 114, 5, 16, 154, 133, 220, 190, 94, 198, 171, 136, 24, 231, 71, 73, 28, 141, 40, 128, 204, 36, 218, 235, 238, 42, 83, 60, 192, 49, 54, 70, 224, 100, 63, 253, 90, 31, 202, 81, 105, 79, 150, 223, 251, 135, 175, 46, 250, 29, 247, 225, 206, 248, 74, 134, 69, 118, 172, 242, 209, 52, 115, 111, 201, 232, 177, 1], +[1, 107, 141, 181, 92, 78, 122, 204, 240, 237, 173, 7, 235, 216, 239, 130, 32, 83, 143, 138, 117, 183, 49, 103, 227, 131, 139, 224, 67, 230, 195, 48, 253, 86, 207, 47, 146, 202, 26, 212, 68, 80, 79, 229, 88, 164, 72, 251, 129, 182, 199, 219, 46, 39, 61, 102, 120, 247, 215, 132, 246, 108, 248, 65, 16, 170, 200, 69, 187, 220, 153, 180, 242, 194, 198, 112, 162, 115, 226, 24, 255, 43, 232, 152, 73, 101, 13, 106, 34, 40, 168, 243, 44, 82, 36, 254, 193, 91, 228, 238, 23, 148, 159, 51, 60, 252, 236, 66, 123, 54, 124, 161, 8, 85, 100, 163, 222, 110, 205, 90, 121, 97, 99, 56, 81, 186, 113, 12, 256, 150, 116, 76, 165, 179, 135, 53, 17, 20, 84, 250, 22, 41, 18, 127, 225, 174, 114, 119, 140, 74, 208, 154, 30, 126, 118, 33, 190, 27, 62, 209, 4, 171, 50, 210, 111, 55, 231, 45, 189, 177, 178, 28, 169, 93, 185, 6, 128, 75, 58, 38, 211, 218, 196, 155, 137, 10, 42, 125, 11, 149, 9, 192, 241, 87, 57, 188, 70, 37, 104, 77, 15, 63, 59, 145, 95, 142, 31, 233, 2, 214, 25, 105, 184, 156, 244, 151, 223, 217, 89, 14, 213, 175, 221, 3, 64, 166, 29, 19, 234, 109, 98, 206, 197, 5, 21, 191, 134, 203, 133, 96, 249, 172, 157, 94, 35, 147, 52, 167, 136, 160, 158, 201, 176, 71, 144, 245, 1], +[1, 108, 99, 155, 35, 182, 124, 28, 197, 202, 228, 209, 213, 131, 13, 119, 2, 216, 198, 53, 70, 107, 248, 56, 137, 147, 199, 161, 169, 5, 26, 238, 4, 175, 139, 106, 140, 214, 239, 112, 17, 37, 141, 65, 81, 10, 52, 219, 8, 93, 21, 212, 23, 171, 221, 224, 34, 74, 25, 130, 162, 20, 104, 181, 16, 186, 42, 167, 46, 85, 185, 191, 68, 148, 50, 3, 67, 40, 208, 105, 32, 115, 84, 77, 92, 170, 113, 125, 136, 39, 100, 6, 134, 80, 159, 210, 64, 230, 168, 154, 184, 83, 226, 250, 15, 78, 200, 12, 11, 160, 61, 163, 128, 203, 79, 51, 111, 166, 195, 243, 30, 156, 143, 24, 22, 63, 122, 69, 256, 149, 158, 102, 222, 75, 133, 229, 60, 55, 29, 48, 44, 126, 244, 138, 255, 41, 59, 204, 187, 150, 9, 201, 120, 110, 58, 96, 88, 252, 231, 19, 253, 82, 118, 151, 117, 43, 18, 145, 240, 220, 116, 192, 176, 247, 205, 38, 249, 164, 236, 45, 234, 86, 36, 33, 223, 183, 232, 127, 95, 237, 153, 76, 241, 71, 215, 90, 211, 172, 72, 66, 189, 109, 207, 254, 190, 217, 49, 152, 225, 142, 173, 180, 165, 87, 144, 132, 121, 218, 157, 251, 123, 177, 98, 47, 193, 27, 89, 103, 73, 174, 31, 7, 242, 179, 57, 245, 246, 97, 196, 94, 129, 54, 178, 206, 146, 91, 62, 14, 227, 101, 114, 233, 235, 194, 135, 188, 1], +[1, 109, 59, 6, 140, 97, 36, 69, 68, 216, 157, 151, 11, 171, 135, 66, 255, 39, 139, 245, 234, 63, 185, 119, 121, 82, 200, 212, 235, 172, 244, 125, 4, 179, 236, 24, 46, 131, 144, 19, 15, 93, 114, 90, 44, 170, 26, 7, 249, 156, 42, 209, 165, 252, 226, 219, 227, 71, 29, 77, 169, 174, 205, 243, 16, 202, 173, 96, 184, 10, 62, 76, 60, 115, 199, 103, 176, 166, 104, 28, 225, 110, 168, 65, 146, 237, 133, 105, 137, 27, 116, 51, 162, 182, 49, 201, 64, 37, 178, 127, 222, 40, 248, 47, 240, 203, 25, 155, 190, 150, 159, 112, 129, 183, 158, 3, 70, 177, 18, 163, 34, 108, 207, 204, 134, 214, 196, 33, 256, 148, 198, 251, 117, 160, 221, 188, 189, 41, 100, 106, 246, 86, 122, 191, 2, 218, 118, 12, 23, 194, 72, 138, 136, 175, 57, 45, 22, 85, 13, 132, 253, 78, 21, 233, 211, 126, 113, 238, 242, 164, 143, 167, 213, 87, 231, 250, 8, 101, 215, 48, 92, 5, 31, 38, 30, 186, 228, 180, 88, 83, 52, 14, 241, 55, 84, 161, 73, 247, 195, 181, 197, 142, 58, 154, 81, 91, 153, 229, 32, 147, 89, 192, 111, 20, 124, 152, 120, 230, 141, 206, 95, 75, 208, 56, 193, 220, 79, 130, 35, 217, 9, 210, 17, 54, 232, 102, 67, 107, 98, 145, 128, 74, 99, 254, 187, 80, 239, 94, 223, 149, 50, 53, 123, 43, 61, 224, 1], +[1, 110, 21, 254, 184, 194, 9, 219, 189, 230, 114, 204, 81, 172, 159, 14, 255, 37, 215, 6, 146, 126, 239, 76, 136, 54, 29, 106, 95, 170, 196, 229, 4, 183, 84, 245, 222, 5, 36, 105, 242, 149, 199, 45, 67, 174, 122, 56, 249, 148, 89, 24, 70, 247, 185, 47, 30, 216, 116, 167, 123, 166, 13, 145, 16, 218, 79, 209, 117, 20, 144, 163, 197, 82, 25, 180, 11, 182, 231, 224, 225, 78, 99, 96, 23, 217, 226, 188, 120, 93, 207, 154, 235, 150, 52, 66, 64, 101, 59, 65, 211, 80, 62, 138, 17, 71, 100, 206, 44, 214, 153, 125, 129, 55, 139, 127, 92, 97, 133, 238, 223, 115, 57, 102, 169, 86, 208, 7, 256, 147, 236, 3, 73, 63, 248, 38, 68, 27, 143, 53, 176, 85, 98, 243, 2, 220, 42, 251, 111, 131, 18, 181, 121, 203, 228, 151, 162, 87, 61, 28, 253, 74, 173, 12, 35, 252, 221, 152, 15, 108, 58, 212, 190, 83, 135, 201, 8, 109, 168, 233, 187, 10, 72, 210, 227, 41, 141, 90, 134, 91, 244, 112, 241, 39, 178, 48, 140, 237, 113, 94, 60, 175, 232, 77, 246, 75, 26, 33, 32, 179, 158, 161, 234, 40, 31, 69, 137, 164, 50, 103, 22, 107, 205, 191, 193, 156, 198, 192, 46, 177, 195, 119, 240, 186, 157, 51, 213, 43, 104, 132, 128, 202, 118, 130, 165, 160, 124, 19, 34, 142, 200, 155, 88, 171, 49, 250, 1], +[1, 111, 242, 134, 225, 46, 223, 81, 253, 70, 60, 235, 128, 73, 136, 190, 16, 234, 17, 88, 2, 222, 227, 11, 193, 92, 189, 162, 249, 140, 120, 213, 256, 146, 15, 123, 32, 211, 34, 176, 4, 187, 197, 22, 129, 184, 121, 67, 241, 23, 240, 169, 255, 35, 30, 246, 64, 165, 68, 95, 8, 117, 137, 44, 1, 111, 242, 134, 225, 46, 223, 81, 253, 70, 60, 235, 128, 73, 136, 190, 16, 234, 17, 88, 2, 222, 227, 11, 193, 92, 189, 162, 249, 140, 120, 213, 256, 146, 15, 123, 32, 211, 34, 176, 4, 187, 197, 22, 129, 184, 121, 67, 241, 23, 240, 169, 255, 35, 30, 246, 64, 165, 68, 95, 8, 117, 137, 44, 1, 111, 242, 134, 225, 46, 223, 81, 253, 70, 60, 235, 128, 73, 136, 190, 16, 234, 17, 88, 2, 222, 227, 11, 193, 92, 189, 162, 249, 140, 120, 213, 256, 146, 15, 123, 32, 211, 34, 176, 4, 187, 197, 22, 129, 184, 121, 67, 241, 23, 240, 169, 255, 35, 30, 246, 64, 165, 68, 95, 8, 117, 137, 44, 1, 111, 242, 134, 225, 46, 223, 81, 253, 70, 60, 235, 128, 73, 136, 190, 16, 234, 17, 88, 2, 222, 227, 11, 193, 92, 189, 162, 249, 140, 120, 213, 256, 146, 15, 123, 32, 211, 34, 176, 4, 187, 197, 22, 129, 184, 121, 67, 241, 23, 240, 169, 255, 35, 30, 246, 64, 165, 68, 95, 8, 117, 137, 44, 1], +[1, 112, 208, 166, 88, 90, 57, 216, 34, 210, 133, 247, 165, 233, 139, 148, 128, 201, 153, 174, 213, 212, 100, 149, 240, 152, 62, 5, 46, 12, 59, 183, 193, 28, 52, 170, 22, 151, 207, 54, 137, 181, 226, 126, 234, 251, 99, 37, 32, 243, 231, 172, 246, 53, 25, 230, 60, 38, 144, 194, 140, 3, 79, 110, 241, 7, 13, 171, 134, 102, 116, 142, 227, 238, 185, 160, 187, 127, 89, 202, 8, 125, 122, 43, 190, 206, 199, 186, 15, 138, 36, 177, 35, 65, 84, 156, 253, 66, 196, 107, 162, 154, 29, 164, 121, 188, 239, 40, 111, 96, 215, 179, 2, 224, 159, 75, 176, 180, 114, 175, 68, 163, 9, 237, 73, 209, 21, 39, 256, 145, 49, 91, 169, 167, 200, 41, 223, 47, 124, 10, 92, 24, 118, 109, 129, 56, 104, 83, 44, 45, 157, 108, 17, 105, 195, 252, 211, 245, 198, 74, 64, 229, 205, 87, 235, 106, 50, 203, 120, 76, 31, 131, 23, 6, 158, 220, 225, 14, 26, 85, 11, 204, 232, 27, 197, 219, 113, 63, 117, 254, 178, 147, 16, 250, 244, 86, 123, 155, 141, 115, 30, 19, 72, 97, 70, 130, 168, 55, 249, 132, 135, 214, 67, 51, 58, 71, 242, 119, 221, 80, 222, 192, 173, 101, 4, 191, 61, 150, 95, 103, 228, 93, 136, 69, 18, 217, 146, 161, 42, 78, 255, 33, 98, 182, 81, 77, 143, 82, 189, 94, 248, 20, 184, 48, 236, 218, 1], +[1, 113, 176, 99, 136, 205, 35, 100, 249, 124, 134, 236, 197, 159, 234, 228, 64, 36, 213, 168, 223, 13, 184, 232, 2, 226, 95, 198, 15, 153, 70, 200, 241, 248, 11, 215, 137, 61, 211, 199, 128, 72, 169, 79, 189, 26, 111, 207, 4, 195, 190, 139, 30, 49, 140, 143, 225, 239, 22, 173, 17, 122, 165, 141, 256, 144, 81, 158, 121, 52, 222, 157, 8, 133, 123, 21, 60, 98, 23, 29, 193, 221, 44, 89, 34, 244, 73, 25, 255, 31, 162, 59, 242, 104, 187, 57, 16, 9, 246, 42, 120, 196, 46, 58, 129, 185, 88, 178, 68, 231, 146, 50, 253, 62, 67, 118, 227, 208, 117, 114, 32, 18, 235, 84, 240, 135, 92, 116, 1, 113, 176, 99, 136, 205, 35, 100, 249, 124, 134, 236, 197, 159, 234, 228, 64, 36, 213, 168, 223, 13, 184, 232, 2, 226, 95, 198, 15, 153, 70, 200, 241, 248, 11, 215, 137, 61, 211, 199, 128, 72, 169, 79, 189, 26, 111, 207, 4, 195, 190, 139, 30, 49, 140, 143, 225, 239, 22, 173, 17, 122, 165, 141, 256, 144, 81, 158, 121, 52, 222, 157, 8, 133, 123, 21, 60, 98, 23, 29, 193, 221, 44, 89, 34, 244, 73, 25, 255, 31, 162, 59, 242, 104, 187, 57, 16, 9, 246, 42, 120, 196, 46, 58, 129, 185, 88, 178, 68, 231, 146, 50, 253, 62, 67, 118, 227, 208, 117, 114, 32, 18, 235, 84, 240, 135, 92, 116, 1], +[1, 114, 146, 196, 242, 89, 123, 144, 225, 207, 211, 153, 223, 236, 176, 18, 253, 58, 187, 244, 60, 158, 22, 195, 128, 200, 184, 159, 136, 84, 67, 185, 16, 25, 23, 52, 17, 139, 169, 248, 2, 228, 35, 135, 227, 178, 246, 31, 193, 157, 165, 49, 189, 215, 95, 36, 249, 116, 117, 231, 120, 59, 44, 133, 256, 143, 111, 61, 15, 168, 134, 113, 32, 50, 46, 104, 34, 21, 81, 239, 4, 199, 70, 13, 197, 99, 235, 62, 129, 57, 73, 98, 121, 173, 190, 72, 241, 232, 234, 205, 240, 118, 88, 9, 255, 29, 222, 122, 30, 79, 11, 226, 64, 100, 92, 208, 68, 42, 162, 221, 8, 141, 140, 26, 137, 198, 213, 124, 1, 114, 146, 196, 242, 89, 123, 144, 225, 207, 211, 153, 223, 236, 176, 18, 253, 58, 187, 244, 60, 158, 22, 195, 128, 200, 184, 159, 136, 84, 67, 185, 16, 25, 23, 52, 17, 139, 169, 248, 2, 228, 35, 135, 227, 178, 246, 31, 193, 157, 165, 49, 189, 215, 95, 36, 249, 116, 117, 231, 120, 59, 44, 133, 256, 143, 111, 61, 15, 168, 134, 113, 32, 50, 46, 104, 34, 21, 81, 239, 4, 199, 70, 13, 197, 99, 235, 62, 129, 57, 73, 98, 121, 173, 190, 72, 241, 232, 234, 205, 240, 118, 88, 9, 255, 29, 222, 122, 30, 79, 11, 226, 64, 100, 92, 208, 68, 42, 162, 221, 8, 141, 140, 26, 137, 198, 213, 124, 1], +[1, 115, 118, 206, 46, 150, 31, 224, 60, 218, 141, 24, 190, 5, 61, 76, 2, 230, 236, 155, 92, 43, 62, 191, 120, 179, 25, 48, 123, 10, 122, 152, 4, 203, 215, 53, 184, 86, 124, 125, 240, 101, 50, 96, 246, 20, 244, 47, 8, 149, 173, 106, 111, 172, 248, 250, 223, 202, 100, 192, 235, 40, 231, 94, 16, 41, 89, 212, 222, 87, 239, 243, 189, 147, 200, 127, 213, 80, 205, 188, 32, 82, 178, 167, 187, 174, 221, 229, 121, 37, 143, 254, 169, 160, 153, 119, 64, 164, 99, 77, 117, 91, 185, 201, 242, 74, 29, 251, 81, 63, 49, 238, 128, 71, 198, 154, 234, 182, 113, 145, 227, 148, 58, 245, 162, 126, 98, 219, 256, 142, 139, 51, 211, 107, 226, 33, 197, 39, 116, 233, 67, 252, 196, 181, 255, 27, 21, 102, 165, 214, 195, 66, 137, 78, 232, 209, 134, 247, 135, 105, 253, 54, 42, 204, 73, 171, 133, 132, 17, 156, 207, 161, 11, 237, 13, 210, 249, 108, 84, 151, 146, 85, 9, 7, 34, 55, 157, 65, 22, 217, 26, 163, 241, 216, 168, 45, 35, 170, 18, 14, 68, 110, 57, 130, 44, 177, 52, 69, 225, 175, 79, 90, 70, 83, 36, 28, 136, 220, 114, 3, 88, 97, 104, 138, 193, 93, 158, 180, 140, 166, 72, 56, 15, 183, 228, 6, 176, 194, 208, 19, 129, 186, 59, 103, 23, 75, 144, 112, 30, 109, 199, 12, 95, 131, 159, 38, 1], +[1, 116, 92, 135, 240, 84, 235, 18, 32, 114, 117, 208, 227, 118, 67, 62, 253, 50, 146, 231, 68, 178, 88, 185, 129, 58, 46, 196, 120, 42, 246, 9, 16, 57, 187, 104, 242, 59, 162, 31, 255, 25, 73, 244, 34, 89, 44, 221, 193, 29, 23, 98, 60, 21, 123, 133, 8, 157, 222, 52, 121, 158, 81, 144, 256, 141, 165, 122, 17, 173, 22, 239, 225, 143, 140, 49, 30, 139, 190, 195, 4, 207, 111, 26, 189, 79, 169, 72, 128, 199, 211, 61, 137, 215, 11, 248, 241, 200, 70, 153, 15, 198, 95, 226, 2, 232, 184, 13, 223, 168, 213, 36, 64, 228, 234, 159, 197, 236, 134, 124, 249, 100, 35, 205, 136, 99, 176, 113, 1, 116, 92, 135, 240, 84, 235, 18, 32, 114, 117, 208, 227, 118, 67, 62, 253, 50, 146, 231, 68, 178, 88, 185, 129, 58, 46, 196, 120, 42, 246, 9, 16, 57, 187, 104, 242, 59, 162, 31, 255, 25, 73, 244, 34, 89, 44, 221, 193, 29, 23, 98, 60, 21, 123, 133, 8, 157, 222, 52, 121, 158, 81, 144, 256, 141, 165, 122, 17, 173, 22, 239, 225, 143, 140, 49, 30, 139, 190, 195, 4, 207, 111, 26, 189, 79, 169, 72, 128, 199, 211, 61, 137, 215, 11, 248, 241, 200, 70, 153, 15, 198, 95, 226, 2, 232, 184, 13, 223, 168, 213, 36, 64, 228, 234, 159, 197, 236, 134, 124, 249, 100, 35, 205, 136, 99, 176, 113, 1], +[1, 117, 68, 246, 255, 23, 121, 22, 4, 211, 15, 213, 249, 92, 227, 88, 16, 73, 60, 81, 225, 111, 137, 95, 64, 35, 240, 67, 129, 187, 34, 123, 256, 140, 189, 11, 2, 234, 136, 235, 253, 46, 242, 44, 8, 165, 30, 169, 241, 184, 197, 176, 32, 146, 120, 162, 193, 222, 17, 190, 128, 70, 223, 134, 1, 117, 68, 246, 255, 23, 121, 22, 4, 211, 15, 213, 249, 92, 227, 88, 16, 73, 60, 81, 225, 111, 137, 95, 64, 35, 240, 67, 129, 187, 34, 123, 256, 140, 189, 11, 2, 234, 136, 235, 253, 46, 242, 44, 8, 165, 30, 169, 241, 184, 197, 176, 32, 146, 120, 162, 193, 222, 17, 190, 128, 70, 223, 134, 1, 117, 68, 246, 255, 23, 121, 22, 4, 211, 15, 213, 249, 92, 227, 88, 16, 73, 60, 81, 225, 111, 137, 95, 64, 35, 240, 67, 129, 187, 34, 123, 256, 140, 189, 11, 2, 234, 136, 235, 253, 46, 242, 44, 8, 165, 30, 169, 241, 184, 197, 176, 32, 146, 120, 162, 193, 222, 17, 190, 128, 70, 223, 134, 1, 117, 68, 246, 255, 23, 121, 22, 4, 211, 15, 213, 249, 92, 227, 88, 16, 73, 60, 81, 225, 111, 137, 95, 64, 35, 240, 67, 129, 187, 34, 123, 256, 140, 189, 11, 2, 234, 136, 235, 253, 46, 242, 44, 8, 165, 30, 169, 241, 184, 197, 176, 32, 146, 120, 162, 193, 222, 17, 190, 128, 70, 223, 134, 1], +[1, 118, 46, 31, 60, 141, 190, 61, 2, 236, 92, 62, 120, 25, 123, 122, 4, 215, 184, 124, 240, 50, 246, 244, 8, 173, 111, 248, 223, 100, 235, 231, 16, 89, 222, 239, 189, 200, 213, 205, 32, 178, 187, 221, 121, 143, 169, 153, 64, 99, 117, 185, 242, 29, 81, 49, 128, 198, 234, 113, 227, 58, 162, 98, 256, 139, 211, 226, 197, 116, 67, 196, 255, 21, 165, 195, 137, 232, 134, 135, 253, 42, 73, 133, 17, 207, 11, 13, 249, 84, 146, 9, 34, 157, 22, 26, 241, 168, 35, 18, 68, 57, 44, 52, 225, 79, 70, 36, 136, 114, 88, 104, 193, 158, 140, 72, 15, 228, 176, 208, 129, 59, 23, 144, 30, 199, 95, 159, 1, 118, 46, 31, 60, 141, 190, 61, 2, 236, 92, 62, 120, 25, 123, 122, 4, 215, 184, 124, 240, 50, 246, 244, 8, 173, 111, 248, 223, 100, 235, 231, 16, 89, 222, 239, 189, 200, 213, 205, 32, 178, 187, 221, 121, 143, 169, 153, 64, 99, 117, 185, 242, 29, 81, 49, 128, 198, 234, 113, 227, 58, 162, 98, 256, 139, 211, 226, 197, 116, 67, 196, 255, 21, 165, 195, 137, 232, 134, 135, 253, 42, 73, 133, 17, 207, 11, 13, 249, 84, 146, 9, 34, 157, 22, 26, 241, 168, 35, 18, 68, 57, 44, 52, 225, 79, 70, 36, 136, 114, 88, 104, 193, 158, 140, 72, 15, 228, 176, 208, 129, 59, 23, 144, 30, 199, 95, 159, 1], +[1, 119, 26, 10, 162, 3, 100, 78, 30, 229, 9, 43, 234, 90, 173, 27, 129, 188, 13, 5, 81, 130, 50, 39, 15, 243, 133, 150, 117, 45, 215, 142, 193, 94, 135, 131, 169, 65, 25, 148, 136, 250, 195, 75, 187, 151, 236, 71, 225, 47, 196, 194, 213, 161, 141, 74, 68, 125, 226, 166, 222, 204, 118, 164, 241, 152, 98, 97, 235, 209, 199, 37, 34, 191, 113, 83, 111, 102, 59, 82, 249, 76, 49, 177, 246, 233, 228, 147, 17, 224, 185, 170, 184, 51, 158, 41, 253, 38, 153, 217, 123, 245, 114, 202, 137, 112, 221, 85, 92, 154, 79, 149, 255, 19, 205, 237, 190, 251, 57, 101, 197, 56, 239, 171, 46, 77, 168, 203, 256, 138, 231, 247, 95, 254, 157, 179, 227, 28, 248, 214, 23, 167, 84, 230, 128, 69, 244, 252, 176, 127, 207, 218, 242, 14, 124, 107, 140, 212, 42, 115, 64, 163, 122, 126, 88, 192, 232, 109, 121, 7, 62, 182, 70, 106, 21, 186, 32, 210, 61, 63, 44, 96, 116, 183, 189, 132, 31, 91, 35, 53, 139, 93, 16, 105, 159, 160, 22, 48, 58, 220, 223, 66, 144, 174, 146, 155, 198, 175, 8, 181, 208, 80, 11, 24, 29, 110, 240, 33, 72, 87, 73, 206, 99, 216, 4, 219, 104, 40, 134, 12, 143, 55, 120, 145, 36, 172, 165, 103, 178, 108, 2, 238, 52, 20, 67, 6, 200, 156, 60, 201, 18, 86, 211, 180, 89, 54, 1], +[1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1], +[1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1], +[1, 122, 235, 143, 227, 195, 146, 79, 129, 61, 246, 200, 242, 226, 73, 168, 193, 159, 123, 100, 121, 113, 165, 84, 225, 208, 190, 50, 189, 185, 211, 42, 241, 104, 95, 25, 223, 221, 234, 21, 249, 52, 176, 141, 240, 239, 117, 139, 253, 26, 88, 199, 120, 248, 187, 198, 255, 13, 44, 228, 60, 124, 222, 99, 256, 135, 22, 114, 30, 62, 111, 178, 128, 196, 11, 57, 15, 31, 184, 89, 64, 98, 134, 157, 136, 144, 92, 173, 32, 49, 67, 207, 68, 72, 46, 215, 16, 153, 162, 232, 34, 36, 23, 236, 8, 205, 81, 116, 17, 18, 140, 118, 4, 231, 169, 58, 137, 9, 70, 59, 2, 244, 213, 29, 197, 133, 35, 158, 1, 122, 235, 143, 227, 195, 146, 79, 129, 61, 246, 200, 242, 226, 73, 168, 193, 159, 123, 100, 121, 113, 165, 84, 225, 208, 190, 50, 189, 185, 211, 42, 241, 104, 95, 25, 223, 221, 234, 21, 249, 52, 176, 141, 240, 239, 117, 139, 253, 26, 88, 199, 120, 248, 187, 198, 255, 13, 44, 228, 60, 124, 222, 99, 256, 135, 22, 114, 30, 62, 111, 178, 128, 196, 11, 57, 15, 31, 184, 89, 64, 98, 134, 157, 136, 144, 92, 173, 32, 49, 67, 207, 68, 72, 46, 215, 16, 153, 162, 232, 34, 36, 23, 236, 8, 205, 81, 116, 17, 18, 140, 118, 4, 231, 169, 58, 137, 9, 70, 59, 2, 244, 213, 29, 197, 133, 35, 158, 1], +[1, 123, 223, 187, 128, 67, 17, 35, 193, 95, 120, 111, 32, 81, 197, 73, 241, 88, 30, 92, 8, 213, 242, 211, 253, 22, 136, 23, 2, 246, 189, 117, 256, 134, 34, 70, 129, 190, 240, 222, 64, 162, 137, 146, 225, 176, 60, 184, 16, 169, 227, 165, 249, 44, 15, 46, 4, 235, 121, 234, 255, 11, 68, 140, 1, 123, 223, 187, 128, 67, 17, 35, 193, 95, 120, 111, 32, 81, 197, 73, 241, 88, 30, 92, 8, 213, 242, 211, 253, 22, 136, 23, 2, 246, 189, 117, 256, 134, 34, 70, 129, 190, 240, 222, 64, 162, 137, 146, 225, 176, 60, 184, 16, 169, 227, 165, 249, 44, 15, 46, 4, 235, 121, 234, 255, 11, 68, 140, 1, 123, 223, 187, 128, 67, 17, 35, 193, 95, 120, 111, 32, 81, 197, 73, 241, 88, 30, 92, 8, 213, 242, 211, 253, 22, 136, 23, 2, 246, 189, 117, 256, 134, 34, 70, 129, 190, 240, 222, 64, 162, 137, 146, 225, 176, 60, 184, 16, 169, 227, 165, 249, 44, 15, 46, 4, 235, 121, 234, 255, 11, 68, 140, 1, 123, 223, 187, 128, 67, 17, 35, 193, 95, 120, 111, 32, 81, 197, 73, 241, 88, 30, 92, 8, 213, 242, 211, 253, 22, 136, 23, 2, 246, 189, 117, 256, 134, 34, 70, 129, 190, 240, 222, 64, 162, 137, 146, 225, 176, 60, 184, 16, 169, 227, 165, 249, 44, 15, 46, 4, 235, 121, 234, 255, 11, 68, 140, 1], +[1, 124, 213, 198, 137, 26, 140, 141, 8, 221, 162, 42, 68, 208, 92, 100, 64, 226, 11, 79, 30, 122, 222, 29, 255, 9, 88, 118, 240, 205, 234, 232, 241, 72, 190, 173, 121, 98, 73, 57, 129, 62, 235, 99, 197, 13, 70, 199, 4, 239, 81, 21, 34, 104, 46, 50, 32, 113, 134, 168, 15, 61, 111, 143, 256, 133, 44, 59, 120, 231, 117, 116, 249, 36, 95, 215, 189, 49, 165, 157, 193, 31, 246, 178, 227, 135, 35, 228, 2, 248, 169, 139, 17, 52, 23, 25, 16, 185, 67, 84, 136, 159, 184, 200, 128, 195, 22, 158, 60, 244, 187, 58, 253, 18, 176, 236, 223, 153, 211, 207, 225, 144, 123, 89, 242, 196, 146, 114, 1, 124, 213, 198, 137, 26, 140, 141, 8, 221, 162, 42, 68, 208, 92, 100, 64, 226, 11, 79, 30, 122, 222, 29, 255, 9, 88, 118, 240, 205, 234, 232, 241, 72, 190, 173, 121, 98, 73, 57, 129, 62, 235, 99, 197, 13, 70, 199, 4, 239, 81, 21, 34, 104, 46, 50, 32, 113, 134, 168, 15, 61, 111, 143, 256, 133, 44, 59, 120, 231, 117, 116, 249, 36, 95, 215, 189, 49, 165, 157, 193, 31, 246, 178, 227, 135, 35, 228, 2, 248, 169, 139, 17, 52, 23, 25, 16, 185, 67, 84, 136, 159, 184, 200, 128, 195, 22, 158, 60, 244, 187, 58, 253, 18, 176, 236, 223, 153, 211, 207, 225, 144, 123, 89, 242, 196, 146, 114, 1], +[1, 125, 205, 182, 134, 45, 228, 230, 223, 119, 226, 237, 70, 12, 215, 147, 128, 66, 26, 166, 190, 106, 143, 142, 17, 69, 144, 10, 222, 251, 21, 55, 193, 224, 244, 174, 162, 204, 57, 186, 120, 94, 185, 252, 146, 3, 118, 101, 32, 145, 135, 170, 176, 155, 100, 164, 197, 210, 36, 131, 184, 127, 198, 78, 241, 56, 61, 172, 169, 51, 207, 175, 30, 152, 239, 63, 165, 65, 158, 218, 8, 229, 98, 171, 44, 103, 25, 41, 242, 181, 9, 97, 46, 96, 178, 148, 253, 14, 208, 43, 235, 77, 116, 108, 136, 38, 124, 80, 234, 209, 168, 183, 2, 250, 153, 107, 11, 90, 199, 203, 189, 238, 195, 217, 140, 24, 173, 37, 256, 132, 52, 75, 123, 212, 29, 27, 34, 138, 31, 20, 187, 245, 42, 110, 129, 191, 231, 91, 67, 151, 114, 115, 240, 188, 113, 247, 35, 6, 236, 202, 64, 33, 13, 83, 95, 53, 200, 71, 137, 163, 72, 5, 111, 254, 139, 156, 225, 112, 122, 87, 81, 102, 157, 93, 60, 47, 221, 126, 73, 130, 59, 179, 16, 201, 196, 85, 88, 206, 50, 82, 227, 105, 18, 194, 92, 192, 99, 39, 249, 28, 159, 86, 213, 154, 232, 216, 15, 76, 248, 160, 211, 161, 79, 109, 4, 243, 49, 214, 22, 180, 141, 149, 121, 219, 133, 177, 23, 48, 89, 74, 255, 7, 104, 150, 246, 167, 58, 54, 68, 19, 62, 40, 117, 233, 84, 220, 1], +[1, 126, 199, 145, 23, 71, 208, 251, 15, 91, 158, 119, 88, 37, 36, 167, 225, 80, 57, 243, 35, 41, 26, 192, 34, 172, 84, 47, 11, 101, 133, 53, 253, 10, 232, 191, 165, 230, 196, 24, 197, 150, 139, 38, 162, 109, 113, 103, 128, 194, 29, 56, 117, 93, 153, 3, 121, 83, 178, 69, 213, 110, 239, 45, 16, 217, 100, 7, 111, 108, 244, 161, 240, 171, 215, 105, 123, 78, 62, 102, 2, 252, 141, 33, 46, 142, 159, 245, 30, 182, 59, 238, 176, 74, 72, 77, 193, 160, 114, 229, 70, 82, 52, 127, 68, 87, 168, 94, 22, 202, 9, 106, 249, 20, 207, 125, 73, 203, 135, 48, 137, 43, 21, 76, 67, 218, 226, 206, 256, 131, 58, 112, 234, 186, 49, 6, 242, 166, 99, 138, 169, 220, 221, 90, 32, 177, 200, 14, 222, 216, 231, 65, 223, 85, 173, 210, 246, 156, 124, 204, 4, 247, 25, 66, 92, 27, 61, 233, 60, 107, 118, 219, 95, 148, 144, 154, 129, 63, 228, 201, 140, 164, 104, 254, 136, 174, 79, 188, 44, 147, 18, 212, 241, 40, 157, 250, 146, 149, 13, 96, 17, 86, 42, 152, 134, 179, 195, 155, 255, 5, 116, 224, 211, 115, 98, 12, 227, 75, 198, 19, 81, 183, 185, 180, 64, 97, 143, 28, 187, 175, 205, 130, 189, 170, 89, 163, 235, 55, 248, 151, 8, 237, 50, 132, 184, 54, 122, 209, 120, 214, 236, 181, 190, 39, 31, 51, 1], +[1, 127, 195, 93, 246, 145, 168, 5, 121, 204, 208, 202, 211, 69, 25, 91, 249, 12, 239, 27, 88, 125, 198, 217, 60, 167, 135, 183, 111, 219, 57, 43, 64, 161, 144, 41, 67, 28, 215, 63, 34, 206, 205, 78, 140, 47, 58, 170, 2, 254, 133, 186, 235, 33, 79, 10, 242, 151, 159, 147, 165, 138, 50, 182, 241, 24, 221, 54, 176, 250, 139, 177, 120, 77, 13, 109, 222, 181, 114, 86, 128, 65, 31, 82, 134, 56, 173, 126, 68, 155, 153, 156, 23, 94, 116, 83, 4, 251, 9, 115, 213, 66, 158, 20, 227, 45, 61, 37, 73, 19, 100, 107, 225, 48, 185, 108, 95, 243, 21, 97, 240, 154, 26, 218, 187, 105, 228, 172, 256, 130, 62, 164, 11, 112, 89, 252, 136, 53, 49, 55, 46, 188, 232, 166, 8, 245, 18, 230, 169, 132, 59, 40, 197, 90, 122, 74, 146, 38, 200, 214, 193, 96, 113, 216, 190, 229, 42, 194, 223, 51, 52, 179, 117, 210, 199, 87, 255, 3, 124, 71, 22, 224, 178, 247, 15, 106, 98, 110, 92, 119, 207, 75, 16, 233, 36, 203, 81, 7, 118, 80, 137, 180, 244, 148, 35, 76, 143, 171, 129, 192, 226, 175, 123, 201, 84, 131, 189, 102, 104, 101, 234, 163, 141, 174, 253, 6, 248, 142, 44, 191, 99, 237, 30, 212, 196, 220, 184, 238, 157, 150, 32, 209, 72, 149, 162, 14, 236, 160, 17, 103, 231, 39, 70, 152, 29, 85, 1], +[1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1], +[1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1], +[1, 130, 195, 164, 246, 112, 168, 252, 121, 53, 208, 55, 211, 188, 25, 166, 249, 245, 239, 230, 88, 132, 198, 40, 60, 90, 135, 74, 111, 38, 57, 214, 64, 96, 144, 216, 67, 229, 215, 194, 34, 51, 205, 179, 140, 210, 58, 87, 2, 3, 133, 71, 235, 224, 79, 247, 242, 106, 159, 110, 165, 119, 50, 75, 241, 233, 221, 203, 176, 7, 139, 80, 120, 180, 13, 148, 222, 76, 114, 171, 128, 192, 31, 175, 134, 201, 173, 131, 68, 102, 153, 101, 23, 163, 116, 174, 4, 6, 9, 142, 213, 191, 158, 237, 227, 212, 61, 220, 73, 238, 100, 150, 225, 209, 185, 149, 95, 14, 21, 160, 240, 103, 26, 39, 187, 152, 228, 85, 256, 127, 62, 93, 11, 145, 89, 5, 136, 204, 49, 202, 46, 69, 232, 91, 8, 12, 18, 27, 169, 125, 59, 217, 197, 167, 122, 183, 146, 219, 200, 43, 193, 161, 113, 41, 190, 28, 42, 63, 223, 206, 52, 78, 117, 47, 199, 170, 255, 254, 124, 186, 22, 33, 178, 10, 15, 151, 98, 147, 92, 138, 207, 182, 16, 24, 36, 54, 81, 250, 118, 177, 137, 77, 244, 109, 35, 181, 143, 86, 129, 65, 226, 82, 123, 56, 84, 126, 189, 155, 104, 156, 234, 94, 141, 83, 253, 251, 248, 115, 44, 66, 99, 20, 30, 45, 196, 37, 184, 19, 157, 107, 32, 48, 72, 108, 162, 243, 236, 97, 17, 154, 231, 218, 70, 105, 29, 172, 1], +[1, 131, 199, 112, 23, 186, 208, 6, 15, 166, 158, 138, 88, 220, 36, 90, 225, 177, 57, 14, 35, 216, 26, 65, 34, 85, 84, 210, 11, 156, 133, 204, 253, 247, 232, 66, 165, 27, 196, 233, 197, 107, 139, 219, 162, 148, 113, 154, 128, 63, 29, 201, 117, 164, 153, 254, 121, 174, 178, 188, 213, 147, 239, 212, 16, 40, 100, 250, 111, 149, 244, 96, 240, 86, 215, 152, 123, 179, 62, 155, 2, 5, 141, 224, 46, 115, 159, 12, 30, 75, 59, 19, 176, 183, 72, 180, 193, 97, 114, 28, 70, 175, 52, 130, 68, 170, 168, 163, 22, 55, 9, 151, 249, 237, 207, 132, 73, 54, 135, 209, 137, 214, 21, 181, 67, 39, 226, 51, 256, 126, 58, 145, 234, 71, 49, 251, 242, 91, 99, 119, 169, 37, 221, 167, 32, 80, 200, 243, 222, 41, 231, 192, 223, 172, 173, 47, 246, 101, 124, 53, 4, 10, 25, 191, 92, 230, 61, 24, 60, 150, 118, 38, 95, 109, 144, 103, 129, 194, 228, 56, 140, 93, 104, 3, 136, 83, 79, 69, 44, 110, 18, 45, 241, 217, 157, 7, 146, 108, 13, 161, 17, 171, 42, 105, 134, 78, 195, 102, 255, 252, 116, 33, 211, 142, 98, 245, 227, 182, 198, 238, 81, 74, 185, 77, 64, 160, 143, 229, 187, 82, 205, 127, 189, 87, 89, 94, 235, 202, 248, 106, 8, 20, 50, 125, 184, 203, 122, 48, 120, 43, 236, 76, 190, 218, 31, 206, 1], +[1, 132, 205, 75, 134, 212, 228, 27, 223, 138, 226, 20, 70, 245, 215, 110, 128, 191, 26, 91, 190, 151, 143, 115, 17, 188, 144, 247, 222, 6, 21, 202, 193, 33, 244, 83, 162, 53, 57, 71, 120, 163, 185, 5, 146, 254, 118, 156, 32, 112, 135, 87, 176, 102, 100, 93, 197, 47, 36, 126, 184, 130, 198, 179, 241, 201, 61, 85, 169, 206, 207, 82, 30, 105, 239, 194, 165, 192, 158, 39, 8, 28, 98, 86, 44, 154, 25, 216, 242, 76, 9, 160, 46, 161, 178, 109, 253, 243, 208, 214, 235, 180, 116, 149, 136, 219, 124, 177, 234, 48, 168, 74, 2, 7, 153, 150, 11, 167, 199, 54, 189, 19, 195, 40, 140, 233, 173, 220, 256, 125, 52, 182, 123, 45, 29, 230, 34, 119, 31, 237, 187, 12, 42, 147, 129, 66, 231, 166, 67, 106, 114, 142, 240, 69, 113, 10, 35, 251, 236, 55, 64, 224, 13, 174, 95, 204, 200, 186, 137, 94, 72, 252, 111, 3, 139, 101, 225, 145, 122, 170, 81, 155, 157, 164, 60, 210, 221, 131, 73, 127, 59, 78, 16, 56, 196, 172, 88, 51, 50, 175, 227, 152, 18, 63, 92, 65, 99, 218, 249, 229, 159, 171, 213, 103, 232, 41, 15, 181, 248, 97, 211, 96, 79, 148, 4, 14, 49, 43, 22, 77, 141, 108, 121, 38, 133, 80, 23, 209, 89, 183, 255, 250, 104, 107, 246, 90, 58, 203, 68, 238, 62, 217, 117, 24, 84, 37, 1], +[1, 133, 213, 59, 137, 231, 140, 116, 8, 36, 162, 215, 68, 49, 92, 157, 64, 31, 11, 178, 30, 135, 222, 228, 255, 248, 88, 139, 240, 52, 234, 25, 241, 185, 190, 84, 121, 159, 73, 200, 129, 195, 235, 158, 197, 244, 70, 58, 4, 18, 81, 236, 34, 153, 46, 207, 32, 144, 134, 89, 15, 196, 111, 114, 256, 124, 44, 198, 120, 26, 117, 141, 249, 221, 95, 42, 189, 208, 165, 100, 193, 226, 246, 79, 227, 122, 35, 29, 2, 9, 169, 118, 17, 205, 23, 232, 16, 72, 67, 173, 136, 98, 184, 57, 128, 62, 22, 99, 60, 13, 187, 199, 253, 239, 176, 21, 223, 104, 211, 50, 225, 113, 123, 168, 242, 61, 146, 143, 1, 133, 213, 59, 137, 231, 140, 116, 8, 36, 162, 215, 68, 49, 92, 157, 64, 31, 11, 178, 30, 135, 222, 228, 255, 248, 88, 139, 240, 52, 234, 25, 241, 185, 190, 84, 121, 159, 73, 200, 129, 195, 235, 158, 197, 244, 70, 58, 4, 18, 81, 236, 34, 153, 46, 207, 32, 144, 134, 89, 15, 196, 111, 114, 256, 124, 44, 198, 120, 26, 117, 141, 249, 221, 95, 42, 189, 208, 165, 100, 193, 226, 246, 79, 227, 122, 35, 29, 2, 9, 169, 118, 17, 205, 23, 232, 16, 72, 67, 173, 136, 98, 184, 57, 128, 62, 22, 99, 60, 13, 187, 199, 253, 239, 176, 21, 223, 104, 211, 50, 225, 113, 123, 168, 242, 61, 146, 143, 1], +[1, 134, 223, 70, 128, 190, 17, 222, 193, 162, 120, 146, 32, 176, 197, 184, 241, 169, 30, 165, 8, 44, 242, 46, 253, 235, 136, 234, 2, 11, 189, 140, 256, 123, 34, 187, 129, 67, 240, 35, 64, 95, 137, 111, 225, 81, 60, 73, 16, 88, 227, 92, 249, 213, 15, 211, 4, 22, 121, 23, 255, 246, 68, 117, 1, 134, 223, 70, 128, 190, 17, 222, 193, 162, 120, 146, 32, 176, 197, 184, 241, 169, 30, 165, 8, 44, 242, 46, 253, 235, 136, 234, 2, 11, 189, 140, 256, 123, 34, 187, 129, 67, 240, 35, 64, 95, 137, 111, 225, 81, 60, 73, 16, 88, 227, 92, 249, 213, 15, 211, 4, 22, 121, 23, 255, 246, 68, 117, 1, 134, 223, 70, 128, 190, 17, 222, 193, 162, 120, 146, 32, 176, 197, 184, 241, 169, 30, 165, 8, 44, 242, 46, 253, 235, 136, 234, 2, 11, 189, 140, 256, 123, 34, 187, 129, 67, 240, 35, 64, 95, 137, 111, 225, 81, 60, 73, 16, 88, 227, 92, 249, 213, 15, 211, 4, 22, 121, 23, 255, 246, 68, 117, 1, 134, 223, 70, 128, 190, 17, 222, 193, 162, 120, 146, 32, 176, 197, 184, 241, 169, 30, 165, 8, 44, 242, 46, 253, 235, 136, 234, 2, 11, 189, 140, 256, 123, 34, 187, 129, 67, 240, 35, 64, 95, 137, 111, 225, 81, 60, 73, 16, 88, 227, 92, 249, 213, 15, 211, 4, 22, 121, 23, 255, 246, 68, 117, 1], +[1, 135, 235, 114, 227, 62, 146, 178, 129, 196, 246, 57, 242, 31, 73, 89, 193, 98, 123, 157, 121, 144, 165, 173, 225, 49, 190, 207, 189, 72, 211, 215, 241, 153, 95, 232, 223, 36, 234, 236, 249, 205, 176, 116, 240, 18, 117, 118, 253, 231, 88, 58, 120, 9, 187, 59, 255, 244, 44, 29, 60, 133, 222, 158, 256, 122, 22, 143, 30, 195, 111, 79, 128, 61, 11, 200, 15, 226, 184, 168, 64, 159, 134, 100, 136, 113, 92, 84, 32, 208, 67, 50, 68, 185, 46, 42, 16, 104, 162, 25, 34, 221, 23, 21, 8, 52, 81, 141, 17, 239, 140, 139, 4, 26, 169, 199, 137, 248, 70, 198, 2, 13, 213, 228, 197, 124, 35, 99, 1, 135, 235, 114, 227, 62, 146, 178, 129, 196, 246, 57, 242, 31, 73, 89, 193, 98, 123, 157, 121, 144, 165, 173, 225, 49, 190, 207, 189, 72, 211, 215, 241, 153, 95, 232, 223, 36, 234, 236, 249, 205, 176, 116, 240, 18, 117, 118, 253, 231, 88, 58, 120, 9, 187, 59, 255, 244, 44, 29, 60, 133, 222, 158, 256, 122, 22, 143, 30, 195, 111, 79, 128, 61, 11, 200, 15, 226, 184, 168, 64, 159, 134, 100, 136, 113, 92, 84, 32, 208, 67, 50, 68, 185, 46, 42, 16, 104, 162, 25, 34, 221, 23, 21, 8, 52, 81, 141, 17, 239, 140, 139, 4, 26, 169, 199, 137, 248, 70, 198, 2, 13, 213, 228, 197, 124, 35, 99, 1], +[1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1], +[1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1], +[1, 138, 26, 247, 162, 254, 100, 179, 30, 28, 9, 214, 234, 167, 173, 230, 129, 69, 13, 252, 81, 127, 50, 218, 15, 14, 133, 107, 117, 212, 215, 115, 193, 163, 135, 126, 169, 192, 25, 109, 136, 7, 195, 182, 187, 106, 236, 186, 225, 210, 196, 63, 213, 96, 141, 183, 68, 132, 226, 91, 222, 53, 118, 93, 241, 105, 98, 160, 235, 48, 199, 220, 34, 66, 113, 174, 111, 155, 59, 175, 249, 181, 49, 80, 246, 24, 228, 110, 17, 33, 185, 87, 184, 206, 158, 216, 253, 219, 153, 40, 123, 12, 114, 55, 137, 145, 221, 172, 92, 103, 79, 108, 255, 238, 205, 20, 190, 6, 57, 156, 197, 201, 239, 86, 46, 180, 168, 54, 256, 119, 231, 10, 95, 3, 157, 78, 227, 229, 248, 43, 23, 90, 84, 27, 128, 188, 244, 5, 176, 130, 207, 39, 242, 243, 124, 150, 140, 45, 42, 142, 64, 94, 122, 131, 88, 65, 232, 148, 121, 250, 62, 75, 70, 151, 21, 71, 32, 47, 61, 194, 44, 161, 116, 74, 189, 125, 31, 166, 35, 204, 139, 164, 16, 152, 159, 97, 22, 209, 58, 37, 223, 191, 144, 83, 146, 102, 198, 82, 8, 76, 208, 177, 11, 233, 29, 147, 240, 224, 72, 170, 73, 51, 99, 41, 4, 38, 104, 217, 134, 245, 143, 202, 120, 112, 36, 85, 165, 154, 178, 149, 2, 19, 52, 237, 67, 251, 200, 101, 60, 56, 18, 171, 211, 77, 89, 203, 1], +[1, 139, 46, 226, 60, 116, 190, 196, 2, 21, 92, 195, 120, 232, 123, 135, 4, 42, 184, 133, 240, 207, 246, 13, 8, 84, 111, 9, 223, 157, 235, 26, 16, 168, 222, 18, 189, 57, 213, 52, 32, 79, 187, 36, 121, 114, 169, 104, 64, 158, 117, 72, 242, 228, 81, 208, 128, 59, 234, 144, 227, 199, 162, 159, 256, 118, 211, 31, 197, 141, 67, 61, 255, 236, 165, 62, 137, 25, 134, 122, 253, 215, 73, 124, 17, 50, 11, 244, 249, 173, 146, 248, 34, 100, 22, 231, 241, 89, 35, 239, 68, 200, 44, 205, 225, 178, 70, 221, 136, 143, 88, 153, 193, 99, 140, 185, 15, 29, 176, 49, 129, 198, 23, 113, 30, 58, 95, 98, 1, 139, 46, 226, 60, 116, 190, 196, 2, 21, 92, 195, 120, 232, 123, 135, 4, 42, 184, 133, 240, 207, 246, 13, 8, 84, 111, 9, 223, 157, 235, 26, 16, 168, 222, 18, 189, 57, 213, 52, 32, 79, 187, 36, 121, 114, 169, 104, 64, 158, 117, 72, 242, 228, 81, 208, 128, 59, 234, 144, 227, 199, 162, 159, 256, 118, 211, 31, 197, 141, 67, 61, 255, 236, 165, 62, 137, 25, 134, 122, 253, 215, 73, 124, 17, 50, 11, 244, 249, 173, 146, 248, 34, 100, 22, 231, 241, 89, 35, 239, 68, 200, 44, 205, 225, 178, 70, 221, 136, 143, 88, 153, 193, 99, 140, 185, 15, 29, 176, 49, 129, 198, 23, 113, 30, 58, 95, 98, 1], +[1, 140, 68, 11, 255, 234, 121, 235, 4, 46, 15, 44, 249, 165, 227, 169, 16, 184, 60, 176, 225, 146, 137, 162, 64, 222, 240, 190, 129, 70, 34, 134, 256, 117, 189, 246, 2, 23, 136, 22, 253, 211, 242, 213, 8, 92, 30, 88, 241, 73, 197, 81, 32, 111, 120, 95, 193, 35, 17, 67, 128, 187, 223, 123, 1, 140, 68, 11, 255, 234, 121, 235, 4, 46, 15, 44, 249, 165, 227, 169, 16, 184, 60, 176, 225, 146, 137, 162, 64, 222, 240, 190, 129, 70, 34, 134, 256, 117, 189, 246, 2, 23, 136, 22, 253, 211, 242, 213, 8, 92, 30, 88, 241, 73, 197, 81, 32, 111, 120, 95, 193, 35, 17, 67, 128, 187, 223, 123, 1, 140, 68, 11, 255, 234, 121, 235, 4, 46, 15, 44, 249, 165, 227, 169, 16, 184, 60, 176, 225, 146, 137, 162, 64, 222, 240, 190, 129, 70, 34, 134, 256, 117, 189, 246, 2, 23, 136, 22, 253, 211, 242, 213, 8, 92, 30, 88, 241, 73, 197, 81, 32, 111, 120, 95, 193, 35, 17, 67, 128, 187, 223, 123, 1, 140, 68, 11, 255, 234, 121, 235, 4, 46, 15, 44, 249, 165, 227, 169, 16, 184, 60, 176, 225, 146, 137, 162, 64, 222, 240, 190, 129, 70, 34, 134, 256, 117, 189, 246, 2, 23, 136, 22, 253, 211, 242, 213, 8, 92, 30, 88, 241, 73, 197, 81, 32, 111, 120, 95, 193, 35, 17, 67, 128, 187, 223, 123, 1], +[1, 141, 92, 122, 240, 173, 235, 239, 32, 143, 117, 49, 227, 139, 67, 195, 253, 207, 146, 26, 68, 79, 88, 72, 129, 199, 46, 61, 120, 215, 246, 248, 16, 200, 187, 153, 242, 198, 162, 226, 255, 232, 73, 13, 34, 168, 44, 36, 193, 228, 23, 159, 60, 236, 123, 124, 8, 100, 222, 205, 121, 99, 81, 113, 256, 116, 165, 135, 17, 84, 22, 18, 225, 114, 140, 208, 30, 118, 190, 62, 4, 50, 111, 231, 189, 178, 169, 185, 128, 58, 211, 196, 137, 42, 11, 9, 241, 57, 70, 104, 15, 59, 95, 31, 2, 25, 184, 244, 223, 89, 213, 221, 64, 29, 234, 98, 197, 21, 134, 133, 249, 157, 35, 52, 136, 158, 176, 144, 1, 141, 92, 122, 240, 173, 235, 239, 32, 143, 117, 49, 227, 139, 67, 195, 253, 207, 146, 26, 68, 79, 88, 72, 129, 199, 46, 61, 120, 215, 246, 248, 16, 200, 187, 153, 242, 198, 162, 226, 255, 232, 73, 13, 34, 168, 44, 36, 193, 228, 23, 159, 60, 236, 123, 124, 8, 100, 222, 205, 121, 99, 81, 113, 256, 116, 165, 135, 17, 84, 22, 18, 225, 114, 140, 208, 30, 118, 190, 62, 4, 50, 111, 231, 189, 178, 169, 185, 128, 58, 211, 196, 137, 42, 11, 9, 241, 57, 70, 104, 15, 59, 95, 31, 2, 25, 184, 244, 223, 89, 213, 221, 64, 29, 234, 98, 197, 21, 134, 133, 249, 157, 35, 52, 136, 158, 176, 144, 1], +[1, 142, 118, 51, 46, 107, 31, 33, 60, 39, 141, 233, 190, 252, 61, 181, 2, 27, 236, 102, 92, 214, 62, 66, 120, 78, 25, 209, 123, 247, 122, 105, 4, 54, 215, 204, 184, 171, 124, 132, 240, 156, 50, 161, 246, 237, 244, 210, 8, 108, 173, 151, 111, 85, 248, 7, 223, 55, 100, 65, 235, 217, 231, 163, 16, 216, 89, 45, 222, 170, 239, 14, 189, 110, 200, 130, 213, 177, 205, 69, 32, 175, 178, 90, 187, 83, 221, 28, 121, 220, 143, 3, 169, 97, 153, 138, 64, 93, 99, 180, 117, 166, 185, 56, 242, 183, 29, 6, 81, 194, 49, 19, 128, 186, 198, 103, 234, 75, 113, 112, 227, 109, 58, 12, 162, 131, 98, 38, 256, 115, 139, 206, 211, 150, 226, 224, 197, 218, 116, 24, 67, 5, 196, 76, 255, 230, 21, 155, 165, 43, 195, 191, 137, 179, 232, 48, 134, 10, 135, 152, 253, 203, 42, 53, 73, 86, 133, 125, 17, 101, 207, 96, 11, 20, 13, 47, 249, 149, 84, 106, 146, 172, 9, 250, 34, 202, 157, 192, 22, 40, 26, 94, 241, 41, 168, 212, 35, 87, 18, 243, 68, 147, 57, 127, 44, 80, 52, 188, 225, 82, 79, 167, 70, 174, 36, 229, 136, 37, 114, 254, 88, 160, 104, 119, 193, 164, 158, 77, 140, 91, 72, 201, 15, 74, 228, 251, 176, 63, 208, 238, 129, 71, 59, 154, 23, 182, 144, 145, 30, 148, 199, 245, 95, 126, 159, 219, 1], +[1, 143, 146, 61, 242, 168, 123, 113, 225, 50, 211, 104, 223, 21, 176, 239, 253, 199, 187, 13, 60, 99, 22, 62, 128, 57, 184, 98, 136, 173, 67, 72, 16, 232, 23, 205, 17, 118, 169, 9, 2, 29, 35, 122, 227, 79, 246, 226, 193, 100, 165, 208, 189, 42, 95, 221, 249, 141, 117, 26, 120, 198, 44, 124, 256, 114, 111, 196, 15, 89, 134, 144, 32, 207, 46, 153, 34, 236, 81, 18, 4, 58, 70, 244, 197, 158, 235, 195, 129, 200, 73, 159, 121, 84, 190, 185, 241, 25, 234, 52, 240, 139, 88, 248, 255, 228, 222, 135, 30, 178, 11, 31, 64, 157, 92, 49, 68, 215, 162, 36, 8, 116, 140, 231, 137, 59, 213, 133, 1, 143, 146, 61, 242, 168, 123, 113, 225, 50, 211, 104, 223, 21, 176, 239, 253, 199, 187, 13, 60, 99, 22, 62, 128, 57, 184, 98, 136, 173, 67, 72, 16, 232, 23, 205, 17, 118, 169, 9, 2, 29, 35, 122, 227, 79, 246, 226, 193, 100, 165, 208, 189, 42, 95, 221, 249, 141, 117, 26, 120, 198, 44, 124, 256, 114, 111, 196, 15, 89, 134, 144, 32, 207, 46, 153, 34, 236, 81, 18, 4, 58, 70, 244, 197, 158, 235, 195, 129, 200, 73, 159, 121, 84, 190, 185, 241, 25, 234, 52, 240, 139, 88, 248, 255, 228, 222, 135, 30, 178, 11, 31, 64, 157, 92, 49, 68, 215, 162, 36, 8, 116, 140, 231, 137, 59, 213, 133, 1], +[1, 144, 176, 158, 136, 52, 35, 157, 249, 133, 134, 21, 197, 98, 234, 29, 64, 221, 213, 89, 223, 244, 184, 25, 2, 31, 95, 59, 15, 104, 70, 57, 241, 9, 11, 42, 137, 196, 211, 58, 128, 185, 169, 178, 189, 231, 111, 50, 4, 62, 190, 118, 30, 208, 140, 114, 225, 18, 22, 84, 17, 135, 165, 116, 256, 113, 81, 99, 121, 205, 222, 100, 8, 124, 123, 236, 60, 159, 23, 228, 193, 36, 44, 168, 34, 13, 73, 232, 255, 226, 162, 198, 242, 153, 187, 200, 16, 248, 246, 215, 120, 61, 46, 199, 129, 72, 88, 79, 68, 26, 146, 207, 253, 195, 67, 139, 227, 49, 117, 143, 32, 239, 235, 173, 240, 122, 92, 141, 1, 144, 176, 158, 136, 52, 35, 157, 249, 133, 134, 21, 197, 98, 234, 29, 64, 221, 213, 89, 223, 244, 184, 25, 2, 31, 95, 59, 15, 104, 70, 57, 241, 9, 11, 42, 137, 196, 211, 58, 128, 185, 169, 178, 189, 231, 111, 50, 4, 62, 190, 118, 30, 208, 140, 114, 225, 18, 22, 84, 17, 135, 165, 116, 256, 113, 81, 99, 121, 205, 222, 100, 8, 124, 123, 236, 60, 159, 23, 228, 193, 36, 44, 168, 34, 13, 73, 232, 255, 226, 162, 198, 242, 153, 187, 200, 16, 248, 246, 215, 120, 61, 46, 199, 129, 72, 88, 79, 68, 26, 146, 207, 253, 195, 67, 139, 227, 49, 117, 143, 32, 239, 235, 173, 240, 122, 92, 141, 1], +[1, 145, 208, 91, 88, 167, 57, 41, 34, 47, 133, 10, 165, 24, 139, 109, 128, 56, 153, 83, 213, 45, 100, 108, 240, 105, 62, 252, 46, 245, 59, 74, 193, 229, 52, 87, 22, 106, 207, 203, 137, 76, 226, 131, 234, 6, 99, 220, 32, 14, 231, 85, 246, 204, 25, 27, 60, 219, 144, 63, 140, 254, 79, 147, 241, 250, 13, 86, 134, 155, 116, 115, 227, 19, 185, 97, 187, 130, 89, 55, 8, 132, 122, 214, 190, 51, 199, 71, 15, 119, 36, 80, 35, 192, 84, 101, 253, 191, 196, 150, 162, 103, 29, 93, 121, 69, 239, 217, 111, 161, 215, 78, 2, 33, 159, 182, 176, 77, 114, 82, 68, 94, 9, 20, 73, 48, 21, 218, 256, 112, 49, 166, 169, 90, 200, 216, 223, 210, 124, 247, 92, 233, 118, 148, 129, 201, 104, 174, 44, 212, 157, 149, 17, 152, 195, 5, 211, 12, 198, 183, 64, 28, 205, 170, 235, 151, 50, 54, 120, 181, 31, 126, 23, 251, 158, 37, 225, 243, 26, 172, 11, 53, 232, 230, 197, 38, 113, 194, 117, 3, 178, 110, 16, 7, 244, 171, 123, 102, 141, 142, 30, 238, 72, 160, 70, 127, 168, 202, 249, 125, 135, 43, 67, 206, 58, 186, 242, 138, 221, 177, 222, 65, 173, 156, 4, 66, 61, 107, 95, 154, 228, 164, 136, 188, 18, 40, 146, 96, 42, 179, 255, 224, 98, 75, 81, 180, 143, 175, 189, 163, 248, 237, 184, 209, 236, 39, 1], +[1, 146, 242, 123, 225, 211, 223, 176, 253, 187, 60, 22, 128, 184, 136, 67, 16, 23, 17, 169, 2, 35, 227, 246, 193, 165, 189, 95, 249, 117, 120, 44, 256, 111, 15, 134, 32, 46, 34, 81, 4, 70, 197, 235, 129, 73, 121, 190, 241, 234, 240, 88, 255, 222, 30, 11, 64, 92, 68, 162, 8, 140, 137, 213, 1, 146, 242, 123, 225, 211, 223, 176, 253, 187, 60, 22, 128, 184, 136, 67, 16, 23, 17, 169, 2, 35, 227, 246, 193, 165, 189, 95, 249, 117, 120, 44, 256, 111, 15, 134, 32, 46, 34, 81, 4, 70, 197, 235, 129, 73, 121, 190, 241, 234, 240, 88, 255, 222, 30, 11, 64, 92, 68, 162, 8, 140, 137, 213, 1, 146, 242, 123, 225, 211, 223, 176, 253, 187, 60, 22, 128, 184, 136, 67, 16, 23, 17, 169, 2, 35, 227, 246, 193, 165, 189, 95, 249, 117, 120, 44, 256, 111, 15, 134, 32, 46, 34, 81, 4, 70, 197, 235, 129, 73, 121, 190, 241, 234, 240, 88, 255, 222, 30, 11, 64, 92, 68, 162, 8, 140, 137, 213, 1, 146, 242, 123, 225, 211, 223, 176, 253, 187, 60, 22, 128, 184, 136, 67, 16, 23, 17, 169, 2, 35, 227, 246, 193, 165, 189, 95, 249, 117, 120, 44, 256, 111, 15, 134, 32, 46, 34, 81, 4, 70, 197, 235, 129, 73, 121, 190, 241, 234, 240, 88, 255, 222, 30, 11, 64, 92, 68, 162, 8, 140, 137, 213, 1], +[1, 147, 21, 3, 184, 63, 9, 38, 189, 27, 114, 53, 81, 85, 159, 243, 255, 220, 215, 251, 146, 131, 239, 181, 136, 203, 29, 151, 95, 87, 196, 28, 4, 74, 84, 12, 222, 252, 36, 152, 242, 108, 199, 212, 67, 83, 122, 201, 249, 109, 89, 233, 70, 10, 185, 210, 30, 41, 116, 90, 123, 91, 13, 112, 16, 39, 79, 48, 117, 237, 144, 94, 197, 175, 25, 77, 11, 75, 231, 33, 225, 179, 99, 161, 23, 40, 226, 69, 120, 164, 207, 103, 235, 107, 52, 191, 64, 156, 59, 192, 211, 177, 62, 119, 17, 186, 100, 51, 44, 43, 153, 132, 129, 202, 139, 130, 92, 160, 133, 19, 223, 142, 57, 155, 169, 171, 208, 250, 256, 110, 236, 254, 73, 194, 248, 219, 68, 230, 143, 204, 176, 172, 98, 14, 2, 37, 42, 6, 111, 126, 18, 76, 121, 54, 228, 106, 162, 170, 61, 229, 253, 183, 173, 245, 35, 5, 221, 105, 15, 149, 58, 45, 190, 174, 135, 56, 8, 148, 168, 24, 187, 247, 72, 47, 227, 216, 141, 167, 134, 166, 244, 145, 241, 218, 178, 209, 140, 20, 113, 163, 60, 82, 232, 180, 246, 182, 26, 224, 32, 78, 158, 96, 234, 217, 31, 188, 137, 93, 50, 154, 22, 150, 205, 66, 193, 101, 198, 65, 46, 80, 195, 138, 240, 71, 157, 206, 213, 214, 104, 125, 128, 55, 118, 127, 165, 97, 124, 238, 34, 115, 200, 102, 88, 86, 49, 7, 1], +[1, 148, 59, 251, 140, 160, 36, 188, 68, 41, 157, 106, 11, 86, 135, 191, 255, 218, 139, 12, 234, 194, 185, 138, 121, 175, 200, 45, 235, 85, 244, 132, 4, 78, 236, 233, 46, 126, 144, 238, 15, 164, 114, 167, 44, 87, 26, 250, 249, 101, 42, 48, 165, 5, 226, 38, 227, 186, 29, 180, 169, 83, 205, 14, 16, 55, 173, 161, 184, 247, 62, 181, 60, 142, 199, 154, 176, 91, 104, 229, 225, 147, 168, 192, 146, 20, 133, 152, 137, 230, 116, 206, 162, 75, 49, 56, 64, 220, 178, 130, 222, 217, 248, 210, 240, 54, 25, 102, 190, 107, 159, 145, 129, 74, 158, 254, 70, 80, 18, 94, 34, 149, 207, 53, 134, 43, 196, 224, 256, 109, 198, 6, 117, 97, 221, 69, 189, 216, 100, 151, 246, 171, 122, 66, 2, 39, 118, 245, 23, 63, 72, 119, 136, 82, 57, 212, 22, 172, 13, 125, 253, 179, 21, 24, 211, 131, 113, 19, 242, 93, 143, 90, 213, 170, 231, 7, 8, 156, 215, 209, 92, 252, 31, 219, 30, 71, 228, 77, 88, 174, 52, 243, 241, 202, 84, 96, 73, 10, 195, 76, 197, 115, 58, 103, 81, 166, 153, 28, 32, 110, 89, 65, 111, 237, 124, 105, 120, 27, 141, 51, 95, 182, 208, 201, 193, 37, 79, 127, 35, 40, 9, 47, 17, 203, 232, 155, 67, 150, 98, 112, 128, 183, 99, 3, 187, 177, 239, 163, 223, 108, 50, 204, 123, 214, 61, 33, 1], +[1, 149, 99, 102, 35, 75, 124, 229, 197, 55, 228, 48, 213, 126, 13, 138, 2, 41, 198, 204, 70, 150, 248, 201, 137, 110, 199, 96, 169, 252, 26, 19, 4, 82, 139, 151, 140, 43, 239, 145, 17, 220, 141, 192, 81, 247, 52, 38, 8, 164, 21, 45, 23, 86, 221, 33, 34, 183, 25, 127, 162, 237, 104, 76, 16, 71, 42, 90, 46, 172, 185, 66, 68, 109, 50, 254, 67, 217, 208, 152, 32, 142, 84, 180, 92, 87, 113, 132, 136, 218, 100, 251, 134, 177, 159, 47, 64, 27, 168, 103, 184, 174, 226, 7, 15, 179, 200, 245, 11, 97, 61, 94, 128, 54, 79, 206, 111, 91, 195, 14, 30, 101, 143, 233, 22, 194, 122, 188, 256, 108, 158, 155, 222, 182, 133, 28, 60, 202, 29, 209, 44, 131, 244, 119, 255, 216, 59, 53, 187, 107, 9, 56, 120, 147, 58, 161, 88, 5, 231, 238, 253, 175, 118, 106, 117, 214, 18, 112, 240, 37, 116, 65, 176, 10, 205, 219, 249, 93, 236, 212, 234, 171, 36, 224, 223, 74, 232, 130, 95, 20, 153, 181, 241, 186, 215, 167, 211, 85, 72, 191, 189, 148, 207, 3, 190, 40, 49, 105, 225, 115, 173, 77, 165, 170, 144, 125, 121, 39, 157, 6, 123, 80, 98, 210, 193, 230, 89, 154, 73, 83, 31, 250, 242, 78, 57, 12, 246, 160, 196, 163, 129, 203, 178, 51, 146, 166, 62, 243, 227, 156, 114, 24, 235, 63, 135, 69, 1], +[1, 150, 141, 76, 92, 179, 122, 53, 240, 20, 173, 250, 235, 41, 239, 127, 32, 174, 143, 119, 117, 74, 49, 154, 227, 126, 139, 33, 67, 27, 195, 209, 253, 171, 207, 210, 146, 55, 26, 45, 68, 177, 79, 28, 88, 93, 72, 6, 129, 75, 199, 38, 46, 218, 61, 155, 120, 10, 215, 125, 246, 149, 248, 192, 16, 87, 200, 188, 187, 37, 153, 77, 242, 63, 198, 145, 162, 142, 226, 233, 255, 214, 232, 105, 73, 156, 13, 151, 34, 217, 168, 14, 44, 175, 36, 3, 193, 166, 228, 19, 23, 109, 159, 206, 60, 5, 236, 191, 123, 203, 124, 96, 8, 172, 100, 94, 222, 147, 205, 167, 121, 160, 99, 201, 81, 71, 113, 245, 256, 107, 116, 181, 165, 78, 135, 204, 17, 237, 84, 7, 22, 216, 18, 130, 225, 83, 114, 138, 140, 183, 208, 103, 30, 131, 118, 224, 190, 230, 62, 48, 4, 86, 50, 47, 111, 202, 231, 212, 189, 80, 178, 229, 169, 164, 185, 251, 128, 182, 58, 219, 211, 39, 196, 102, 137, 247, 42, 132, 11, 108, 9, 65, 241, 170, 57, 69, 70, 220, 104, 180, 15, 194, 59, 112, 95, 115, 31, 24, 2, 43, 25, 152, 184, 101, 244, 106, 223, 40, 89, 243, 213, 82, 221, 254, 64, 91, 29, 238, 234, 148, 98, 51, 197, 252, 21, 66, 134, 54, 133, 161, 249, 85, 157, 163, 35, 110, 52, 90, 136, 97, 158, 56, 176, 186, 144, 12, 1], +[1, 151, 185, 179, 44, 219, 173, 166, 137, 127, 159, 108, 117, 191, 57, 126, 8, 180, 195, 147, 95, 210, 99, 43, 68, 245, 244, 93, 165, 243, 199, 237, 64, 155, 18, 148, 246, 138, 21, 87, 30, 161, 153, 230, 35, 145, 50, 97, 255, 212, 144, 156, 169, 76, 168, 182, 240, 3, 196, 41, 23, 132, 143, 5, 241, 154, 124, 220, 67, 94, 59, 171, 121, 24, 26, 71, 184, 28, 116, 40, 129, 204, 221, 218, 22, 238, 215, 83, 197, 192, 208, 54, 187, 224, 157, 63, 4, 90, 226, 202, 176, 105, 178, 150, 34, 251, 122, 175, 211, 250, 228, 247, 32, 206, 9, 74, 123, 69, 139, 172, 15, 209, 205, 115, 146, 201, 25, 177, 256, 106, 72, 78, 213, 38, 84, 91, 120, 130, 98, 149, 140, 66, 200, 131, 249, 77, 62, 110, 162, 47, 158, 214, 189, 12, 13, 164, 92, 14, 58, 20, 193, 102, 239, 109, 11, 119, 236, 170, 227, 96, 104, 27, 222, 112, 207, 160, 2, 45, 113, 101, 88, 181, 89, 75, 17, 254, 61, 216, 234, 125, 114, 252, 16, 103, 133, 37, 190, 163, 198, 86, 136, 233, 231, 186, 73, 229, 141, 217, 128, 53, 36, 39, 235, 19, 42, 174, 60, 65, 49, 203, 70, 33, 100, 194, 253, 167, 31, 55, 81, 152, 79, 107, 223, 6, 135, 82, 46, 7, 29, 10, 225, 51, 248, 183, 134, 188, 118, 85, 242, 48, 52, 142, 111, 56, 232, 80, 1], +[1, 152, 231, 160, 162, 209, 157, 220, 30, 191, 248, 174, 234, 102, 84, 175, 129, 76, 244, 80, 81, 233, 207, 110, 15, 224, 124, 87, 117, 51, 42, 216, 193, 38, 122, 40, 169, 245, 232, 55, 136, 112, 62, 172, 187, 154, 21, 108, 225, 19, 61, 20, 213, 251, 116, 156, 68, 56, 31, 86, 222, 77, 139, 54, 241, 138, 159, 10, 235, 254, 58, 78, 34, 28, 144, 43, 111, 167, 198, 27, 249, 69, 208, 5, 246, 127, 29, 39, 17, 14, 72, 150, 184, 212, 99, 142, 253, 163, 104, 131, 123, 192, 143, 148, 137, 7, 36, 75, 92, 106, 178, 71, 255, 210, 52, 194, 190, 96, 200, 74, 197, 132, 18, 166, 46, 53, 89, 164, 256, 105, 26, 97, 95, 48, 100, 37, 227, 66, 9, 83, 23, 155, 173, 82, 128, 181, 13, 177, 176, 24, 50, 147, 242, 33, 133, 170, 140, 206, 215, 41, 64, 219, 135, 217, 88, 12, 25, 202, 121, 145, 195, 85, 70, 103, 236, 149, 32, 238, 196, 237, 44, 6, 141, 101, 189, 201, 226, 171, 35, 180, 118, 203, 16, 119, 98, 247, 22, 3, 199, 179, 223, 229, 113, 214, 146, 90, 59, 230, 8, 188, 49, 252, 11, 130, 228, 218, 240, 243, 185, 107, 73, 45, 158, 115, 4, 94, 153, 126, 134, 65, 114, 109, 120, 250, 221, 182, 165, 151, 79, 186, 2, 47, 205, 63, 67, 161, 57, 183, 60, 125, 239, 91, 211, 204, 168, 93, 1], +[1, 153, 22, 25, 227, 36, 111, 21, 129, 205, 11, 141, 242, 18, 184, 139, 193, 231, 134, 199, 121, 9, 92, 198, 225, 244, 67, 228, 189, 133, 46, 99, 241, 122, 162, 114, 223, 195, 23, 178, 249, 61, 81, 57, 240, 226, 140, 89, 253, 159, 169, 157, 120, 113, 70, 173, 255, 208, 213, 207, 60, 185, 35, 215, 256, 104, 235, 232, 30, 221, 146, 236, 128, 52, 246, 116, 15, 239, 73, 118, 64, 26, 123, 58, 136, 248, 165, 59, 32, 13, 190, 29, 68, 124, 211, 158, 16, 135, 95, 143, 34, 62, 234, 79, 8, 196, 176, 200, 17, 31, 117, 168, 4, 98, 88, 100, 137, 144, 187, 84, 2, 49, 44, 50, 197, 72, 222, 42, 1, 153, 22, 25, 227, 36, 111, 21, 129, 205, 11, 141, 242, 18, 184, 139, 193, 231, 134, 199, 121, 9, 92, 198, 225, 244, 67, 228, 189, 133, 46, 99, 241, 122, 162, 114, 223, 195, 23, 178, 249, 61, 81, 57, 240, 226, 140, 89, 253, 159, 169, 157, 120, 113, 70, 173, 255, 208, 213, 207, 60, 185, 35, 215, 256, 104, 235, 232, 30, 221, 146, 236, 128, 52, 246, 116, 15, 239, 73, 118, 64, 26, 123, 58, 136, 248, 165, 59, 32, 13, 190, 29, 68, 124, 211, 158, 16, 135, 95, 143, 34, 62, 234, 79, 8, 196, 176, 200, 17, 31, 117, 168, 4, 98, 88, 100, 137, 144, 187, 84, 2, 49, 44, 50, 197, 72, 222, 42, 1], +[1, 154, 72, 37, 44, 94, 84, 86, 137, 24, 98, 186, 117, 28, 200, 217, 8, 204, 62, 39, 95, 238, 158, 174, 68, 192, 13, 203, 165, 224, 58, 194, 64, 90, 239, 55, 246, 105, 236, 107, 30, 251, 104, 82, 35, 250, 207, 10, 255, 206, 113, 183, 169, 69, 89, 85, 240, 209, 61, 142, 23, 201, 114, 80, 241, 106, 133, 179, 67, 38, 198, 166, 121, 130, 231, 108, 184, 66, 141, 126, 129, 77, 36, 147, 22, 47, 42, 43, 197, 12, 49, 93, 187, 14, 100, 237, 4, 102, 31, 148, 176, 119, 79, 87, 34, 96, 135, 230, 211, 112, 29, 97, 32, 45, 248, 156, 123, 181, 118, 182, 15, 254, 52, 41, 146, 125, 232, 5, 256, 103, 185, 220, 213, 163, 173, 171, 120, 233, 159, 71, 140, 229, 57, 40, 249, 53, 195, 218, 162, 19, 99, 83, 189, 65, 244, 54, 92, 33, 199, 63, 193, 167, 18, 202, 11, 152, 21, 150, 227, 6, 153, 175, 222, 7, 50, 247, 2, 51, 144, 74, 88, 188, 168, 172, 17, 48, 196, 115, 234, 56, 143, 177, 16, 151, 124, 78, 190, 219, 59, 91, 136, 127, 26, 149, 73, 191, 116, 131, 128, 180, 221, 110, 235, 210, 215, 214, 60, 245, 208, 164, 70, 243, 157, 20, 253, 155, 226, 109, 81, 138, 178, 170, 223, 161, 122, 27, 46, 145, 228, 160, 225, 212, 9, 101, 134, 76, 139, 75, 242, 3, 205, 216, 111, 132, 25, 252, 1], +[1, 155, 124, 202, 213, 119, 198, 107, 137, 161, 26, 175, 140, 112, 141, 10, 8, 212, 221, 74, 162, 181, 42, 85, 68, 3, 208, 115, 92, 125, 100, 80, 64, 154, 226, 78, 11, 163, 79, 166, 30, 24, 122, 149, 222, 229, 29, 126, 255, 204, 9, 110, 88, 19, 118, 43, 240, 192, 205, 164, 234, 33, 232, 237, 241, 90, 72, 109, 190, 152, 173, 87, 121, 251, 98, 27, 73, 7, 57, 97, 129, 206, 62, 101, 235, 188, 99, 182, 197, 209, 13, 216, 70, 56, 199, 5, 4, 106, 239, 37, 81, 219, 21, 171, 34, 130, 104, 186, 46, 191, 50, 40, 32, 77, 113, 39, 134, 210, 168, 83, 15, 12, 61, 203, 111, 243, 143, 63, 256, 102, 133, 55, 44, 138, 59, 150, 120, 96, 231, 82, 117, 145, 116, 247, 249, 45, 36, 183, 95, 76, 215, 172, 189, 254, 49, 142, 165, 132, 157, 177, 193, 103, 31, 179, 246, 94, 178, 91, 227, 233, 135, 108, 35, 28, 228, 131, 2, 53, 248, 147, 169, 238, 139, 214, 17, 65, 52, 93, 23, 224, 25, 20, 16, 167, 185, 148, 67, 105, 84, 170, 136, 6, 159, 230, 184, 250, 200, 160, 128, 51, 195, 156, 22, 69, 158, 75, 60, 48, 244, 41, 187, 201, 58, 252, 253, 151, 18, 220, 176, 38, 236, 86, 223, 127, 153, 71, 211, 66, 207, 217, 225, 180, 144, 218, 123, 47, 89, 174, 242, 245, 196, 54, 146, 14, 114, 194, 1], +[1, 156, 178, 12, 73, 80, 144, 105, 189, 186, 232, 212, 176, 214, 231, 56, 255, 202, 158, 233, 111, 97, 226, 47, 136, 142, 50, 90, 162, 86, 52, 145, 4, 110, 198, 48, 35, 63, 62, 163, 242, 230, 157, 77, 190, 85, 153, 224, 249, 37, 118, 161, 187, 131, 133, 188, 30, 54, 200, 103, 134, 87, 208, 66, 16, 183, 21, 192, 140, 252, 248, 138, 197, 149, 114, 51, 246, 83, 98, 125, 225, 148, 215, 130, 234, 10, 18, 238, 120, 216, 29, 155, 22, 91, 61, 7, 64, 218, 84, 254, 46, 237, 221, 38, 17, 82, 199, 204, 213, 75, 135, 243, 129, 78, 89, 6, 165, 40, 72, 181, 223, 93, 116, 106, 88, 107, 244, 28, 256, 101, 79, 245, 184, 177, 113, 152, 68, 71, 25, 45, 81, 43, 26, 201, 2, 55, 99, 24, 146, 160, 31, 210, 121, 115, 207, 167, 95, 171, 205, 112, 253, 147, 59, 209, 222, 194, 195, 94, 15, 27, 100, 180, 67, 172, 104, 33, 8, 220, 139, 96, 70, 126, 124, 69, 227, 203, 57, 154, 123, 170, 49, 191, 241, 74, 236, 65, 117, 5, 9, 119, 60, 108, 143, 206, 11, 174, 159, 132, 32, 109, 42, 127, 23, 247, 239, 19, 137, 41, 228, 102, 235, 166, 196, 250, 193, 39, 173, 3, 211, 20, 36, 219, 240, 175, 58, 53, 44, 182, 122, 14, 128, 179, 168, 251, 92, 217, 185, 76, 34, 164, 141, 151, 169, 150, 13, 229, 1], +[1, 157, 234, 244, 15, 42, 169, 62, 225, 116, 222, 159, 34, 198, 246, 72, 253, 143, 92, 52, 197, 89, 95, 9, 128, 50, 140, 135, 121, 236, 44, 226, 16, 199, 146, 49, 240, 158, 134, 221, 2, 57, 211, 231, 30, 84, 81, 124, 193, 232, 187, 61, 68, 139, 235, 144, 249, 29, 184, 104, 137, 178, 190, 18, 256, 100, 23, 13, 242, 215, 88, 195, 32, 141, 35, 98, 223, 59, 11, 185, 4, 114, 165, 205, 60, 168, 162, 248, 129, 207, 117, 122, 136, 21, 213, 31, 241, 58, 111, 208, 17, 99, 123, 36, 255, 200, 46, 26, 227, 173, 176, 133, 64, 25, 70, 196, 189, 118, 22, 113, 8, 228, 73, 153, 120, 79, 67, 239, 1, 157, 234, 244, 15, 42, 169, 62, 225, 116, 222, 159, 34, 198, 246, 72, 253, 143, 92, 52, 197, 89, 95, 9, 128, 50, 140, 135, 121, 236, 44, 226, 16, 199, 146, 49, 240, 158, 134, 221, 2, 57, 211, 231, 30, 84, 81, 124, 193, 232, 187, 61, 68, 139, 235, 144, 249, 29, 184, 104, 137, 178, 190, 18, 256, 100, 23, 13, 242, 215, 88, 195, 32, 141, 35, 98, 223, 59, 11, 185, 4, 114, 165, 205, 60, 168, 162, 248, 129, 207, 117, 122, 136, 21, 213, 31, 241, 58, 111, 208, 17, 99, 123, 36, 255, 200, 46, 26, 227, 173, 176, 133, 64, 25, 70, 196, 189, 118, 22, 113, 8, 228, 73, 153, 120, 79, 67, 239, 1], +[1, 158, 35, 133, 197, 29, 213, 244, 2, 59, 70, 9, 137, 58, 169, 231, 4, 118, 140, 18, 17, 116, 81, 205, 8, 236, 23, 36, 34, 232, 162, 153, 16, 215, 46, 72, 68, 207, 67, 49, 32, 173, 92, 144, 136, 157, 134, 98, 64, 89, 184, 31, 15, 57, 11, 196, 128, 178, 111, 62, 30, 114, 22, 135, 256, 99, 222, 124, 60, 228, 44, 13, 255, 198, 187, 248, 120, 199, 88, 26, 253, 139, 117, 239, 240, 141, 176, 52, 249, 21, 234, 221, 223, 25, 95, 104, 241, 42, 211, 185, 189, 50, 190, 208, 225, 84, 165, 113, 121, 100, 123, 159, 193, 168, 73, 226, 242, 200, 246, 61, 129, 79, 146, 195, 227, 143, 235, 122, 1, 158, 35, 133, 197, 29, 213, 244, 2, 59, 70, 9, 137, 58, 169, 231, 4, 118, 140, 18, 17, 116, 81, 205, 8, 236, 23, 36, 34, 232, 162, 153, 16, 215, 46, 72, 68, 207, 67, 49, 32, 173, 92, 144, 136, 157, 134, 98, 64, 89, 184, 31, 15, 57, 11, 196, 128, 178, 111, 62, 30, 114, 22, 135, 256, 99, 222, 124, 60, 228, 44, 13, 255, 198, 187, 248, 120, 199, 88, 26, 253, 139, 117, 239, 240, 141, 176, 52, 249, 21, 234, 221, 223, 25, 95, 104, 241, 42, 211, 185, 189, 50, 190, 208, 225, 84, 165, 113, 121, 100, 123, 159, 193, 168, 73, 226, 242, 200, 246, 61, 129, 79, 146, 195, 227, 143, 235, 122, 1], +[1, 159, 95, 199, 30, 144, 23, 59, 129, 208, 176, 228, 15, 72, 140, 158, 193, 104, 88, 114, 136, 36, 70, 79, 225, 52, 44, 57, 68, 18, 35, 168, 241, 26, 22, 157, 34, 9, 146, 84, 249, 13, 11, 207, 17, 133, 73, 42, 253, 135, 134, 232, 137, 195, 165, 21, 255, 196, 67, 116, 197, 226, 211, 139, 256, 98, 162, 58, 227, 113, 234, 198, 128, 49, 81, 29, 242, 185, 117, 99, 64, 153, 169, 143, 121, 221, 187, 178, 32, 205, 213, 200, 189, 239, 222, 89, 16, 231, 235, 100, 223, 248, 111, 173, 8, 244, 246, 50, 240, 124, 184, 215, 4, 122, 123, 25, 120, 62, 92, 236, 2, 61, 190, 141, 60, 31, 46, 118, 1, 159, 95, 199, 30, 144, 23, 59, 129, 208, 176, 228, 15, 72, 140, 158, 193, 104, 88, 114, 136, 36, 70, 79, 225, 52, 44, 57, 68, 18, 35, 168, 241, 26, 22, 157, 34, 9, 146, 84, 249, 13, 11, 207, 17, 133, 73, 42, 253, 135, 134, 232, 137, 195, 165, 21, 255, 196, 67, 116, 197, 226, 211, 139, 256, 98, 162, 58, 227, 113, 234, 198, 128, 49, 81, 29, 242, 185, 117, 99, 64, 153, 169, 143, 121, 221, 187, 178, 32, 205, 213, 200, 189, 239, 222, 89, 16, 231, 235, 100, 223, 248, 111, 173, 8, 244, 246, 50, 240, 124, 184, 215, 4, 122, 123, 25, 120, 62, 92, 236, 2, 61, 190, 141, 60, 31, 46, 118, 1], +[1, 160, 157, 191, 234, 175, 244, 233, 15, 87, 42, 38, 169, 55, 62, 154, 225, 20, 116, 56, 222, 54, 159, 254, 34, 43, 198, 69, 246, 39, 72, 212, 253, 131, 143, 7, 92, 71, 52, 96, 197, 166, 89, 105, 95, 37, 9, 155, 128, 177, 50, 33, 140, 41, 135, 12, 121, 85, 236, 238, 44, 101, 226, 180, 16, 247, 199, 229, 146, 230, 49, 130, 240, 107, 158, 94, 134, 109, 221, 151, 2, 63, 57, 125, 211, 93, 231, 209, 30, 174, 84, 76, 81, 110, 124, 51, 193, 40, 232, 112, 187, 108, 61, 251, 68, 86, 139, 138, 235, 78, 144, 167, 249, 5, 29, 14, 184, 142, 104, 192, 137, 75, 178, 210, 190, 74, 18, 53, 256, 97, 100, 66, 23, 82, 13, 24, 242, 170, 215, 219, 88, 202, 195, 103, 32, 237, 141, 201, 35, 203, 98, 3, 223, 214, 59, 188, 11, 218, 185, 45, 4, 126, 114, 250, 165, 186, 205, 161, 60, 91, 168, 152, 162, 220, 248, 102, 129, 80, 207, 224, 117, 216, 122, 245, 136, 172, 21, 19, 213, 156, 31, 77, 241, 10, 58, 28, 111, 27, 208, 127, 17, 150, 99, 163, 123, 148, 36, 106, 255, 194, 200, 132, 46, 164, 26, 48, 227, 83, 173, 181, 176, 147, 133, 206, 64, 217, 25, 145, 70, 149, 196, 6, 189, 171, 118, 119, 22, 179, 113, 90, 8, 252, 228, 243, 73, 115, 153, 65, 120, 182, 79, 47, 67, 183, 239, 204, 1], +[1, 161, 221, 115, 11, 229, 118, 237, 121, 206, 13, 37, 46, 210, 143, 150, 249, 254, 31, 108, 169, 224, 84, 160, 60, 151, 153, 218, 146, 119, 141, 85, 64, 24, 9, 164, 190, 7, 99, 5, 34, 77, 61, 55, 117, 76, 157, 91, 2, 65, 185, 230, 22, 201, 236, 217, 242, 155, 26, 74, 92, 163, 29, 43, 241, 251, 62, 216, 81, 191, 168, 63, 120, 45, 49, 179, 35, 238, 25, 170, 128, 48, 18, 71, 123, 14, 198, 10, 68, 154, 122, 110, 234, 152, 57, 182, 4, 130, 113, 203, 44, 145, 215, 177, 227, 53, 52, 148, 184, 69, 58, 86, 225, 245, 124, 175, 162, 125, 79, 126, 240, 90, 98, 101, 70, 219, 50, 83, 256, 96, 36, 142, 246, 28, 139, 20, 136, 51, 244, 220, 211, 47, 114, 107, 8, 3, 226, 149, 88, 33, 173, 97, 197, 106, 104, 39, 111, 138, 116, 172, 193, 233, 248, 93, 67, 250, 158, 252, 223, 180, 196, 202, 140, 181, 100, 166, 255, 192, 72, 27, 235, 56, 21, 40, 15, 102, 231, 183, 165, 94, 228, 214, 16, 6, 195, 41, 176, 66, 89, 194, 137, 212, 208, 78, 222, 19, 232, 87, 129, 209, 239, 186, 134, 243, 59, 247, 189, 103, 135, 147, 23, 105, 200, 75, 253, 127, 144, 54, 213, 112, 42, 80, 30, 204, 205, 109, 73, 188, 199, 171, 32, 12, 133, 82, 95, 132, 178, 131, 17, 167, 159, 156, 187, 38, 207, 174, 1], +[1, 162, 30, 234, 129, 81, 15, 117, 193, 169, 136, 187, 225, 213, 68, 222, 241, 235, 34, 111, 249, 246, 17, 184, 253, 123, 137, 92, 255, 190, 197, 46, 256, 95, 227, 23, 128, 176, 242, 140, 64, 88, 121, 70, 32, 44, 189, 35, 16, 22, 223, 146, 8, 11, 240, 73, 4, 134, 120, 165, 2, 67, 60, 211, 1, 162, 30, 234, 129, 81, 15, 117, 193, 169, 136, 187, 225, 213, 68, 222, 241, 235, 34, 111, 249, 246, 17, 184, 253, 123, 137, 92, 255, 190, 197, 46, 256, 95, 227, 23, 128, 176, 242, 140, 64, 88, 121, 70, 32, 44, 189, 35, 16, 22, 223, 146, 8, 11, 240, 73, 4, 134, 120, 165, 2, 67, 60, 211, 1, 162, 30, 234, 129, 81, 15, 117, 193, 169, 136, 187, 225, 213, 68, 222, 241, 235, 34, 111, 249, 246, 17, 184, 253, 123, 137, 92, 255, 190, 197, 46, 256, 95, 227, 23, 128, 176, 242, 140, 64, 88, 121, 70, 32, 44, 189, 35, 16, 22, 223, 146, 8, 11, 240, 73, 4, 134, 120, 165, 2, 67, 60, 211, 1, 162, 30, 234, 129, 81, 15, 117, 193, 169, 136, 187, 225, 213, 68, 222, 241, 235, 34, 111, 249, 246, 17, 184, 253, 123, 137, 92, 255, 190, 197, 46, 256, 95, 227, 23, 128, 176, 242, 140, 64, 88, 121, 70, 32, 44, 189, 35, 16, 22, 223, 146, 8, 11, 240, 73, 4, 134, 120, 165, 2, 67, 60, 211, 1], +[1, 163, 98, 40, 95, 65, 58, 202, 30, 7, 113, 172, 23, 151, 198, 149, 129, 210, 49, 20, 176, 161, 29, 101, 15, 132, 185, 86, 140, 204, 99, 203, 193, 105, 153, 10, 88, 209, 143, 179, 136, 66, 221, 43, 70, 102, 178, 230, 225, 181, 205, 5, 44, 233, 200, 218, 68, 33, 239, 150, 35, 51, 89, 115, 241, 219, 231, 131, 22, 245, 100, 109, 34, 145, 248, 75, 146, 154, 173, 186, 249, 238, 244, 194, 11, 251, 50, 183, 17, 201, 124, 166, 73, 77, 215, 93, 253, 119, 122, 97, 134, 254, 25, 220, 137, 229, 62, 83, 165, 167, 236, 175, 255, 188, 61, 177, 67, 127, 141, 110, 197, 243, 31, 170, 211, 212, 118, 216, 256, 94, 159, 217, 162, 192, 199, 55, 227, 250, 144, 85, 234, 106, 59, 108, 128, 47, 208, 237, 81, 96, 228, 156, 242, 125, 72, 171, 117, 53, 158, 54, 64, 152, 104, 247, 169, 48, 114, 78, 121, 191, 36, 214, 187, 155, 79, 27, 32, 76, 52, 252, 213, 24, 57, 39, 189, 224, 18, 107, 222, 206, 168, 142, 16, 38, 26, 126, 235, 12, 157, 148, 223, 112, 9, 182, 111, 103, 84, 71, 8, 19, 13, 63, 246, 6, 207, 74, 240, 56, 133, 91, 184, 180, 42, 164, 4, 138, 135, 160, 123, 3, 232, 37, 120, 28, 195, 174, 92, 90, 21, 82, 2, 69, 196, 80, 190, 130, 116, 147, 60, 14, 226, 87, 46, 45, 139, 41, 1], +[1, 164, 168, 53, 211, 166, 239, 132, 60, 74, 57, 96, 67, 194, 205, 210, 2, 71, 79, 106, 165, 75, 221, 7, 120, 148, 114, 192, 134, 131, 153, 163, 4, 142, 158, 212, 73, 150, 185, 14, 240, 39, 228, 127, 11, 5, 49, 69, 8, 27, 59, 167, 146, 43, 113, 28, 223, 78, 199, 254, 22, 10, 98, 138, 16, 54, 118, 77, 35, 86, 226, 56, 189, 156, 141, 251, 44, 20, 196, 19, 32, 108, 236, 154, 70, 172, 195, 112, 121, 55, 25, 245, 88, 40, 135, 38, 64, 216, 215, 51, 140, 87, 133, 224, 242, 110, 50, 233, 176, 80, 13, 76, 128, 175, 173, 102, 23, 174, 9, 191, 227, 220, 100, 209, 95, 160, 26, 152, 256, 93, 89, 204, 46, 91, 18, 125, 197, 183, 200, 161, 190, 63, 52, 47, 255, 186, 178, 151, 92, 182, 36, 250, 137, 109, 143, 65, 123, 126, 104, 94, 253, 115, 99, 45, 184, 107, 72, 243, 17, 218, 29, 130, 246, 252, 208, 188, 249, 230, 198, 90, 111, 214, 144, 229, 34, 179, 58, 3, 235, 247, 159, 119, 241, 203, 139, 180, 222, 171, 31, 201, 68, 101, 116, 6, 213, 237, 61, 238, 225, 149, 21, 103, 187, 85, 62, 145, 136, 202, 232, 12, 169, 217, 122, 219, 193, 41, 42, 206, 117, 170, 124, 33, 15, 147, 207, 24, 81, 177, 244, 181, 129, 82, 84, 155, 234, 83, 248, 66, 30, 37, 157, 48, 162, 97, 231, 105, 1], +[1, 165, 240, 22, 32, 140, 227, 190, 253, 111, 68, 169, 129, 211, 120, 11, 16, 70, 242, 95, 255, 184, 34, 213, 193, 234, 60, 134, 8, 35, 121, 176, 256, 92, 17, 235, 225, 117, 30, 67, 4, 146, 189, 88, 128, 46, 137, 246, 241, 187, 15, 162, 2, 73, 223, 44, 64, 23, 197, 123, 249, 222, 136, 81, 1, 165, 240, 22, 32, 140, 227, 190, 253, 111, 68, 169, 129, 211, 120, 11, 16, 70, 242, 95, 255, 184, 34, 213, 193, 234, 60, 134, 8, 35, 121, 176, 256, 92, 17, 235, 225, 117, 30, 67, 4, 146, 189, 88, 128, 46, 137, 246, 241, 187, 15, 162, 2, 73, 223, 44, 64, 23, 197, 123, 249, 222, 136, 81, 1, 165, 240, 22, 32, 140, 227, 190, 253, 111, 68, 169, 129, 211, 120, 11, 16, 70, 242, 95, 255, 184, 34, 213, 193, 234, 60, 134, 8, 35, 121, 176, 256, 92, 17, 235, 225, 117, 30, 67, 4, 146, 189, 88, 128, 46, 137, 246, 241, 187, 15, 162, 2, 73, 223, 44, 64, 23, 197, 123, 249, 222, 136, 81, 1, 165, 240, 22, 32, 140, 227, 190, 253, 111, 68, 169, 129, 211, 120, 11, 16, 70, 242, 95, 255, 184, 34, 213, 193, 234, 60, 134, 8, 35, 121, 176, 256, 92, 17, 235, 225, 117, 30, 67, 4, 146, 189, 88, 128, 46, 137, 246, 241, 187, 15, 162, 2, 73, 223, 44, 64, 23, 197, 123, 249, 222, 136, 81, 1], +[1, 166, 57, 210, 165, 148, 153, 212, 240, 5, 59, 28, 22, 54, 226, 251, 32, 172, 25, 38, 140, 110, 13, 102, 227, 160, 89, 125, 190, 186, 36, 65, 253, 107, 29, 188, 111, 179, 159, 180, 68, 237, 21, 145, 169, 41, 124, 24, 129, 83, 157, 105, 211, 74, 205, 106, 120, 131, 158, 14, 11, 27, 113, 254, 16, 86, 141, 19, 70, 55, 135, 51, 242, 80, 173, 191, 95, 93, 18, 161, 255, 182, 143, 94, 184, 218, 208, 90, 34, 247, 139, 201, 213, 149, 62, 12, 193, 170, 207, 181, 234, 37, 231, 53, 60, 194, 79, 7, 134, 142, 185, 127, 8, 43, 199, 138, 35, 156, 196, 154, 121, 40, 215, 224, 176, 175, 9, 209, 256, 91, 200, 47, 92, 109, 104, 45, 17, 252, 198, 229, 235, 203, 31, 6, 225, 85, 232, 219, 117, 147, 244, 155, 30, 97, 168, 132, 67, 71, 221, 192, 4, 150, 228, 69, 146, 78, 98, 77, 189, 20, 236, 112, 88, 216, 133, 233, 128, 174, 100, 152, 46, 183, 52, 151, 137, 126, 99, 243, 246, 230, 144, 3, 241, 171, 116, 238, 187, 202, 122, 206, 15, 177, 84, 66, 162, 164, 239, 96, 2, 75, 114, 163, 73, 39, 49, 167, 223, 10, 118, 56, 44, 108, 195, 245, 64, 87, 50, 76, 23, 220, 26, 204, 197, 63, 178, 250, 123, 115, 72, 130, 249, 214, 58, 119, 222, 101, 61, 103, 136, 217, 42, 33, 81, 82, 248, 48, 1], +[1, 167, 133, 109, 213, 105, 59, 87, 137, 6, 231, 27, 140, 250, 116, 97, 8, 51, 36, 101, 162, 69, 215, 182, 68, 48, 49, 216, 92, 201, 157, 5, 64, 151, 31, 37, 11, 38, 178, 171, 30, 127, 135, 186, 222, 66, 228, 40, 255, 180, 248, 39, 88, 47, 139, 83, 240, 245, 52, 203, 234, 14, 25, 63, 241, 155, 185, 55, 190, 119, 84, 150, 121, 161, 159, 82, 73, 112, 200, 247, 129, 212, 195, 183, 235, 181, 158, 172, 197, 3, 244, 142, 70, 125, 58, 177, 4, 154, 18, 179, 81, 163, 236, 91, 34, 24, 153, 108, 46, 229, 207, 131, 32, 204, 144, 147, 134, 19, 89, 214, 15, 192, 196, 93, 111, 33, 114, 20, 256, 90, 124, 148, 44, 152, 198, 170, 120, 251, 26, 230, 117, 7, 141, 160, 249, 206, 221, 156, 95, 188, 42, 75, 189, 209, 208, 41, 165, 56, 100, 252, 193, 106, 226, 220, 246, 219, 79, 86, 227, 130, 122, 71, 35, 191, 29, 217, 2, 77, 9, 218, 169, 210, 118, 174, 17, 12, 205, 54, 23, 243, 232, 194, 16, 102, 72, 202, 67, 138, 173, 107, 136, 96, 98, 175, 184, 145, 57, 10, 128, 45, 62, 74, 22, 76, 99, 85, 60, 254, 13, 115, 187, 132, 199, 80, 253, 103, 239, 78, 176, 94, 21, 166, 223, 233, 104, 149, 211, 28, 50, 126, 225, 53, 113, 110, 123, 238, 168, 43, 242, 65, 61, 164, 146, 224, 143, 237, 1], +[1, 168, 211, 239, 60, 57, 67, 205, 2, 79, 165, 221, 120, 114, 134, 153, 4, 158, 73, 185, 240, 228, 11, 49, 8, 59, 146, 113, 223, 199, 22, 98, 16, 118, 35, 226, 189, 141, 44, 196, 32, 236, 70, 195, 121, 25, 88, 135, 64, 215, 140, 133, 242, 50, 176, 13, 128, 173, 23, 9, 227, 100, 95, 26, 256, 89, 46, 18, 197, 200, 190, 52, 255, 178, 92, 36, 137, 143, 123, 104, 253, 99, 184, 72, 17, 29, 246, 208, 249, 198, 111, 144, 34, 58, 235, 159, 241, 139, 222, 31, 68, 116, 213, 61, 225, 21, 187, 62, 136, 232, 169, 122, 193, 42, 117, 124, 15, 207, 81, 244, 129, 84, 234, 248, 30, 157, 162, 231, 1, 168, 211, 239, 60, 57, 67, 205, 2, 79, 165, 221, 120, 114, 134, 153, 4, 158, 73, 185, 240, 228, 11, 49, 8, 59, 146, 113, 223, 199, 22, 98, 16, 118, 35, 226, 189, 141, 44, 196, 32, 236, 70, 195, 121, 25, 88, 135, 64, 215, 140, 133, 242, 50, 176, 13, 128, 173, 23, 9, 227, 100, 95, 26, 256, 89, 46, 18, 197, 200, 190, 52, 255, 178, 92, 36, 137, 143, 123, 104, 253, 99, 184, 72, 17, 29, 246, 208, 249, 198, 111, 144, 34, 58, 235, 159, 241, 139, 222, 31, 68, 116, 213, 61, 225, 21, 187, 62, 136, 232, 169, 122, 193, 42, 117, 124, 15, 207, 81, 244, 129, 84, 234, 248, 30, 157, 162, 231, 1], +[1, 169, 34, 92, 128, 44, 240, 211, 193, 235, 137, 23, 32, 11, 60, 117, 241, 123, 227, 70, 8, 67, 15, 222, 253, 95, 121, 146, 2, 81, 68, 184, 256, 88, 223, 165, 129, 213, 17, 46, 64, 22, 120, 234, 225, 246, 197, 140, 16, 134, 30, 187, 249, 190, 242, 35, 4, 162, 136, 111, 255, 176, 189, 73, 1, 169, 34, 92, 128, 44, 240, 211, 193, 235, 137, 23, 32, 11, 60, 117, 241, 123, 227, 70, 8, 67, 15, 222, 253, 95, 121, 146, 2, 81, 68, 184, 256, 88, 223, 165, 129, 213, 17, 46, 64, 22, 120, 234, 225, 246, 197, 140, 16, 134, 30, 187, 249, 190, 242, 35, 4, 162, 136, 111, 255, 176, 189, 73, 1, 169, 34, 92, 128, 44, 240, 211, 193, 235, 137, 23, 32, 11, 60, 117, 241, 123, 227, 70, 8, 67, 15, 222, 253, 95, 121, 146, 2, 81, 68, 184, 256, 88, 223, 165, 129, 213, 17, 46, 64, 22, 120, 234, 225, 246, 197, 140, 16, 134, 30, 187, 249, 190, 242, 35, 4, 162, 136, 111, 255, 176, 189, 73, 1, 169, 34, 92, 128, 44, 240, 211, 193, 235, 137, 23, 32, 11, 60, 117, 241, 123, 227, 70, 8, 67, 15, 222, 253, 95, 121, 146, 2, 81, 68, 184, 256, 88, 223, 165, 129, 213, 17, 46, 64, 22, 120, 234, 225, 246, 197, 140, 16, 134, 30, 187, 249, 190, 242, 35, 4, 162, 136, 111, 255, 176, 189, 73, 1], +[1, 170, 116, 188, 92, 220, 135, 77, 240, 194, 84, 145, 235, 115, 18, 233, 32, 43, 114, 105, 117, 101, 208, 151, 227, 40, 118, 14, 67, 82, 62, 3, 253, 91, 50, 19, 146, 148, 231, 206, 68, 252, 178, 191, 88, 54, 185, 96, 129, 85, 58, 94, 46, 110, 196, 167, 120, 97, 42, 201, 246, 186, 9, 245, 16, 150, 57, 181, 187, 179, 104, 204, 242, 20, 59, 7, 162, 41, 31, 130, 255, 174, 25, 138, 73, 74, 244, 103, 34, 126, 89, 224, 44, 27, 221, 48, 193, 171, 29, 47, 23, 55, 98, 212, 60, 177, 21, 229, 123, 93, 133, 251, 8, 75, 157, 219, 222, 218, 52, 102, 121, 10, 158, 132, 81, 149, 144, 65, 256, 87, 141, 69, 165, 37, 122, 180, 17, 63, 173, 112, 22, 142, 239, 24, 225, 214, 143, 152, 140, 156, 49, 106, 30, 217, 139, 243, 190, 175, 195, 254, 4, 166, 207, 238, 111, 109, 26, 51, 189, 5, 79, 66, 169, 203, 72, 161, 128, 172, 199, 163, 211, 147, 61, 90, 137, 160, 215, 56, 11, 71, 248, 12, 241, 107, 200, 76, 70, 78, 153, 53, 15, 237, 198, 250, 95, 216, 226, 127, 2, 83, 232, 119, 184, 183, 13, 154, 223, 131, 168, 33, 213, 230, 36, 209, 64, 86, 228, 210, 234, 202, 159, 45, 197, 80, 236, 28, 134, 164, 124, 6, 249, 182, 100, 38, 35, 39, 205, 155, 136, 247, 99, 125, 176, 108, 113, 192, 1], +[1, 171, 200, 19, 165, 202, 104, 51, 240, 177, 198, 191, 22, 164, 31, 161, 32, 75, 232, 94, 140, 39, 244, 90, 227, 10, 168, 201, 190, 108, 221, 12, 253, 87, 228, 181, 111, 220, 98, 53, 68, 63, 236, 7, 169, 115, 133, 127, 129, 214, 100, 138, 211, 101, 52, 154, 120, 217, 99, 224, 11, 82, 144, 209, 16, 166, 116, 47, 70, 148, 122, 45, 242, 5, 84, 229, 95, 54, 239, 6, 255, 172, 114, 219, 184, 110, 49, 155, 34, 160, 118, 132, 213, 186, 195, 192, 193, 107, 50, 69, 234, 179, 26, 77, 60, 237, 178, 112, 134, 41, 72, 233, 8, 83, 58, 152, 35, 74, 61, 151, 121, 131, 42, 243, 176, 27, 248, 3, 256, 86, 57, 238, 92, 55, 153, 206, 17, 80, 59, 66, 235, 93, 226, 96, 225, 182, 25, 163, 117, 218, 13, 167, 30, 247, 89, 56, 67, 149, 36, 245, 4, 170, 29, 76, 146, 37, 159, 204, 189, 194, 21, 250, 88, 142, 124, 130, 128, 43, 157, 119, 46, 156, 205, 103, 137, 40, 158, 33, 246, 175, 113, 48, 241, 91, 141, 210, 187, 109, 135, 212, 15, 252, 173, 28, 162, 203, 18, 251, 2, 85, 143, 38, 73, 147, 208, 102, 223, 97, 139, 125, 44, 71, 62, 65, 64, 150, 207, 188, 23, 78, 231, 180, 197, 20, 79, 145, 123, 216, 185, 24, 249, 174, 199, 105, 222, 183, 196, 106, 136, 126, 215, 14, 81, 230, 9, 254, 1], +[1, 172, 29, 105, 70, 218, 231, 154, 17, 97, 236, 243, 162, 108, 72, 48, 32, 107, 157, 19, 184, 37, 196, 45, 30, 20, 99, 66, 44, 115, 248, 251, 253, 83, 141, 94, 234, 156, 104, 155, 189, 126, 84, 56, 123, 82, 226, 65, 129, 86, 143, 181, 35, 109, 244, 77, 137, 177, 118, 250, 81, 54, 36, 24, 16, 182, 207, 138, 92, 147, 98, 151, 15, 10, 178, 33, 22, 186, 124, 254, 255, 170, 199, 47, 117, 78, 52, 206, 223, 63, 42, 28, 190, 41, 113, 161, 193, 43, 200, 219, 146, 183, 122, 167, 197, 217, 59, 125, 169, 27, 18, 12, 8, 91, 232, 69, 46, 202, 49, 204, 136, 5, 89, 145, 11, 93, 62, 127, 256, 85, 228, 152, 187, 39, 26, 103, 240, 160, 21, 14, 95, 149, 185, 209, 225, 150, 100, 238, 73, 220, 61, 212, 227, 237, 158, 191, 213, 142, 9, 6, 4, 174, 116, 163, 23, 101, 153, 102, 68, 131, 173, 201, 134, 175, 31, 192, 128, 171, 114, 76, 222, 148, 13, 180, 120, 80, 139, 7, 176, 203, 221, 233, 241, 75, 50, 119, 165, 110, 159, 106, 242, 247, 79, 224, 235, 71, 133, 3, 2, 87, 58, 210, 140, 179, 205, 51, 34, 194, 215, 229, 67, 216, 144, 96, 64, 214, 57, 38, 111, 74, 135, 90, 60, 40, 198, 132, 88, 230, 239, 245, 249, 166, 25, 188, 211, 55, 208, 53, 121, 252, 168, 112, 246, 164, 195, 130, 1], +[1, 173, 117, 195, 68, 199, 246, 153, 255, 168, 23, 124, 121, 116, 22, 208, 4, 178, 211, 9, 15, 25, 213, 98, 249, 158, 92, 239, 227, 207, 88, 61, 16, 198, 73, 36, 60, 100, 81, 135, 225, 118, 111, 185, 137, 57, 95, 244, 64, 21, 35, 144, 240, 143, 67, 26, 129, 215, 187, 226, 34, 228, 123, 205, 256, 84, 140, 62, 189, 58, 11, 104, 2, 89, 234, 133, 136, 141, 235, 49, 253, 79, 46, 248, 242, 232, 44, 159, 8, 99, 165, 18, 30, 50, 169, 196, 241, 59, 184, 221, 197, 157, 176, 122, 32, 139, 146, 72, 120, 200, 162, 13, 193, 236, 222, 113, 17, 114, 190, 231, 128, 42, 70, 31, 223, 29, 134, 52, 1, 173, 117, 195, 68, 199, 246, 153, 255, 168, 23, 124, 121, 116, 22, 208, 4, 178, 211, 9, 15, 25, 213, 98, 249, 158, 92, 239, 227, 207, 88, 61, 16, 198, 73, 36, 60, 100, 81, 135, 225, 118, 111, 185, 137, 57, 95, 244, 64, 21, 35, 144, 240, 143, 67, 26, 129, 215, 187, 226, 34, 228, 123, 205, 256, 84, 140, 62, 189, 58, 11, 104, 2, 89, 234, 133, 136, 141, 235, 49, 253, 79, 46, 248, 242, 232, 44, 159, 8, 99, 165, 18, 30, 50, 169, 196, 241, 59, 184, 221, 197, 157, 176, 122, 32, 139, 146, 72, 120, 200, 162, 13, 193, 236, 222, 113, 17, 114, 190, 231, 128, 42, 70, 31, 223, 29, 134, 52, 1], +[1, 174, 207, 38, 187, 156, 159, 167, 17, 131, 178, 132, 95, 82, 133, 12, 32, 171, 199, 188, 73, 109, 205, 204, 30, 80, 42, 112, 213, 54, 144, 127, 253, 75, 200, 105, 23, 147, 135, 103, 189, 247, 59, 243, 134, 186, 239, 209, 129, 87, 232, 19, 222, 78, 208, 212, 137, 194, 89, 66, 176, 41, 195, 6, 16, 214, 228, 94, 165, 183, 231, 102, 15, 40, 21, 56, 235, 27, 72, 192, 255, 166, 100, 181, 140, 202, 196, 180, 223, 252, 158, 250, 67, 93, 248, 233, 193, 172, 116, 138, 111, 39, 104, 106, 197, 97, 173, 33, 88, 149, 226, 3, 8, 107, 114, 47, 211, 220, 244, 51, 136, 20, 139, 28, 246, 142, 36, 96, 256, 83, 50, 219, 70, 101, 98, 90, 240, 126, 79, 125, 162, 175, 124, 245, 225, 86, 58, 69, 184, 148, 52, 53, 227, 177, 215, 145, 44, 203, 113, 130, 4, 182, 57, 152, 234, 110, 122, 154, 68, 10, 198, 14, 123, 71, 18, 48, 128, 170, 25, 238, 35, 179, 49, 45, 120, 63, 168, 191, 81, 216, 62, 251, 241, 43, 29, 163, 92, 74, 26, 155, 242, 217, 236, 201, 22, 230, 185, 65, 2, 91, 157, 76, 117, 55, 61, 77, 34, 5, 99, 7, 190, 164, 9, 24, 64, 85, 141, 119, 146, 218, 153, 151, 60, 160, 84, 224, 169, 108, 31, 254, 249, 150, 143, 210, 46, 37, 13, 206, 121, 237, 118, 229, 11, 115, 221, 161, 1], +[1, 175, 42, 154, 222, 43, 72, 7, 197, 37, 50, 12, 44, 247, 49, 94, 2, 93, 84, 51, 187, 86, 144, 14, 137, 74, 100, 24, 88, 237, 98, 188, 4, 186, 168, 102, 117, 172, 31, 28, 17, 148, 200, 48, 176, 217, 196, 119, 8, 115, 79, 204, 234, 87, 62, 56, 34, 39, 143, 96, 95, 177, 135, 238, 16, 230, 158, 151, 211, 174, 124, 112, 68, 78, 29, 192, 190, 97, 13, 219, 32, 203, 59, 45, 165, 91, 248, 224, 136, 156, 58, 127, 123, 194, 26, 181, 64, 149, 118, 90, 73, 182, 239, 191, 15, 55, 116, 254, 246, 131, 52, 105, 128, 41, 236, 180, 146, 107, 221, 125, 30, 110, 232, 251, 235, 5, 104, 210, 256, 82, 215, 103, 35, 214, 185, 250, 60, 220, 207, 245, 213, 10, 208, 163, 255, 164, 173, 206, 70, 171, 113, 243, 120, 183, 157, 233, 169, 20, 159, 69, 253, 71, 89, 155, 140, 85, 226, 229, 240, 109, 57, 209, 81, 40, 61, 138, 249, 142, 178, 53, 23, 170, 195, 201, 223, 218, 114, 161, 162, 80, 122, 19, 241, 27, 99, 106, 46, 83, 133, 145, 189, 179, 228, 65, 67, 160, 244, 38, 225, 54, 198, 212, 92, 166, 9, 33, 121, 101, 199, 130, 134, 63, 231, 76, 193, 108, 139, 167, 184, 75, 18, 66, 242, 202, 141, 3, 11, 126, 205, 152, 129, 216, 21, 77, 111, 150, 36, 132, 227, 147, 25, 6, 22, 252, 153, 47, 1], +[1, 176, 136, 35, 249, 134, 197, 234, 64, 213, 223, 184, 2, 95, 15, 70, 241, 11, 137, 211, 128, 169, 189, 111, 4, 190, 30, 140, 225, 22, 17, 165, 256, 81, 121, 222, 8, 123, 60, 23, 193, 44, 34, 73, 255, 162, 242, 187, 16, 246, 120, 46, 129, 88, 68, 146, 253, 67, 227, 117, 32, 235, 240, 92, 1, 176, 136, 35, 249, 134, 197, 234, 64, 213, 223, 184, 2, 95, 15, 70, 241, 11, 137, 211, 128, 169, 189, 111, 4, 190, 30, 140, 225, 22, 17, 165, 256, 81, 121, 222, 8, 123, 60, 23, 193, 44, 34, 73, 255, 162, 242, 187, 16, 246, 120, 46, 129, 88, 68, 146, 253, 67, 227, 117, 32, 235, 240, 92, 1, 176, 136, 35, 249, 134, 197, 234, 64, 213, 223, 184, 2, 95, 15, 70, 241, 11, 137, 211, 128, 169, 189, 111, 4, 190, 30, 140, 225, 22, 17, 165, 256, 81, 121, 222, 8, 123, 60, 23, 193, 44, 34, 73, 255, 162, 242, 187, 16, 246, 120, 46, 129, 88, 68, 146, 253, 67, 227, 117, 32, 235, 240, 92, 1, 176, 136, 35, 249, 134, 197, 234, 64, 213, 223, 184, 2, 95, 15, 70, 241, 11, 137, 211, 128, 169, 189, 111, 4, 190, 30, 140, 225, 22, 17, 165, 256, 81, 121, 222, 8, 123, 60, 23, 193, 44, 34, 73, 255, 162, 242, 187, 16, 246, 120, 46, 129, 88, 68, 146, 253, 67, 227, 117, 32, 235, 240, 92, 1], +[1, 177, 232, 201, 111, 115, 52, 209, 242, 172, 118, 69, 134, 74, 248, 206, 225, 247, 29, 250, 46, 175, 135, 251, 223, 150, 79, 105, 81, 202, 31, 90, 253, 63, 100, 224, 70, 54, 49, 192, 60, 83, 42, 238, 235, 218, 36, 204, 128, 40, 141, 28, 73, 71, 231, 24, 136, 171, 198, 94, 190, 220, 133, 154, 16, 5, 114, 132, 234, 41, 61, 3, 17, 182, 89, 76, 88, 156, 113, 212, 2, 97, 207, 145, 222, 230, 104, 161, 227, 87, 236, 138, 11, 148, 239, 155, 193, 237, 58, 243, 92, 93, 13, 245, 189, 43, 158, 210, 162, 147, 62, 180, 249, 126, 200, 191, 140, 108, 98, 127, 120, 166, 84, 219, 213, 179, 72, 151, 256, 80, 25, 56, 146, 142, 205, 48, 15, 85, 139, 188, 123, 183, 9, 51, 32, 10, 228, 7, 211, 82, 122, 6, 34, 107, 178, 152, 176, 55, 226, 167, 4, 194, 157, 33, 187, 203, 208, 65, 197, 174, 215, 19, 22, 39, 221, 53, 129, 217, 116, 229, 184, 186, 26, 233, 121, 86, 59, 163, 67, 37, 124, 103, 241, 252, 143, 125, 23, 216, 196, 254, 240, 75, 168, 181, 169, 101, 144, 45, 255, 160, 50, 112, 35, 27, 153, 96, 30, 170, 21, 119, 246, 109, 18, 102, 64, 20, 199, 14, 165, 164, 244, 12, 68, 214, 99, 47, 95, 110, 195, 77, 8, 131, 57, 66, 117, 149, 159, 130, 137, 91, 173, 38, 44, 78, 185, 106, 1], +[1, 178, 73, 144, 189, 232, 176, 231, 255, 158, 111, 226, 136, 50, 162, 52, 4, 198, 35, 62, 242, 157, 190, 153, 249, 118, 187, 133, 30, 200, 134, 208, 16, 21, 140, 248, 197, 114, 246, 98, 225, 215, 234, 18, 120, 29, 22, 61, 64, 84, 46, 221, 17, 199, 213, 135, 129, 89, 165, 72, 223, 116, 88, 244, 256, 79, 184, 113, 68, 25, 81, 26, 2, 99, 146, 31, 121, 207, 95, 205, 253, 59, 222, 195, 15, 100, 67, 104, 8, 139, 70, 124, 227, 57, 123, 49, 241, 236, 117, 9, 60, 143, 11, 159, 32, 42, 23, 239, 137, 228, 235, 196, 193, 173, 211, 36, 240, 58, 44, 122, 128, 168, 92, 185, 34, 141, 169, 13, 1, 178, 73, 144, 189, 232, 176, 231, 255, 158, 111, 226, 136, 50, 162, 52, 4, 198, 35, 62, 242, 157, 190, 153, 249, 118, 187, 133, 30, 200, 134, 208, 16, 21, 140, 248, 197, 114, 246, 98, 225, 215, 234, 18, 120, 29, 22, 61, 64, 84, 46, 221, 17, 199, 213, 135, 129, 89, 165, 72, 223, 116, 88, 244, 256, 79, 184, 113, 68, 25, 81, 26, 2, 99, 146, 31, 121, 207, 95, 205, 253, 59, 222, 195, 15, 100, 67, 104, 8, 139, 70, 124, 227, 57, 123, 49, 241, 236, 117, 9, 60, 143, 11, 159, 32, 42, 23, 239, 137, 228, 235, 196, 193, 173, 211, 36, 240, 58, 44, 122, 128, 168, 92, 185, 34, 141, 169, 13, 1], +[1, 179, 173, 127, 117, 126, 195, 210, 68, 93, 199, 155, 246, 87, 153, 145, 255, 156, 168, 3, 23, 5, 124, 94, 121, 71, 116, 204, 22, 83, 208, 224, 4, 202, 178, 251, 211, 247, 9, 69, 15, 115, 25, 106, 213, 91, 98, 66, 249, 110, 158, 12, 92, 20, 239, 119, 227, 27, 207, 45, 88, 75, 61, 125, 16, 37, 198, 233, 73, 217, 36, 19, 60, 203, 100, 167, 81, 107, 135, 7, 225, 183, 118, 48, 111, 80, 185, 219, 137, 108, 57, 180, 95, 43, 244, 243, 64, 148, 21, 161, 35, 97, 144, 76, 240, 41, 143, 154, 67, 171, 26, 28, 129, 218, 215, 192, 187, 63, 226, 105, 34, 175, 228, 206, 123, 172, 205, 201, 256, 78, 84, 130, 140, 131, 62, 47, 189, 164, 58, 102, 11, 170, 104, 112, 2, 101, 89, 254, 234, 252, 133, 163, 136, 186, 141, 53, 235, 174, 49, 33, 253, 55, 79, 6, 46, 10, 248, 188, 242, 142, 232, 151, 44, 166, 159, 191, 8, 147, 99, 245, 165, 237, 18, 138, 30, 230, 50, 212, 169, 182, 196, 132, 241, 220, 59, 24, 184, 40, 221, 238, 197, 54, 157, 90, 176, 150, 122, 250, 32, 74, 139, 209, 146, 177, 72, 38, 120, 149, 200, 77, 162, 214, 13, 14, 193, 109, 236, 96, 222, 160, 113, 181, 17, 216, 114, 103, 190, 86, 231, 229, 128, 39, 42, 65, 70, 194, 31, 152, 223, 82, 29, 51, 134, 85, 52, 56, 1], +[1, 180, 18, 156, 67, 238, 178, 172, 120, 12, 104, 216, 73, 33, 29, 80, 8, 155, 144, 220, 22, 105, 139, 91, 189, 96, 61, 186, 70, 7, 232, 126, 64, 212, 124, 218, 176, 69, 84, 214, 227, 254, 231, 203, 46, 56, 57, 237, 255, 154, 221, 202, 123, 38, 158, 170, 17, 233, 49, 82, 111, 191, 199, 97, 241, 204, 226, 74, 213, 47, 236, 75, 136, 65, 135, 142, 117, 243, 50, 5, 129, 90, 9, 78, 162, 119, 89, 86, 60, 6, 52, 108, 165, 145, 143, 40, 4, 206, 72, 110, 11, 181, 198, 174, 223, 48, 159, 93, 35, 132, 116, 63, 32, 106, 62, 109, 88, 163, 42, 107, 242, 127, 244, 230, 23, 28, 157, 247, 256, 77, 239, 101, 190, 19, 79, 85, 137, 245, 153, 41, 184, 224, 228, 177, 249, 102, 113, 37, 235, 152, 118, 166, 68, 161, 196, 71, 187, 250, 25, 131, 193, 45, 133, 39, 81, 188, 173, 43, 30, 3, 26, 54, 211, 201, 200, 20, 2, 103, 36, 55, 134, 219, 99, 87, 240, 24, 208, 175, 146, 66, 58, 160, 16, 53, 31, 183, 44, 210, 21, 182, 121, 192, 122, 115, 140, 14, 207, 252, 128, 167, 248, 179, 95, 138, 168, 171, 197, 251, 205, 149, 92, 112, 114, 217, 253, 51, 185, 147, 246, 76, 59, 83, 34, 209, 98, 164, 222, 125, 141, 194, 225, 151, 195, 148, 169, 94, 215, 150, 15, 130, 13, 27, 234, 229, 100, 10, 1], +[1, 181, 122, 237, 235, 130, 143, 183, 227, 224, 195, 86, 146, 212, 79, 164, 129, 219, 61, 247, 246, 65, 200, 220, 242, 112, 226, 43, 73, 106, 168, 82, 193, 238, 159, 252, 123, 161, 100, 110, 121, 56, 113, 150, 165, 53, 84, 41, 225, 119, 208, 126, 190, 209, 50, 55, 189, 28, 185, 75, 211, 155, 42, 149, 241, 188, 104, 63, 95, 233, 25, 156, 223, 14, 221, 166, 234, 206, 21, 203, 249, 94, 52, 160, 176, 245, 141, 78, 240, 7, 239, 83, 117, 103, 139, 230, 253, 47, 26, 80, 88, 251, 199, 39, 120, 132, 248, 170, 187, 180, 198, 115, 255, 152, 13, 40, 44, 254, 228, 148, 60, 66, 124, 85, 222, 90, 99, 186, 256, 76, 135, 20, 22, 127, 114, 74, 30, 33, 62, 171, 111, 45, 178, 93, 128, 38, 196, 10, 11, 192, 57, 37, 15, 145, 31, 214, 184, 151, 89, 175, 64, 19, 98, 5, 134, 96, 157, 147, 136, 201, 144, 107, 92, 204, 173, 216, 32, 138, 49, 131, 67, 48, 207, 202, 68, 229, 72, 182, 46, 102, 215, 108, 16, 69, 153, 194, 162, 24, 232, 101, 34, 243, 36, 91, 23, 51, 236, 54, 8, 163, 205, 97, 81, 12, 116, 179, 17, 250, 18, 174, 140, 154, 118, 27, 4, 210, 231, 177, 169, 6, 58, 218, 137, 125, 9, 87, 70, 77, 59, 142, 2, 105, 244, 217, 213, 3, 29, 109, 197, 191, 133, 172, 35, 167, 158, 71, 1], +[1, 182, 228, 119, 70, 147, 26, 106, 17, 10, 21, 224, 162, 186, 185, 3, 32, 170, 100, 210, 184, 78, 61, 51, 30, 63, 158, 229, 44, 41, 9, 96, 253, 43, 116, 38, 234, 183, 153, 90, 189, 217, 173, 132, 123, 27, 31, 245, 129, 91, 114, 188, 35, 202, 13, 53, 137, 5, 139, 112, 81, 93, 221, 130, 16, 85, 50, 105, 92, 39, 159, 154, 15, 160, 79, 243, 22, 149, 133, 48, 255, 150, 58, 19, 117, 220, 205, 45, 223, 237, 215, 66, 190, 142, 144, 251, 193, 174, 57, 94, 146, 101, 135, 155, 197, 131, 198, 56, 169, 175, 239, 65, 8, 171, 25, 181, 46, 148, 208, 77, 136, 80, 168, 250, 11, 203, 195, 24, 256, 75, 29, 138, 187, 110, 231, 151, 240, 247, 236, 33, 95, 71, 72, 254, 225, 87, 157, 47, 73, 179, 196, 206, 227, 194, 99, 28, 213, 216, 248, 161, 4, 214, 141, 219, 23, 74, 104, 167, 68, 40, 84, 125, 134, 230, 226, 12, 128, 166, 143, 69, 222, 55, 244, 204, 120, 252, 118, 145, 176, 164, 36, 127, 241, 172, 207, 152, 165, 218, 98, 103, 242, 97, 178, 14, 235, 108, 124, 209, 2, 107, 199, 238, 140, 37, 52, 212, 34, 20, 42, 191, 67, 115, 113, 6, 64, 83, 200, 163, 111, 156, 122, 102, 60, 126, 59, 201, 88, 82, 18, 192, 249, 86, 232, 76, 211, 109, 49, 180, 121, 177, 89, 7, 246, 54, 62, 233, 1], +[1, 183, 79, 65, 73, 252, 113, 119, 189, 149, 25, 206, 176, 83, 26, 132, 255, 148, 99, 127, 111, 10, 31, 19, 136, 216, 207, 102, 162, 91, 205, 250, 4, 218, 59, 3, 35, 237, 195, 219, 242, 82, 100, 53, 190, 75, 104, 14, 249, 78, 139, 251, 187, 40, 124, 76, 30, 93, 57, 151, 134, 107, 49, 229, 16, 101, 236, 12, 140, 177, 9, 105, 197, 71, 143, 212, 246, 43, 159, 56, 225, 55, 42, 233, 234, 160, 239, 47, 120, 115, 228, 90, 22, 171, 196, 145, 64, 147, 173, 48, 46, 194, 36, 163, 17, 27, 58, 77, 213, 172, 122, 224, 129, 220, 168, 161, 165, 126, 185, 188, 223, 203, 141, 103, 88, 170, 13, 66, 256, 74, 178, 192, 184, 5, 144, 138, 68, 108, 232, 51, 81, 174, 231, 125, 2, 109, 158, 130, 146, 247, 226, 238, 121, 41, 50, 155, 95, 166, 52, 7, 253, 39, 198, 254, 222, 20, 62, 38, 15, 175, 157, 204, 67, 182, 153, 243, 8, 179, 118, 6, 70, 217, 133, 181, 227, 164, 200, 106, 123, 150, 208, 28, 241, 156, 21, 245, 117, 80, 248, 152, 60, 186, 114, 45, 11, 214, 98, 201, 32, 202, 215, 24, 23, 97, 18, 210, 137, 142, 29, 167, 235, 86, 61, 112, 193, 110, 84, 209, 211, 63, 221, 94, 240, 230, 199, 180, 44, 85, 135, 33, 128, 37, 89, 96, 92, 131, 72, 69, 34, 54, 116, 154, 169, 87, 244, 191, 1], +[1, 184, 189, 81, 255, 146, 136, 95, 4, 222, 242, 67, 249, 70, 30, 123, 16, 117, 197, 11, 225, 23, 120, 235, 64, 211, 17, 44, 129, 92, 223, 169, 256, 73, 68, 176, 2, 111, 121, 162, 253, 35, 15, 190, 8, 187, 227, 134, 241, 140, 60, 246, 32, 234, 137, 22, 193, 46, 240, 213, 128, 165, 34, 88, 1, 184, 189, 81, 255, 146, 136, 95, 4, 222, 242, 67, 249, 70, 30, 123, 16, 117, 197, 11, 225, 23, 120, 235, 64, 211, 17, 44, 129, 92, 223, 169, 256, 73, 68, 176, 2, 111, 121, 162, 253, 35, 15, 190, 8, 187, 227, 134, 241, 140, 60, 246, 32, 234, 137, 22, 193, 46, 240, 213, 128, 165, 34, 88, 1, 184, 189, 81, 255, 146, 136, 95, 4, 222, 242, 67, 249, 70, 30, 123, 16, 117, 197, 11, 225, 23, 120, 235, 64, 211, 17, 44, 129, 92, 223, 169, 256, 73, 68, 176, 2, 111, 121, 162, 253, 35, 15, 190, 8, 187, 227, 134, 241, 140, 60, 246, 32, 234, 137, 22, 193, 46, 240, 213, 128, 165, 34, 88, 1, 184, 189, 81, 255, 146, 136, 95, 4, 222, 242, 67, 249, 70, 30, 123, 16, 117, 197, 11, 225, 23, 120, 235, 64, 211, 17, 44, 129, 92, 223, 169, 256, 73, 68, 176, 2, 111, 121, 162, 253, 35, 15, 190, 8, 187, 227, 134, 241, 140, 60, 246, 32, 234, 137, 22, 193, 46, 240, 213, 128, 165, 34, 88, 1], +[1, 185, 44, 173, 137, 159, 117, 57, 8, 195, 95, 99, 68, 244, 165, 199, 64, 18, 246, 21, 30, 153, 35, 50, 255, 144, 169, 168, 240, 196, 23, 143, 241, 124, 67, 59, 121, 26, 184, 116, 129, 221, 22, 215, 197, 208, 187, 157, 4, 226, 176, 178, 34, 122, 211, 228, 32, 9, 123, 139, 15, 205, 146, 25, 256, 72, 213, 84, 120, 98, 140, 200, 249, 62, 162, 158, 189, 13, 92, 58, 193, 239, 11, 236, 227, 104, 222, 207, 2, 113, 88, 89, 17, 61, 234, 114, 16, 133, 190, 198, 136, 231, 73, 141, 128, 36, 235, 42, 60, 49, 70, 100, 253, 31, 81, 79, 223, 135, 46, 29, 225, 248, 134, 118, 242, 52, 111, 232, 1, 185, 44, 173, 137, 159, 117, 57, 8, 195, 95, 99, 68, 244, 165, 199, 64, 18, 246, 21, 30, 153, 35, 50, 255, 144, 169, 168, 240, 196, 23, 143, 241, 124, 67, 59, 121, 26, 184, 116, 129, 221, 22, 215, 197, 208, 187, 157, 4, 226, 176, 178, 34, 122, 211, 228, 32, 9, 123, 139, 15, 205, 146, 25, 256, 72, 213, 84, 120, 98, 140, 200, 249, 62, 162, 158, 189, 13, 92, 58, 193, 239, 11, 236, 227, 104, 222, 207, 2, 113, 88, 89, 17, 61, 234, 114, 16, 133, 190, 198, 136, 231, 73, 141, 128, 36, 235, 42, 60, 49, 70, 100, 253, 31, 81, 79, 223, 135, 46, 29, 225, 248, 134, 118, 242, 52, 111, 232, 1], +[1, 186, 158, 90, 35, 85, 133, 66, 197, 148, 29, 254, 213, 40, 244, 152, 2, 115, 59, 180, 70, 170, 9, 132, 137, 39, 58, 251, 169, 80, 231, 47, 4, 230, 118, 103, 140, 83, 18, 7, 17, 78, 116, 245, 81, 160, 205, 94, 8, 203, 236, 206, 23, 166, 36, 14, 34, 156, 232, 233, 162, 63, 153, 188, 16, 149, 215, 155, 46, 75, 72, 28, 68, 55, 207, 209, 67, 126, 49, 119, 32, 41, 173, 53, 92, 150, 144, 56, 136, 110, 157, 161, 134, 252, 98, 238, 64, 82, 89, 106, 184, 43, 31, 112, 15, 220, 57, 65, 11, 247, 196, 219, 128, 164, 178, 212, 111, 86, 62, 224, 30, 183, 114, 130, 22, 237, 135, 181, 256, 71, 99, 167, 222, 172, 124, 191, 60, 109, 228, 3, 44, 217, 13, 105, 255, 142, 198, 77, 187, 87, 248, 125, 120, 218, 199, 6, 88, 177, 26, 210, 253, 27, 139, 154, 117, 174, 239, 250, 240, 179, 141, 12, 176, 97, 52, 163, 249, 54, 21, 51, 234, 91, 221, 243, 223, 101, 25, 24, 95, 194, 104, 69, 241, 108, 42, 102, 211, 182, 185, 229, 189, 202, 50, 48, 190, 131, 208, 138, 225, 216, 84, 204, 165, 107, 113, 201, 121, 147, 100, 96, 123, 5, 159, 19, 193, 175, 168, 151, 73, 214, 226, 145, 242, 37, 200, 192, 246, 10, 61, 38, 129, 93, 79, 45, 146, 171, 195, 33, 227, 74, 143, 127, 235, 20, 122, 76, 1], +[1, 187, 17, 95, 32, 73, 30, 213, 253, 23, 189, 134, 129, 222, 137, 176, 16, 165, 15, 235, 255, 140, 223, 67, 193, 111, 197, 88, 8, 211, 136, 246, 256, 70, 240, 162, 225, 184, 227, 44, 4, 234, 68, 123, 128, 35, 120, 81, 241, 92, 242, 22, 2, 117, 34, 190, 64, 146, 60, 169, 249, 46, 121, 11, 1, 187, 17, 95, 32, 73, 30, 213, 253, 23, 189, 134, 129, 222, 137, 176, 16, 165, 15, 235, 255, 140, 223, 67, 193, 111, 197, 88, 8, 211, 136, 246, 256, 70, 240, 162, 225, 184, 227, 44, 4, 234, 68, 123, 128, 35, 120, 81, 241, 92, 242, 22, 2, 117, 34, 190, 64, 146, 60, 169, 249, 46, 121, 11, 1, 187, 17, 95, 32, 73, 30, 213, 253, 23, 189, 134, 129, 222, 137, 176, 16, 165, 15, 235, 255, 140, 223, 67, 193, 111, 197, 88, 8, 211, 136, 246, 256, 70, 240, 162, 225, 184, 227, 44, 4, 234, 68, 123, 128, 35, 120, 81, 241, 92, 242, 22, 2, 117, 34, 190, 64, 146, 60, 169, 249, 46, 121, 11, 1, 187, 17, 95, 32, 73, 30, 213, 253, 23, 189, 134, 129, 222, 137, 176, 16, 165, 15, 235, 255, 140, 223, 67, 193, 111, 197, 88, 8, 211, 136, 246, 256, 70, 240, 162, 225, 184, 227, 44, 4, 234, 68, 123, 128, 35, 120, 81, 241, 92, 242, 22, 2, 117, 34, 190, 64, 146, 60, 169, 249, 46, 121, 11, 1], +[1, 188, 135, 194, 235, 233, 114, 101, 227, 14, 62, 91, 146, 206, 178, 54, 129, 94, 196, 97, 246, 245, 57, 179, 242, 7, 31, 174, 73, 103, 89, 27, 193, 47, 98, 177, 123, 251, 157, 218, 121, 132, 144, 87, 165, 180, 173, 142, 225, 152, 49, 217, 190, 254, 207, 109, 189, 66, 72, 172, 211, 90, 215, 71, 241, 76, 153, 237, 95, 127, 232, 183, 223, 33, 36, 86, 234, 45, 236, 164, 249, 38, 205, 247, 176, 192, 116, 220, 240, 145, 18, 43, 117, 151, 118, 82, 253, 19, 231, 252, 88, 96, 58, 110, 120, 201, 9, 150, 187, 204, 59, 41, 255, 138, 244, 126, 44, 48, 29, 55, 60, 229, 133, 75, 222, 102, 158, 149, 256, 69, 122, 63, 22, 24, 143, 156, 30, 243, 195, 166, 111, 51, 79, 203, 128, 163, 61, 160, 11, 12, 200, 78, 15, 250, 226, 83, 184, 154, 168, 230, 64, 210, 159, 80, 134, 6, 100, 39, 136, 125, 113, 170, 92, 77, 84, 115, 32, 105, 208, 40, 67, 3, 50, 148, 68, 191, 185, 85, 46, 167, 42, 186, 16, 181, 104, 20, 162, 130, 25, 74, 34, 224, 221, 171, 23, 212, 21, 93, 8, 219, 52, 10, 81, 65, 141, 37, 17, 112, 239, 214, 140, 106, 139, 175, 4, 238, 26, 5, 169, 161, 199, 147, 137, 56, 248, 107, 70, 53, 198, 216, 2, 119, 13, 131, 213, 209, 228, 202, 197, 28, 124, 182, 35, 155, 99, 108, 1], +[1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1], +[1, 190, 120, 184, 8, 235, 189, 187, 64, 81, 227, 211, 255, 134, 17, 146, 241, 44, 136, 140, 129, 95, 60, 92, 4, 246, 223, 222, 32, 169, 242, 234, 256, 67, 137, 73, 249, 22, 68, 70, 193, 176, 30, 46, 2, 123, 240, 111, 16, 213, 121, 117, 128, 162, 197, 165, 253, 11, 34, 35, 225, 88, 15, 23, 1, 190, 120, 184, 8, 235, 189, 187, 64, 81, 227, 211, 255, 134, 17, 146, 241, 44, 136, 140, 129, 95, 60, 92, 4, 246, 223, 222, 32, 169, 242, 234, 256, 67, 137, 73, 249, 22, 68, 70, 193, 176, 30, 46, 2, 123, 240, 111, 16, 213, 121, 117, 128, 162, 197, 165, 253, 11, 34, 35, 225, 88, 15, 23, 1, 190, 120, 184, 8, 235, 189, 187, 64, 81, 227, 211, 255, 134, 17, 146, 241, 44, 136, 140, 129, 95, 60, 92, 4, 246, 223, 222, 32, 169, 242, 234, 256, 67, 137, 73, 249, 22, 68, 70, 193, 176, 30, 46, 2, 123, 240, 111, 16, 213, 121, 117, 128, 162, 197, 165, 253, 11, 34, 35, 225, 88, 15, 23, 1, 190, 120, 184, 8, 235, 189, 187, 64, 81, 227, 211, 255, 134, 17, 146, 241, 44, 136, 140, 129, 95, 60, 92, 4, 246, 223, 222, 32, 169, 242, 234, 256, 67, 137, 73, 249, 22, 68, 70, 193, 176, 30, 46, 2, 123, 240, 111, 16, 213, 121, 117, 128, 162, 197, 165, 253, 11, 34, 35, 225, 88, 15, 23, 1], +[1, 191, 244, 87, 169, 154, 116, 54, 34, 69, 72, 131, 92, 96, 89, 37, 128, 33, 135, 85, 44, 180, 199, 230, 240, 94, 221, 63, 211, 209, 84, 110, 193, 112, 61, 86, 235, 167, 29, 142, 137, 210, 18, 97, 23, 24, 215, 202, 32, 201, 98, 214, 11, 45, 114, 186, 60, 152, 248, 80, 117, 245, 21, 156, 241, 28, 208, 150, 123, 106, 200, 164, 227, 181, 133, 217, 70, 6, 118, 179, 8, 243, 153, 182, 67, 204, 157, 175, 15, 38, 62, 20, 222, 254, 198, 39, 253, 7, 52, 166, 95, 155, 50, 41, 121, 238, 226, 247, 146, 130, 158, 109, 2, 125, 231, 174, 81, 51, 232, 108, 68, 138, 144, 5, 184, 192, 178, 74, 256, 66, 13, 170, 88, 103, 141, 203, 223, 188, 185, 126, 165, 161, 168, 220, 129, 224, 122, 172, 213, 77, 58, 27, 17, 163, 36, 194, 46, 48, 173, 147, 64, 145, 196, 171, 22, 90, 228, 115, 120, 47, 239, 160, 234, 233, 42, 55, 225, 56, 159, 43, 246, 212, 143, 71, 197, 105, 9, 177, 140, 12, 236, 101, 16, 229, 49, 107, 134, 151, 57, 93, 30, 76, 124, 40, 187, 251, 139, 78, 249, 14, 104, 75, 190, 53, 100, 82, 242, 219, 195, 237, 35, 3, 59, 218, 4, 250, 205, 91, 162, 102, 207, 216, 136, 19, 31, 10, 111, 127, 99, 148, 255, 132, 26, 83, 176, 206, 25, 149, 189, 119, 113, 252, 73, 65, 79, 183, 1], +[1, 192, 113, 108, 176, 125, 99, 247, 136, 155, 205, 39, 35, 38, 100, 182, 249, 6, 124, 164, 134, 28, 236, 80, 197, 45, 159, 202, 234, 210, 228, 86, 64, 209, 36, 230, 213, 33, 168, 131, 223, 154, 13, 183, 184, 119, 232, 83, 2, 127, 226, 216, 95, 250, 198, 237, 15, 53, 153, 78, 70, 76, 200, 107, 241, 12, 248, 71, 11, 56, 215, 160, 137, 90, 61, 147, 211, 163, 199, 172, 128, 161, 72, 203, 169, 66, 79, 5, 189, 51, 26, 109, 111, 238, 207, 166, 4, 254, 195, 175, 190, 243, 139, 217, 30, 106, 49, 156, 140, 152, 143, 214, 225, 24, 239, 142, 22, 112, 173, 63, 17, 180, 122, 37, 165, 69, 141, 87, 256, 65, 144, 149, 81, 132, 158, 10, 121, 102, 52, 218, 222, 219, 157, 75, 8, 251, 133, 93, 123, 229, 21, 177, 60, 212, 98, 55, 23, 47, 29, 171, 193, 48, 221, 27, 44, 224, 89, 126, 34, 103, 244, 74, 73, 138, 25, 174, 255, 130, 31, 41, 162, 7, 59, 20, 242, 204, 104, 179, 187, 181, 57, 150, 16, 245, 9, 186, 246, 201, 42, 97, 120, 167, 196, 110, 46, 94, 58, 85, 129, 96, 185, 54, 88, 191, 178, 252, 68, 206, 231, 148, 146, 19, 50, 91, 253, 3, 62, 82, 67, 14, 118, 40, 227, 151, 208, 101, 117, 105, 114, 43, 32, 233, 18, 115, 235, 145, 84, 194, 240, 77, 135, 220, 92, 188, 116, 170, 1], +[1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1], +[1, 194, 114, 14, 146, 54, 196, 245, 242, 174, 89, 47, 123, 218, 144, 180, 225, 217, 207, 66, 211, 71, 153, 127, 223, 86, 236, 38, 176, 220, 18, 151, 253, 252, 58, 201, 187, 41, 244, 48, 60, 75, 158, 69, 22, 156, 195, 51, 128, 160, 200, 250, 184, 230, 159, 6, 136, 170, 84, 105, 67, 148, 185, 167, 16, 20, 25, 224, 23, 93, 52, 65, 17, 214, 139, 238, 169, 147, 248, 53, 2, 131, 228, 28, 35, 108, 135, 233, 227, 91, 178, 94, 246, 179, 31, 103, 193, 177, 157, 132, 165, 142, 49, 254, 189, 172, 215, 76, 95, 183, 36, 45, 249, 247, 116, 145, 117, 82, 231, 96, 120, 150, 59, 138, 44, 55, 133, 102, 256, 63, 143, 243, 111, 203, 61, 12, 15, 83, 168, 210, 134, 39, 113, 77, 32, 40, 50, 191, 46, 186, 104, 130, 34, 171, 21, 219, 81, 37, 239, 106, 4, 5, 199, 56, 70, 216, 13, 209, 197, 182, 99, 188, 235, 101, 62, 206, 129, 97, 57, 7, 73, 27, 98, 251, 121, 87, 173, 152, 190, 109, 72, 90, 241, 237, 232, 33, 234, 164, 205, 192, 240, 43, 118, 19, 88, 110, 9, 204, 255, 126, 29, 229, 222, 149, 122, 24, 30, 166, 79, 163, 11, 78, 226, 154, 64, 80, 100, 125, 92, 115, 208, 3, 68, 85, 42, 181, 162, 74, 221, 212, 8, 10, 141, 112, 140, 175, 26, 161, 137, 107, 198, 119, 213, 202, 124, 155, 1], +[1, 195, 246, 168, 121, 208, 211, 25, 249, 239, 88, 198, 60, 135, 111, 57, 64, 144, 67, 215, 34, 205, 140, 58, 2, 133, 235, 79, 242, 159, 165, 50, 241, 221, 176, 139, 120, 13, 222, 114, 128, 31, 134, 173, 68, 153, 23, 116, 4, 9, 213, 158, 227, 61, 73, 100, 225, 185, 95, 21, 240, 26, 187, 228, 256, 62, 11, 89, 136, 49, 46, 232, 8, 18, 169, 59, 197, 122, 146, 200, 193, 113, 190, 42, 223, 52, 117, 199, 255, 124, 22, 178, 15, 98, 92, 207, 16, 36, 81, 118, 137, 244, 35, 143, 129, 226, 123, 84, 189, 104, 234, 141, 253, 248, 44, 99, 30, 196, 184, 157, 32, 72, 162, 236, 17, 231, 70, 29, 1, 195, 246, 168, 121, 208, 211, 25, 249, 239, 88, 198, 60, 135, 111, 57, 64, 144, 67, 215, 34, 205, 140, 58, 2, 133, 235, 79, 242, 159, 165, 50, 241, 221, 176, 139, 120, 13, 222, 114, 128, 31, 134, 173, 68, 153, 23, 116, 4, 9, 213, 158, 227, 61, 73, 100, 225, 185, 95, 21, 240, 26, 187, 228, 256, 62, 11, 89, 136, 49, 46, 232, 8, 18, 169, 59, 197, 122, 146, 200, 193, 113, 190, 42, 223, 52, 117, 199, 255, 124, 22, 178, 15, 98, 92, 207, 16, 36, 81, 118, 137, 244, 35, 143, 129, 226, 123, 84, 189, 104, 234, 141, 253, 248, 44, 99, 30, 196, 184, 157, 32, 72, 162, 236, 17, 231, 70, 29, 1], +[1, 196, 123, 207, 223, 18, 187, 158, 128, 159, 67, 25, 17, 248, 35, 178, 193, 49, 95, 116, 120, 133, 111, 168, 32, 104, 81, 199, 197, 62, 73, 173, 241, 205, 88, 29, 30, 226, 92, 42, 8, 26, 213, 114, 242, 144, 211, 236, 253, 244, 22, 200, 136, 185, 23, 139, 2, 135, 246, 157, 189, 36, 117, 59, 256, 61, 134, 50, 34, 239, 70, 99, 129, 98, 190, 232, 240, 9, 222, 79, 64, 208, 162, 141, 137, 124, 146, 89, 225, 153, 176, 58, 60, 195, 184, 84, 16, 52, 169, 228, 227, 31, 165, 215, 249, 231, 44, 143, 15, 113, 46, 21, 4, 13, 235, 57, 121, 72, 234, 118, 255, 122, 11, 100, 68, 221, 140, 198, 1, 196, 123, 207, 223, 18, 187, 158, 128, 159, 67, 25, 17, 248, 35, 178, 193, 49, 95, 116, 120, 133, 111, 168, 32, 104, 81, 199, 197, 62, 73, 173, 241, 205, 88, 29, 30, 226, 92, 42, 8, 26, 213, 114, 242, 144, 211, 236, 253, 244, 22, 200, 136, 185, 23, 139, 2, 135, 246, 157, 189, 36, 117, 59, 256, 61, 134, 50, 34, 239, 70, 99, 129, 98, 190, 232, 240, 9, 222, 79, 64, 208, 162, 141, 137, 124, 146, 89, 225, 153, 176, 58, 60, 195, 184, 84, 16, 52, 169, 228, 227, 31, 165, 215, 249, 231, 44, 143, 15, 113, 46, 21, 4, 13, 235, 57, 121, 72, 234, 118, 255, 122, 11, 100, 68, 221, 140, 198, 1], +[1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1], +[1, 198, 140, 221, 68, 100, 11, 122, 255, 118, 234, 72, 121, 57, 235, 13, 4, 21, 46, 113, 15, 143, 44, 231, 249, 215, 165, 31, 227, 228, 169, 52, 16, 84, 184, 195, 60, 58, 176, 153, 225, 89, 146, 124, 137, 141, 162, 208, 64, 79, 222, 9, 240, 232, 190, 98, 129, 99, 70, 239, 34, 50, 134, 61, 256, 59, 117, 36, 189, 157, 246, 135, 2, 139, 23, 185, 136, 200, 22, 244, 253, 236, 211, 144, 242, 114, 213, 26, 8, 42, 92, 226, 30, 29, 88, 205, 241, 173, 73, 62, 197, 199, 81, 104, 32, 168, 111, 133, 120, 116, 95, 49, 193, 178, 35, 248, 17, 25, 67, 159, 128, 158, 187, 18, 223, 207, 123, 196, 1, 198, 140, 221, 68, 100, 11, 122, 255, 118, 234, 72, 121, 57, 235, 13, 4, 21, 46, 113, 15, 143, 44, 231, 249, 215, 165, 31, 227, 228, 169, 52, 16, 84, 184, 195, 60, 58, 176, 153, 225, 89, 146, 124, 137, 141, 162, 208, 64, 79, 222, 9, 240, 232, 190, 98, 129, 99, 70, 239, 34, 50, 134, 61, 256, 59, 117, 36, 189, 157, 246, 135, 2, 139, 23, 185, 136, 200, 22, 244, 253, 236, 211, 144, 242, 114, 213, 26, 8, 42, 92, 226, 30, 29, 88, 205, 241, 173, 73, 62, 197, 199, 81, 104, 32, 168, 111, 133, 120, 116, 95, 49, 193, 178, 35, 248, 17, 25, 67, 159, 128, 158, 187, 18, 223, 207, 123, 196, 1], +[1, 199, 23, 208, 15, 158, 88, 36, 225, 57, 35, 26, 34, 84, 11, 133, 253, 232, 165, 196, 197, 139, 162, 113, 128, 29, 117, 153, 121, 178, 213, 239, 16, 100, 111, 244, 240, 215, 123, 62, 2, 141, 46, 159, 30, 59, 176, 72, 193, 114, 70, 52, 68, 168, 22, 9, 249, 207, 73, 135, 137, 21, 67, 226, 256, 58, 234, 49, 242, 99, 169, 221, 32, 200, 222, 231, 223, 173, 246, 124, 4, 25, 92, 61, 60, 118, 95, 144, 129, 228, 140, 104, 136, 79, 44, 18, 241, 157, 146, 13, 17, 42, 134, 195, 255, 116, 211, 98, 227, 198, 81, 185, 64, 143, 187, 205, 189, 89, 235, 248, 8, 50, 184, 122, 120, 236, 190, 31, 1, 199, 23, 208, 15, 158, 88, 36, 225, 57, 35, 26, 34, 84, 11, 133, 253, 232, 165, 196, 197, 139, 162, 113, 128, 29, 117, 153, 121, 178, 213, 239, 16, 100, 111, 244, 240, 215, 123, 62, 2, 141, 46, 159, 30, 59, 176, 72, 193, 114, 70, 52, 68, 168, 22, 9, 249, 207, 73, 135, 137, 21, 67, 226, 256, 58, 234, 49, 242, 99, 169, 221, 32, 200, 222, 231, 223, 173, 246, 124, 4, 25, 92, 61, 60, 118, 95, 144, 129, 228, 140, 104, 136, 79, 44, 18, 241, 157, 146, 13, 17, 42, 134, 195, 255, 116, 211, 98, 227, 198, 81, 185, 64, 143, 187, 205, 189, 89, 235, 248, 8, 50, 184, 122, 120, 236, 190, 31, 1], +[1, 200, 165, 104, 240, 198, 22, 31, 32, 232, 140, 244, 227, 168, 190, 221, 253, 228, 111, 98, 68, 236, 169, 133, 129, 100, 211, 52, 120, 99, 11, 144, 16, 116, 70, 122, 242, 84, 95, 239, 255, 114, 184, 49, 34, 118, 213, 195, 193, 50, 234, 26, 60, 178, 134, 72, 8, 58, 35, 61, 121, 42, 176, 248, 256, 57, 92, 153, 17, 59, 235, 226, 225, 25, 117, 13, 30, 89, 67, 36, 4, 29, 146, 159, 189, 21, 88, 124, 128, 157, 46, 205, 137, 158, 246, 113, 241, 141, 187, 135, 15, 173, 162, 18, 2, 143, 73, 208, 223, 139, 44, 62, 64, 207, 23, 231, 197, 79, 123, 185, 249, 199, 222, 196, 136, 215, 81, 9, 1, 200, 165, 104, 240, 198, 22, 31, 32, 232, 140, 244, 227, 168, 190, 221, 253, 228, 111, 98, 68, 236, 169, 133, 129, 100, 211, 52, 120, 99, 11, 144, 16, 116, 70, 122, 242, 84, 95, 239, 255, 114, 184, 49, 34, 118, 213, 195, 193, 50, 234, 26, 60, 178, 134, 72, 8, 58, 35, 61, 121, 42, 176, 248, 256, 57, 92, 153, 17, 59, 235, 226, 225, 25, 117, 13, 30, 89, 67, 36, 4, 29, 146, 159, 189, 21, 88, 124, 128, 157, 46, 205, 137, 158, 246, 113, 241, 141, 187, 135, 15, 173, 162, 18, 2, 143, 73, 208, 223, 139, 44, 62, 64, 207, 23, 231, 197, 79, 123, 185, 249, 199, 222, 196, 136, 215, 81, 9, 1], +[1, 201, 52, 172, 134, 206, 29, 175, 223, 105, 31, 63, 70, 192, 42, 218, 128, 28, 231, 171, 190, 154, 114, 41, 17, 76, 113, 97, 222, 161, 236, 148, 193, 243, 13, 43, 162, 180, 200, 108, 120, 219, 72, 80, 146, 48, 139, 183, 32, 7, 122, 107, 176, 167, 157, 203, 197, 19, 221, 217, 184, 233, 59, 37, 241, 125, 196, 75, 169, 45, 50, 27, 30, 119, 18, 20, 165, 12, 99, 110, 8, 66, 159, 91, 44, 106, 232, 115, 242, 69, 248, 247, 46, 251, 79, 202, 253, 224, 49, 83, 235, 204, 141, 71, 136, 94, 133, 5, 234, 3, 89, 156, 2, 145, 104, 87, 11, 155, 58, 93, 189, 210, 62, 126, 140, 127, 84, 179, 256, 56, 205, 85, 123, 51, 228, 82, 34, 152, 226, 194, 187, 65, 215, 39, 129, 229, 26, 86, 67, 103, 143, 216, 240, 181, 144, 160, 35, 96, 21, 109, 64, 14, 244, 214, 95, 77, 57, 149, 137, 38, 185, 177, 111, 209, 118, 74, 225, 250, 135, 150, 81, 90, 100, 54, 60, 238, 36, 40, 73, 24, 198, 220, 16, 132, 61, 182, 88, 212, 207, 230, 227, 138, 239, 237, 92, 245, 158, 147, 249, 191, 98, 166, 213, 151, 25, 142, 15, 188, 9, 10, 211, 6, 178, 55, 4, 33, 208, 174, 22, 53, 116, 186, 121, 163, 124, 252, 23, 254, 168, 101, 255, 112, 153, 170, 246, 102, 199, 164, 68, 47, 195, 131, 117, 130, 173, 78, 1], +[1, 202, 198, 161, 140, 10, 221, 181, 68, 115, 100, 154, 11, 166, 122, 229, 255, 110, 118, 192, 234, 237, 72, 152, 121, 27, 57, 206, 235, 182, 13, 56, 4, 37, 21, 130, 46, 40, 113, 210, 15, 203, 143, 102, 44, 150, 231, 145, 249, 183, 215, 254, 165, 177, 31, 94, 227, 108, 228, 53, 169, 214, 52, 224, 16, 148, 84, 6, 184, 160, 195, 69, 60, 41, 58, 151, 176, 86, 153, 66, 225, 218, 89, 245, 146, 194, 124, 119, 137, 175, 141, 212, 162, 85, 208, 125, 64, 78, 79, 24, 222, 126, 9, 19, 240, 164, 232, 90, 190, 87, 98, 7, 129, 101, 99, 209, 70, 5, 239, 219, 34, 186, 50, 77, 134, 83, 61, 243, 256, 55, 59, 96, 117, 247, 36, 76, 189, 142, 157, 103, 246, 91, 135, 28, 2, 147, 139, 65, 23, 20, 185, 105, 136, 230, 200, 51, 22, 75, 244, 201, 253, 220, 236, 127, 211, 217, 144, 47, 242, 54, 114, 155, 213, 107, 26, 112, 8, 74, 42, 3, 92, 80, 226, 163, 30, 149, 29, 204, 88, 43, 205, 33, 241, 109, 173, 251, 73, 97, 62, 188, 197, 216, 199, 106, 81, 171, 104, 191, 32, 39, 168, 12, 111, 63, 133, 138, 120, 82, 116, 45, 95, 172, 49, 132, 193, 179, 178, 233, 35, 131, 248, 238, 17, 93, 25, 167, 67, 170, 159, 250, 128, 156, 158, 48, 187, 252, 18, 38, 223, 71, 207, 180, 123, 174, 196, 14, 1], +[1, 203, 89, 77, 211, 171, 18, 56, 60, 101, 200, 251, 67, 237, 52, 19, 2, 149, 178, 154, 165, 85, 36, 112, 120, 202, 143, 245, 134, 217, 104, 38, 4, 41, 99, 51, 73, 170, 72, 224, 240, 147, 29, 233, 11, 177, 208, 76, 8, 82, 198, 102, 146, 83, 144, 191, 223, 37, 58, 209, 22, 97, 159, 152, 16, 164, 139, 204, 35, 166, 31, 125, 189, 74, 116, 161, 44, 194, 61, 47, 32, 71, 21, 151, 70, 75, 62, 250, 121, 148, 232, 65, 88, 131, 122, 94, 64, 142, 42, 45, 140, 150, 124, 243, 242, 39, 207, 130, 176, 5, 244, 188, 128, 27, 84, 90, 23, 43, 248, 229, 227, 78, 157, 3, 95, 10, 231, 119, 256, 54, 168, 180, 46, 86, 239, 201, 197, 156, 57, 6, 190, 20, 205, 238, 255, 108, 79, 103, 92, 172, 221, 145, 137, 55, 114, 12, 123, 40, 153, 219, 253, 216, 158, 206, 184, 87, 185, 33, 17, 110, 228, 24, 246, 80, 49, 181, 249, 175, 59, 155, 111, 174, 113, 66, 34, 220, 199, 48, 235, 160, 98, 105, 241, 93, 118, 53, 222, 91, 226, 132, 68, 183, 141, 96, 213, 63, 196, 210, 225, 186, 236, 106, 187, 182, 195, 7, 136, 109, 25, 192, 169, 126, 135, 163, 193, 115, 215, 212, 117, 107, 133, 14, 15, 218, 50, 127, 81, 252, 13, 69, 129, 230, 173, 167, 234, 214, 9, 28, 30, 179, 100, 254, 162, 247, 26, 138, 1], +[1, 204, 239, 183, 67, 47, 79, 182, 120, 65, 153, 115, 73, 243, 228, 252, 8, 90, 113, 179, 22, 119, 118, 171, 189, 6, 196, 149, 70, 145, 25, 217, 64, 206, 133, 147, 176, 181, 173, 83, 227, 48, 26, 164, 46, 132, 200, 194, 255, 106, 36, 148, 123, 163, 99, 150, 17, 127, 208, 27, 111, 28, 58, 10, 241, 77, 31, 156, 213, 19, 21, 172, 136, 245, 122, 216, 117, 224, 207, 80, 129, 102, 248, 220, 162, 152, 168, 91, 60, 161, 205, 186, 165, 250, 114, 126, 4, 45, 185, 218, 11, 188, 59, 214, 223, 3, 98, 203, 35, 201, 141, 237, 32, 103, 195, 202, 88, 219, 215, 170, 242, 24, 13, 82, 23, 66, 100, 97, 256, 53, 18, 74, 190, 210, 178, 75, 137, 192, 104, 142, 184, 14, 29, 5, 249, 167, 144, 78, 235, 138, 139, 86, 68, 251, 61, 108, 187, 112, 232, 40, 193, 51, 124, 110, 81, 76, 84, 174, 30, 209, 231, 93, 211, 125, 57, 63, 2, 151, 221, 109, 134, 94, 158, 107, 240, 130, 49, 230, 146, 229, 199, 247, 16, 180, 226, 101, 44, 238, 236, 85, 121, 12, 135, 41, 140, 33, 50, 177, 128, 155, 9, 37, 95, 105, 89, 166, 197, 96, 52, 71, 92, 7, 143, 131, 253, 212, 72, 39, 246, 69, 198, 43, 34, 254, 159, 54, 222, 56, 116, 20, 225, 154, 62, 55, 169, 38, 42, 87, 15, 233, 244, 175, 234, 191, 157, 160, 1], +[1, 205, 134, 228, 223, 226, 70, 215, 128, 26, 190, 143, 17, 144, 222, 21, 193, 244, 162, 57, 120, 185, 146, 118, 32, 135, 176, 100, 197, 36, 184, 198, 241, 61, 169, 207, 30, 239, 165, 158, 8, 98, 44, 25, 242, 9, 46, 178, 253, 208, 235, 116, 136, 124, 234, 168, 2, 153, 11, 199, 189, 195, 140, 173, 256, 52, 123, 29, 34, 31, 187, 42, 129, 231, 67, 114, 240, 113, 35, 236, 64, 13, 95, 200, 137, 72, 111, 139, 225, 122, 81, 157, 60, 221, 73, 59, 16, 196, 88, 50, 227, 18, 92, 99, 249, 159, 213, 232, 15, 248, 211, 79, 4, 49, 22, 141, 121, 133, 23, 89, 255, 104, 246, 58, 68, 62, 117, 84, 1, 205, 134, 228, 223, 226, 70, 215, 128, 26, 190, 143, 17, 144, 222, 21, 193, 244, 162, 57, 120, 185, 146, 118, 32, 135, 176, 100, 197, 36, 184, 198, 241, 61, 169, 207, 30, 239, 165, 158, 8, 98, 44, 25, 242, 9, 46, 178, 253, 208, 235, 116, 136, 124, 234, 168, 2, 153, 11, 199, 189, 195, 140, 173, 256, 52, 123, 29, 34, 31, 187, 42, 129, 231, 67, 114, 240, 113, 35, 236, 64, 13, 95, 200, 137, 72, 111, 139, 225, 122, 81, 157, 60, 221, 73, 59, 16, 196, 88, 50, 227, 18, 92, 99, 249, 159, 213, 232, 15, 248, 211, 79, 4, 49, 22, 141, 121, 133, 23, 89, 255, 104, 246, 58, 68, 62, 117, 84, 1], +[1, 206, 31, 218, 190, 76, 236, 43, 120, 48, 122, 203, 184, 125, 50, 20, 8, 106, 248, 202, 235, 94, 89, 87, 189, 127, 205, 82, 187, 229, 143, 160, 64, 77, 185, 74, 81, 238, 198, 182, 227, 245, 98, 142, 211, 33, 116, 252, 255, 102, 195, 78, 134, 105, 42, 171, 17, 161, 13, 108, 146, 7, 157, 217, 241, 45, 18, 110, 44, 69, 79, 83, 136, 3, 104, 93, 140, 56, 228, 194, 129, 103, 144, 109, 95, 38, 118, 150, 60, 24, 61, 230, 92, 191, 25, 10, 4, 53, 124, 101, 246, 47, 173, 172, 223, 192, 231, 41, 222, 243, 200, 80, 32, 167, 221, 37, 169, 119, 99, 91, 242, 251, 49, 71, 234, 145, 58, 126, 256, 51, 226, 39, 67, 181, 21, 214, 137, 209, 135, 54, 73, 132, 207, 237, 249, 151, 9, 55, 22, 163, 168, 170, 68, 130, 52, 175, 70, 28, 114, 97, 193, 180, 72, 183, 176, 19, 59, 75, 30, 12, 159, 115, 46, 224, 141, 5, 2, 155, 62, 179, 123, 152, 215, 86, 240, 96, 244, 149, 111, 250, 100, 40, 16, 212, 239, 147, 213, 188, 178, 174, 121, 254, 153, 164, 117, 201, 29, 63, 128, 154, 113, 148, 162, 219, 139, 107, 197, 233, 196, 27, 165, 66, 232, 247, 253, 204, 133, 156, 11, 210, 84, 85, 34, 65, 26, 216, 35, 14, 57, 177, 225, 90, 36, 220, 88, 138, 158, 166, 15, 6, 208, 186, 23, 112, 199, 131, 1], +[1, 207, 187, 159, 17, 178, 95, 133, 32, 199, 73, 205, 30, 42, 213, 144, 253, 200, 23, 135, 189, 59, 134, 239, 129, 232, 222, 208, 137, 89, 176, 195, 16, 228, 165, 231, 15, 21, 235, 72, 255, 100, 140, 196, 223, 158, 67, 248, 193, 116, 111, 104, 197, 173, 88, 226, 8, 114, 211, 244, 136, 139, 246, 36, 256, 50, 70, 98, 240, 79, 162, 124, 225, 58, 184, 52, 227, 215, 44, 113, 4, 57, 234, 122, 68, 198, 123, 18, 128, 25, 35, 49, 120, 168, 81, 62, 241, 29, 92, 26, 242, 236, 22, 185, 2, 157, 117, 61, 34, 99, 190, 9, 64, 141, 146, 153, 60, 84, 169, 31, 249, 143, 46, 13, 121, 118, 11, 221, 1, 207, 187, 159, 17, 178, 95, 133, 32, 199, 73, 205, 30, 42, 213, 144, 253, 200, 23, 135, 189, 59, 134, 239, 129, 232, 222, 208, 137, 89, 176, 195, 16, 228, 165, 231, 15, 21, 235, 72, 255, 100, 140, 196, 223, 158, 67, 248, 193, 116, 111, 104, 197, 173, 88, 226, 8, 114, 211, 244, 136, 139, 246, 36, 256, 50, 70, 98, 240, 79, 162, 124, 225, 58, 184, 52, 227, 215, 44, 113, 4, 57, 234, 122, 68, 198, 123, 18, 128, 25, 35, 49, 120, 168, 81, 62, 241, 29, 92, 26, 242, 236, 22, 185, 2, 157, 117, 61, 34, 99, 190, 9, 64, 141, 146, 153, 60, 84, 169, 31, 249, 143, 46, 13, 121, 118, 11, 221, 1], +[1, 208, 88, 57, 34, 133, 165, 139, 128, 153, 213, 100, 240, 62, 46, 59, 193, 52, 22, 207, 137, 226, 234, 99, 32, 231, 246, 25, 60, 144, 140, 79, 241, 13, 134, 116, 227, 185, 187, 89, 8, 122, 190, 199, 15, 36, 35, 84, 253, 196, 162, 29, 121, 239, 111, 215, 2, 159, 176, 114, 68, 9, 73, 21, 256, 49, 169, 200, 223, 124, 92, 118, 129, 104, 44, 157, 17, 195, 211, 198, 64, 205, 235, 50, 120, 31, 23, 158, 225, 26, 11, 232, 197, 113, 117, 178, 16, 244, 123, 141, 30, 72, 70, 168, 249, 135, 67, 58, 242, 221, 222, 173, 4, 61, 95, 228, 136, 18, 146, 42, 255, 98, 81, 143, 189, 248, 184, 236, 1, 208, 88, 57, 34, 133, 165, 139, 128, 153, 213, 100, 240, 62, 46, 59, 193, 52, 22, 207, 137, 226, 234, 99, 32, 231, 246, 25, 60, 144, 140, 79, 241, 13, 134, 116, 227, 185, 187, 89, 8, 122, 190, 199, 15, 36, 35, 84, 253, 196, 162, 29, 121, 239, 111, 215, 2, 159, 176, 114, 68, 9, 73, 21, 256, 49, 169, 200, 223, 124, 92, 118, 129, 104, 44, 157, 17, 195, 211, 198, 64, 205, 235, 50, 120, 31, 23, 158, 225, 26, 11, 232, 197, 113, 117, 178, 16, 244, 123, 141, 30, 72, 70, 168, 249, 135, 67, 58, 242, 221, 222, 173, 4, 61, 95, 228, 136, 18, 146, 42, 255, 98, 81, 143, 189, 248, 184, 236, 1], +[1, 209, 248, 175, 81, 224, 42, 40, 136, 154, 61, 156, 222, 138, 58, 43, 249, 127, 72, 142, 123, 7, 178, 194, 197, 53, 26, 37, 23, 181, 50, 170, 64, 12, 195, 149, 44, 201, 118, 247, 223, 90, 49, 218, 73, 94, 114, 182, 2, 161, 239, 93, 162, 191, 84, 80, 15, 51, 122, 55, 187, 19, 116, 86, 241, 254, 144, 27, 246, 14, 99, 131, 137, 106, 52, 74, 46, 105, 100, 83, 128, 24, 133, 41, 88, 145, 236, 237, 189, 180, 98, 179, 146, 188, 228, 107, 4, 65, 221, 186, 67, 125, 168, 160, 30, 102, 244, 110, 117, 38, 232, 172, 225, 251, 31, 54, 235, 28, 198, 5, 17, 212, 104, 148, 92, 210, 200, 166, 256, 48, 9, 82, 176, 33, 215, 217, 121, 103, 196, 101, 35, 119, 199, 214, 8, 130, 185, 115, 134, 250, 79, 63, 60, 204, 231, 220, 234, 76, 207, 87, 193, 245, 62, 108, 213, 56, 139, 10, 34, 167, 208, 39, 184, 163, 143, 75, 255, 96, 18, 164, 95, 66, 173, 177, 242, 206, 135, 202, 70, 238, 141, 171, 16, 3, 113, 230, 11, 243, 158, 126, 120, 151, 205, 183, 211, 152, 157, 174, 129, 233, 124, 216, 169, 112, 21, 20, 68, 77, 159, 78, 111, 69, 29, 150, 253, 192, 36, 71, 190, 132, 89, 97, 227, 155, 13, 147, 140, 219, 25, 85, 32, 6, 226, 203, 22, 229, 59, 252, 240, 45, 153, 109, 165, 47, 57, 91, 1], +[1, 210, 153, 5, 22, 251, 25, 110, 227, 125, 36, 107, 111, 180, 21, 41, 129, 105, 205, 131, 11, 254, 141, 55, 242, 191, 18, 182, 184, 90, 139, 149, 193, 181, 231, 194, 134, 127, 199, 156, 121, 224, 9, 91, 92, 45, 198, 203, 225, 219, 244, 97, 67, 192, 228, 78, 189, 112, 133, 174, 46, 151, 99, 230, 241, 238, 122, 177, 162, 96, 114, 39, 223, 56, 195, 87, 23, 204, 178, 115, 249, 119, 61, 217, 81, 48, 57, 148, 240, 28, 226, 172, 140, 102, 89, 186, 253, 188, 159, 237, 169, 24, 157, 74, 120, 14, 113, 86, 70, 51, 173, 93, 255, 94, 208, 247, 213, 12, 207, 37, 60, 7, 185, 43, 35, 154, 215, 175, 256, 47, 104, 252, 235, 6, 232, 147, 30, 132, 221, 150, 146, 77, 236, 216, 128, 152, 52, 126, 246, 3, 116, 202, 15, 66, 239, 75, 73, 167, 118, 108, 64, 76, 26, 63, 123, 130, 58, 101, 136, 33, 248, 166, 165, 212, 59, 54, 32, 38, 13, 160, 190, 65, 29, 179, 68, 145, 124, 83, 211, 106, 158, 27, 16, 19, 135, 80, 95, 161, 143, 218, 34, 201, 62, 170, 234, 53, 79, 142, 8, 138, 196, 40, 176, 209, 200, 109, 17, 229, 31, 85, 117, 155, 168, 71, 4, 69, 98, 20, 88, 233, 100, 183, 137, 243, 144, 171, 187, 206, 84, 164, 2, 163, 49, 10, 44, 245, 50, 220, 197, 250, 72, 214, 222, 103, 42, 82, 1], +[1, 211, 60, 67, 2, 165, 120, 134, 4, 73, 240, 11, 8, 146, 223, 22, 16, 35, 189, 44, 32, 70, 121, 88, 64, 140, 242, 176, 128, 23, 227, 95, 256, 46, 197, 190, 255, 92, 137, 123, 253, 184, 17, 246, 249, 111, 34, 235, 241, 222, 68, 213, 225, 187, 136, 169, 193, 117, 15, 81, 129, 234, 30, 162, 1, 211, 60, 67, 2, 165, 120, 134, 4, 73, 240, 11, 8, 146, 223, 22, 16, 35, 189, 44, 32, 70, 121, 88, 64, 140, 242, 176, 128, 23, 227, 95, 256, 46, 197, 190, 255, 92, 137, 123, 253, 184, 17, 246, 249, 111, 34, 235, 241, 222, 68, 213, 225, 187, 136, 169, 193, 117, 15, 81, 129, 234, 30, 162, 1, 211, 60, 67, 2, 165, 120, 134, 4, 73, 240, 11, 8, 146, 223, 22, 16, 35, 189, 44, 32, 70, 121, 88, 64, 140, 242, 176, 128, 23, 227, 95, 256, 46, 197, 190, 255, 92, 137, 123, 253, 184, 17, 246, 249, 111, 34, 235, 241, 222, 68, 213, 225, 187, 136, 169, 193, 117, 15, 81, 129, 234, 30, 162, 1, 211, 60, 67, 2, 165, 120, 134, 4, 73, 240, 11, 8, 146, 223, 22, 16, 35, 189, 44, 32, 70, 121, 88, 64, 140, 242, 176, 128, 23, 227, 95, 256, 46, 197, 190, 255, 92, 137, 123, 253, 184, 17, 246, 249, 111, 34, 235, 241, 222, 68, 213, 225, 187, 136, 169, 193, 117, 15, 81, 129, 234, 30, 162, 1], +[1, 212, 226, 110, 190, 188, 21, 83, 120, 254, 135, 93, 184, 201, 207, 194, 8, 154, 9, 109, 235, 219, 168, 150, 189, 233, 52, 230, 187, 66, 114, 10, 64, 204, 72, 101, 81, 210, 59, 172, 227, 65, 159, 41, 211, 14, 141, 80, 255, 90, 62, 37, 134, 138, 215, 91, 17, 6, 244, 71, 146, 112, 100, 126, 241, 206, 239, 39, 44, 76, 178, 214, 136, 48, 153, 54, 140, 125, 29, 237, 129, 106, 113, 55, 95, 94, 139, 170, 60, 127, 196, 175, 92, 229, 232, 97, 4, 77, 133, 183, 246, 238, 84, 75, 223, 245, 26, 115, 222, 33, 57, 5, 32, 102, 36, 179, 169, 105, 158, 86, 242, 161, 208, 149, 234, 7, 199, 40, 256, 45, 31, 147, 67, 69, 236, 174, 137, 3, 122, 164, 73, 56, 50, 63, 249, 103, 248, 148, 22, 38, 89, 107, 68, 24, 205, 27, 70, 191, 143, 247, 193, 53, 185, 156, 176, 47, 198, 85, 30, 192, 98, 216, 46, 243, 116, 177, 2, 167, 195, 220, 123, 119, 42, 166, 240, 251, 13, 186, 111, 145, 157, 131, 16, 51, 18, 218, 213, 181, 79, 43, 121, 209, 104, 203, 117, 132, 228, 20, 128, 151, 144, 202, 162, 163, 118, 87, 197, 130, 61, 82, 165, 28, 25, 160, 253, 180, 124, 74, 11, 19, 173, 182, 34, 12, 231, 142, 35, 224, 200, 252, 225, 155, 221, 78, 88, 152, 99, 171, 15, 96, 49, 108, 23, 250, 58, 217, 1], +[1, 213, 137, 140, 8, 162, 68, 92, 64, 11, 30, 222, 255, 88, 240, 234, 241, 190, 121, 73, 129, 235, 197, 70, 4, 81, 34, 46, 32, 134, 15, 111, 256, 44, 120, 117, 249, 95, 189, 165, 193, 246, 227, 35, 2, 169, 17, 23, 16, 67, 136, 184, 128, 22, 60, 187, 253, 176, 223, 211, 225, 123, 242, 146, 1, 213, 137, 140, 8, 162, 68, 92, 64, 11, 30, 222, 255, 88, 240, 234, 241, 190, 121, 73, 129, 235, 197, 70, 4, 81, 34, 46, 32, 134, 15, 111, 256, 44, 120, 117, 249, 95, 189, 165, 193, 246, 227, 35, 2, 169, 17, 23, 16, 67, 136, 184, 128, 22, 60, 187, 253, 176, 223, 211, 225, 123, 242, 146, 1, 213, 137, 140, 8, 162, 68, 92, 64, 11, 30, 222, 255, 88, 240, 234, 241, 190, 121, 73, 129, 235, 197, 70, 4, 81, 34, 46, 32, 134, 15, 111, 256, 44, 120, 117, 249, 95, 189, 165, 193, 246, 227, 35, 2, 169, 17, 23, 16, 67, 136, 184, 128, 22, 60, 187, 253, 176, 223, 211, 225, 123, 242, 146, 1, 213, 137, 140, 8, 162, 68, 92, 64, 11, 30, 222, 255, 88, 240, 234, 241, 190, 121, 73, 129, 235, 197, 70, 4, 81, 34, 46, 32, 134, 15, 111, 256, 44, 120, 117, 249, 95, 189, 165, 193, 246, 227, 35, 2, 169, 17, 23, 16, 67, 136, 184, 128, 22, 60, 187, 253, 176, 223, 211, 225, 123, 242, 146, 1], +[1, 214, 50, 163, 187, 183, 98, 155, 17, 40, 79, 201, 95, 27, 124, 65, 32, 166, 58, 76, 73, 202, 52, 77, 30, 252, 215, 7, 213, 93, 113, 24, 253, 172, 57, 119, 23, 39, 122, 151, 189, 97, 198, 224, 134, 149, 18, 254, 129, 107, 25, 210, 222, 220, 49, 206, 137, 20, 168, 229, 176, 142, 62, 161, 16, 83, 29, 38, 165, 101, 26, 167, 15, 126, 236, 132, 235, 175, 185, 12, 255, 86, 157, 188, 140, 148, 61, 204, 223, 177, 99, 112, 67, 203, 9, 127, 193, 182, 141, 105, 111, 110, 153, 103, 197, 10, 84, 243, 88, 71, 31, 209, 8, 170, 143, 19, 211, 179, 13, 212, 136, 63, 118, 66, 246, 216, 221, 6, 256, 43, 207, 94, 70, 74, 159, 102, 240, 217, 178, 56, 162, 230, 133, 192, 225, 91, 199, 181, 184, 55, 205, 180, 227, 5, 42, 250, 44, 164, 144, 233, 4, 85, 200, 138, 234, 218, 135, 106, 68, 160, 59, 33, 123, 108, 239, 3, 128, 150, 232, 47, 35, 37, 208, 51, 120, 237, 89, 28, 81, 115, 195, 96, 241, 174, 228, 219, 92, 156, 231, 90, 242, 131, 21, 125, 22, 82, 72, 245, 2, 171, 100, 69, 117, 109, 196, 53, 34, 80, 158, 145, 190, 54, 248, 130, 64, 75, 116, 152, 146, 147, 104, 154, 60, 247, 173, 14, 169, 186, 226, 48, 249, 87, 114, 238, 46, 78, 244, 45, 121, 194, 139, 191, 11, 41, 36, 251, 1], +[1, 215, 222, 185, 197, 207, 44, 208, 2, 173, 187, 113, 137, 157, 88, 159, 4, 89, 117, 226, 17, 57, 176, 61, 8, 178, 234, 195, 34, 114, 95, 122, 16, 99, 211, 133, 68, 228, 190, 244, 32, 198, 165, 9, 136, 199, 123, 231, 64, 139, 73, 18, 15, 141, 246, 205, 128, 21, 146, 36, 30, 25, 235, 153, 256, 42, 35, 72, 60, 50, 213, 49, 255, 84, 70, 144, 120, 100, 169, 98, 253, 168, 140, 31, 240, 200, 81, 196, 249, 79, 23, 62, 223, 143, 162, 135, 241, 158, 46, 124, 189, 29, 67, 13, 225, 59, 92, 248, 121, 58, 134, 26, 193, 118, 184, 239, 242, 116, 11, 52, 129, 236, 111, 221, 227, 232, 22, 104, 1, 215, 222, 185, 197, 207, 44, 208, 2, 173, 187, 113, 137, 157, 88, 159, 4, 89, 117, 226, 17, 57, 176, 61, 8, 178, 234, 195, 34, 114, 95, 122, 16, 99, 211, 133, 68, 228, 190, 244, 32, 198, 165, 9, 136, 199, 123, 231, 64, 139, 73, 18, 15, 141, 246, 205, 128, 21, 146, 36, 30, 25, 235, 153, 256, 42, 35, 72, 60, 50, 213, 49, 255, 84, 70, 144, 120, 100, 169, 98, 253, 168, 140, 31, 240, 200, 81, 196, 249, 79, 23, 62, 223, 143, 162, 135, 241, 158, 46, 124, 189, 29, 67, 13, 225, 59, 92, 248, 121, 58, 134, 26, 193, 118, 184, 239, 242, 116, 11, 52, 129, 236, 111, 221, 227, 232, 22, 104, 1], +[1, 216, 139, 212, 46, 170, 226, 243, 60, 110, 116, 127, 190, 177, 196, 188, 2, 175, 21, 167, 92, 83, 195, 229, 120, 220, 232, 254, 123, 97, 135, 119, 4, 93, 42, 77, 184, 166, 133, 201, 240, 183, 207, 251, 246, 194, 13, 238, 8, 186, 84, 154, 111, 75, 9, 145, 223, 109, 157, 245, 235, 131, 26, 219, 16, 115, 168, 51, 222, 150, 18, 33, 189, 218, 57, 233, 213, 5, 52, 181, 32, 230, 79, 102, 187, 43, 36, 66, 121, 179, 114, 209, 169, 10, 104, 105, 64, 203, 158, 204, 117, 86, 72, 132, 242, 101, 228, 161, 81, 20, 208, 210, 128, 149, 59, 151, 234, 172, 144, 7, 227, 202, 199, 65, 162, 40, 159, 163, 256, 41, 118, 45, 211, 87, 31, 14, 197, 147, 141, 130, 67, 80, 61, 69, 255, 82, 236, 90, 165, 174, 62, 28, 137, 37, 25, 3, 134, 160, 122, 138, 253, 164, 215, 180, 73, 91, 124, 56, 17, 74, 50, 6, 11, 63, 244, 19, 249, 71, 173, 103, 146, 182, 248, 112, 34, 148, 100, 12, 22, 126, 231, 38, 241, 142, 89, 206, 35, 107, 239, 224, 68, 39, 200, 24, 44, 252, 205, 76, 225, 27, 178, 155, 70, 214, 221, 191, 136, 78, 143, 48, 88, 247, 153, 152, 193, 54, 99, 53, 140, 171, 185, 125, 15, 156, 29, 96, 176, 237, 49, 47, 129, 108, 198, 106, 23, 85, 113, 250, 30, 55, 58, 192, 95, 217, 98, 94, 1], +[1, 217, 58, 250, 23, 108, 49, 96, 15, 171, 99, 152, 88, 78, 221, 155, 225, 252, 200, 224, 35, 142, 231, 12, 34, 182, 173, 19, 11, 74, 124, 180, 253, 160, 25, 28, 165, 82, 61, 130, 197, 87, 118, 163, 162, 202, 144, 151, 128, 20, 228, 132, 117, 203, 104, 209, 121, 43, 79, 181, 213, 218, 18, 51, 16, 131, 157, 145, 111, 186, 13, 251, 240, 166, 42, 119, 123, 220, 195, 167, 2, 177, 116, 243, 46, 216, 98, 192, 30, 85, 198, 47, 176, 156, 185, 53, 193, 247, 143, 191, 70, 27, 205, 24, 68, 107, 89, 38, 22, 148, 248, 103, 249, 63, 50, 56, 73, 164, 122, 3, 137, 174, 236, 69, 67, 147, 31, 45, 256, 40, 199, 7, 234, 149, 208, 161, 242, 86, 158, 105, 169, 179, 36, 102, 32, 5, 57, 33, 222, 115, 26, 245, 223, 75, 84, 238, 246, 183, 133, 77, 4, 97, 232, 229, 92, 175, 196, 127, 60, 170, 139, 94, 95, 55, 113, 106, 129, 237, 29, 125, 140, 54, 153, 48, 136, 214, 178, 76, 44, 39, 239, 206, 241, 126, 100, 112, 146, 71, 244, 6, 17, 91, 215, 138, 134, 37, 62, 90, 255, 80, 141, 14, 211, 41, 159, 65, 227, 172, 59, 210, 81, 101, 72, 204, 64, 10, 114, 66, 187, 230, 52, 233, 189, 150, 168, 219, 235, 109, 9, 154, 8, 194, 207, 201, 184, 93, 135, 254, 120, 83, 21, 188, 190, 110, 226, 212, 1], +[1, 218, 236, 48, 184, 20, 248, 94, 189, 82, 143, 77, 81, 182, 98, 33, 255, 78, 42, 161, 146, 217, 18, 69, 136, 93, 228, 103, 95, 150, 61, 191, 4, 101, 173, 192, 222, 80, 221, 119, 242, 71, 58, 51, 67, 214, 135, 132, 249, 55, 168, 130, 70, 97, 72, 19, 30, 115, 141, 155, 123, 86, 244, 250, 16, 147, 178, 254, 117, 63, 113, 219, 197, 27, 232, 204, 11, 85, 26, 14, 225, 220, 158, 6, 23, 131, 31, 76, 120, 203, 50, 106, 235, 87, 205, 229, 64, 74, 198, 245, 211, 252, 195, 105, 17, 108, 157, 45, 44, 83, 104, 56, 129, 109, 118, 24, 92, 10, 124, 47, 223, 41, 200, 167, 169, 91, 49, 145, 256, 39, 21, 209, 73, 237, 9, 163, 68, 175, 114, 180, 176, 75, 159, 224, 2, 179, 215, 96, 111, 40, 239, 188, 121, 164, 29, 154, 162, 107, 196, 66, 253, 156, 84, 65, 35, 177, 36, 138, 15, 186, 199, 206, 190, 43, 122, 125, 8, 202, 89, 127, 187, 160, 185, 238, 227, 142, 116, 102, 134, 171, 13, 7, 241, 110, 79, 3, 140, 194, 144, 38, 60, 230, 25, 53, 246, 172, 231, 243, 32, 37, 99, 251, 234, 126, 226, 181, 137, 54, 207, 151, 22, 170, 52, 28, 193, 183, 59, 12, 46, 5, 62, 152, 240, 149, 100, 212, 213, 174, 153, 201, 128, 148, 139, 233, 165, 247, 133, 210, 34, 216, 57, 90, 88, 166, 208, 112, 1], +[1, 219, 159, 126, 95, 245, 199, 148, 30, 145, 144, 182, 23, 154, 59, 71, 129, 238, 208, 63, 176, 251, 228, 74, 15, 201, 72, 91, 140, 77, 158, 164, 193, 119, 104, 160, 88, 254, 114, 37, 136, 229, 36, 174, 70, 167, 79, 82, 225, 188, 52, 80, 44, 127, 57, 147, 68, 243, 18, 87, 35, 212, 168, 41, 241, 94, 26, 40, 22, 192, 157, 202, 34, 250, 9, 172, 146, 106, 84, 149, 249, 47, 13, 20, 11, 96, 207, 101, 17, 125, 133, 86, 73, 53, 42, 203, 253, 152, 135, 10, 134, 48, 232, 179, 137, 191, 195, 43, 165, 155, 21, 230, 255, 76, 196, 5, 67, 24, 116, 218, 197, 224, 226, 150, 211, 206, 139, 115, 256, 38, 98, 131, 162, 12, 58, 109, 227, 112, 113, 75, 234, 103, 198, 186, 128, 19, 49, 194, 81, 6, 29, 183, 242, 56, 185, 166, 117, 180, 99, 93, 64, 138, 153, 97, 169, 3, 143, 220, 121, 28, 221, 83, 187, 90, 178, 175, 32, 69, 205, 177, 213, 130, 200, 110, 189, 14, 239, 170, 222, 45, 89, 216, 16, 163, 231, 217, 235, 65, 100, 55, 223, 7, 248, 85, 111, 151, 173, 108, 8, 210, 244, 237, 246, 161, 50, 156, 240, 132, 124, 171, 184, 204, 215, 54, 4, 105, 122, 247, 123, 209, 25, 78, 120, 66, 62, 214, 92, 102, 236, 27, 2, 181, 61, 252, 190, 233, 141, 39, 60, 33, 31, 107, 46, 51, 118, 142, 1], +[1, 220, 84, 233, 117, 40, 62, 19, 68, 54, 58, 167, 246, 150, 104, 7, 255, 74, 89, 48, 23, 177, 133, 219, 121, 149, 141, 180, 22, 214, 49, 243, 4, 109, 79, 161, 211, 160, 248, 76, 15, 216, 232, 154, 213, 86, 159, 28, 249, 39, 99, 192, 92, 194, 18, 105, 227, 82, 50, 206, 88, 85, 196, 201, 16, 179, 59, 130, 73, 126, 221, 47, 60, 93, 157, 102, 81, 87, 122, 112, 225, 156, 139, 254, 111, 5, 72, 163, 137, 71, 200, 53, 95, 83, 13, 33, 64, 202, 236, 6, 35, 247, 113, 188, 240, 115, 114, 151, 67, 91, 231, 191, 129, 110, 42, 245, 187, 20, 31, 138, 34, 27, 29, 212, 123, 75, 52, 132, 256, 37, 173, 24, 140, 217, 195, 238, 189, 203, 199, 90, 11, 107, 153, 250, 2, 183, 168, 209, 234, 80, 124, 38, 136, 108, 116, 77, 235, 43, 208, 14, 253, 148, 178, 96, 46, 97, 9, 181, 242, 41, 25, 103, 44, 171, 98, 229, 8, 218, 158, 65, 165, 63, 239, 152, 30, 175, 207, 51, 169, 172, 61, 56, 241, 78, 198, 127, 184, 131, 36, 210, 197, 164, 100, 155, 176, 170, 135, 145, 32, 101, 118, 3, 146, 252, 185, 94, 120, 186, 57, 204, 162, 174, 244, 224, 193, 55, 21, 251, 222, 10, 144, 69, 17, 142, 143, 106, 190, 166, 26, 66, 128, 147, 215, 12, 70, 237, 226, 119, 223, 230, 228, 45, 134, 182, 205, 125, 1], +[1, 221, 11, 118, 121, 13, 46, 143, 249, 31, 169, 84, 60, 153, 146, 141, 64, 9, 190, 99, 34, 61, 117, 157, 2, 185, 22, 236, 242, 26, 92, 29, 241, 62, 81, 168, 120, 49, 35, 25, 128, 18, 123, 198, 68, 122, 234, 57, 4, 113, 44, 215, 227, 52, 184, 58, 225, 124, 162, 79, 240, 98, 70, 50, 256, 36, 246, 139, 136, 244, 211, 114, 8, 226, 88, 173, 197, 104, 111, 116, 193, 248, 67, 158, 223, 196, 140, 100, 255, 72, 235, 21, 15, 231, 165, 228, 16, 195, 176, 89, 137, 208, 222, 232, 129, 239, 134, 59, 189, 135, 23, 200, 253, 144, 213, 42, 30, 205, 73, 199, 32, 133, 95, 178, 17, 159, 187, 207, 1, 221, 11, 118, 121, 13, 46, 143, 249, 31, 169, 84, 60, 153, 146, 141, 64, 9, 190, 99, 34, 61, 117, 157, 2, 185, 22, 236, 242, 26, 92, 29, 241, 62, 81, 168, 120, 49, 35, 25, 128, 18, 123, 198, 68, 122, 234, 57, 4, 113, 44, 215, 227, 52, 184, 58, 225, 124, 162, 79, 240, 98, 70, 50, 256, 36, 246, 139, 136, 244, 211, 114, 8, 226, 88, 173, 197, 104, 111, 116, 193, 248, 67, 158, 223, 196, 140, 100, 255, 72, 235, 21, 15, 231, 165, 228, 16, 195, 176, 89, 137, 208, 222, 232, 129, 239, 134, 59, 189, 135, 23, 200, 253, 144, 213, 42, 30, 205, 73, 199, 32, 133, 95, 178, 17, 159, 187, 207, 1], +[1, 222, 197, 44, 2, 187, 137, 88, 4, 117, 17, 176, 8, 234, 34, 95, 16, 211, 68, 190, 32, 165, 136, 123, 64, 73, 15, 246, 128, 146, 30, 235, 256, 35, 60, 213, 255, 70, 120, 169, 253, 140, 240, 81, 249, 23, 223, 162, 241, 46, 189, 67, 225, 92, 121, 134, 193, 184, 242, 11, 129, 111, 227, 22, 1, 222, 197, 44, 2, 187, 137, 88, 4, 117, 17, 176, 8, 234, 34, 95, 16, 211, 68, 190, 32, 165, 136, 123, 64, 73, 15, 246, 128, 146, 30, 235, 256, 35, 60, 213, 255, 70, 120, 169, 253, 140, 240, 81, 249, 23, 223, 162, 241, 46, 189, 67, 225, 92, 121, 134, 193, 184, 242, 11, 129, 111, 227, 22, 1, 222, 197, 44, 2, 187, 137, 88, 4, 117, 17, 176, 8, 234, 34, 95, 16, 211, 68, 190, 32, 165, 136, 123, 64, 73, 15, 246, 128, 146, 30, 235, 256, 35, 60, 213, 255, 70, 120, 169, 253, 140, 240, 81, 249, 23, 223, 162, 241, 46, 189, 67, 225, 92, 121, 134, 193, 184, 242, 11, 129, 111, 227, 22, 1, 222, 197, 44, 2, 187, 137, 88, 4, 117, 17, 176, 8, 234, 34, 95, 16, 211, 68, 190, 32, 165, 136, 123, 64, 73, 15, 246, 128, 146, 30, 235, 256, 35, 60, 213, 255, 70, 120, 169, 253, 140, 240, 81, 249, 23, 223, 162, 241, 46, 189, 67, 225, 92, 121, 134, 193, 184, 242, 11, 129, 111, 227, 22, 1], +[1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1], +[1, 224, 61, 43, 123, 53, 50, 149, 223, 94, 239, 80, 187, 254, 99, 74, 128, 145, 98, 107, 67, 102, 232, 54, 17, 210, 9, 217, 35, 130, 79, 220, 193, 56, 208, 75, 95, 206, 141, 230, 120, 152, 124, 20, 111, 192, 89, 147, 32, 229, 153, 91, 81, 154, 58, 142, 197, 181, 195, 247, 73, 161, 84, 55, 241, 14, 52, 83, 88, 180, 228, 186, 30, 38, 31, 5, 92, 48, 215, 101, 8, 250, 231, 87, 213, 167, 143, 164, 242, 238, 113, 126, 211, 233, 21, 78, 253, 132, 13, 85, 22, 45, 57, 175, 136, 138, 72, 194, 23, 12, 118, 218, 2, 191, 122, 86, 246, 106, 100, 41, 189, 188, 221, 160, 117, 251, 198, 148, 256, 33, 196, 214, 134, 204, 207, 108, 34, 163, 18, 177, 70, 3, 158, 183, 129, 112, 159, 150, 190, 155, 25, 203, 240, 47, 248, 40, 222, 127, 178, 37, 64, 201, 49, 182, 162, 51, 116, 27, 137, 105, 133, 237, 146, 65, 168, 110, 225, 28, 104, 166, 176, 103, 199, 115, 60, 76, 62, 10, 184, 96, 173, 202, 16, 243, 205, 174, 169, 77, 29, 71, 227, 219, 226, 252, 165, 209, 42, 156, 249, 7, 26, 170, 44, 90, 114, 93, 15, 19, 144, 131, 46, 24, 236, 179, 4, 125, 244, 172, 235, 212, 200, 82, 121, 119, 185, 63, 234, 245, 139, 39, 255, 66, 135, 171, 11, 151, 157, 216, 68, 69, 36, 97, 140, 6, 59, 109, 1], +[1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1], +[1, 226, 190, 21, 120, 135, 184, 207, 8, 9, 235, 168, 189, 52, 187, 114, 64, 72, 81, 59, 227, 159, 211, 141, 255, 62, 134, 215, 17, 244, 146, 100, 241, 239, 44, 178, 136, 153, 140, 29, 129, 113, 95, 139, 60, 196, 92, 232, 4, 133, 246, 84, 223, 26, 222, 57, 32, 36, 169, 158, 242, 208, 234, 199, 256, 31, 67, 236, 137, 122, 73, 50, 249, 248, 22, 89, 68, 205, 70, 143, 193, 185, 176, 198, 30, 98, 46, 116, 2, 195, 123, 42, 240, 13, 111, 157, 16, 18, 213, 79, 121, 104, 117, 228, 128, 144, 162, 118, 197, 61, 165, 25, 253, 124, 11, 173, 34, 231, 35, 200, 225, 221, 88, 99, 15, 49, 23, 58, 1, 226, 190, 21, 120, 135, 184, 207, 8, 9, 235, 168, 189, 52, 187, 114, 64, 72, 81, 59, 227, 159, 211, 141, 255, 62, 134, 215, 17, 244, 146, 100, 241, 239, 44, 178, 136, 153, 140, 29, 129, 113, 95, 139, 60, 196, 92, 232, 4, 133, 246, 84, 223, 26, 222, 57, 32, 36, 169, 158, 242, 208, 234, 199, 256, 31, 67, 236, 137, 122, 73, 50, 249, 248, 22, 89, 68, 205, 70, 143, 193, 185, 176, 198, 30, 98, 46, 116, 2, 195, 123, 42, 240, 13, 111, 157, 16, 18, 213, 79, 121, 104, 117, 228, 128, 144, 162, 118, 197, 61, 165, 25, 253, 124, 11, 173, 34, 231, 35, 200, 225, 221, 88, 99, 15, 49, 23, 58, 1], +[1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1], +[1, 228, 70, 26, 17, 21, 162, 185, 32, 100, 184, 61, 30, 158, 44, 9, 253, 116, 234, 153, 189, 173, 123, 31, 129, 114, 35, 13, 137, 139, 81, 221, 16, 50, 92, 159, 15, 79, 22, 133, 255, 58, 117, 205, 223, 215, 190, 144, 193, 57, 146, 135, 197, 198, 169, 239, 8, 25, 46, 208, 136, 168, 11, 195, 256, 29, 187, 231, 240, 236, 95, 72, 225, 157, 73, 196, 227, 99, 213, 248, 4, 141, 23, 104, 68, 84, 134, 226, 128, 143, 222, 244, 120, 118, 176, 36, 241, 207, 165, 98, 242, 178, 235, 124, 2, 199, 140, 52, 34, 42, 67, 113, 64, 200, 111, 122, 60, 59, 88, 18, 249, 232, 211, 49, 121, 89, 246, 62, 1, 228, 70, 26, 17, 21, 162, 185, 32, 100, 184, 61, 30, 158, 44, 9, 253, 116, 234, 153, 189, 173, 123, 31, 129, 114, 35, 13, 137, 139, 81, 221, 16, 50, 92, 159, 15, 79, 22, 133, 255, 58, 117, 205, 223, 215, 190, 144, 193, 57, 146, 135, 197, 198, 169, 239, 8, 25, 46, 208, 136, 168, 11, 195, 256, 29, 187, 231, 240, 236, 95, 72, 225, 157, 73, 196, 227, 99, 213, 248, 4, 141, 23, 104, 68, 84, 134, 226, 128, 143, 222, 244, 120, 118, 176, 36, 241, 207, 165, 98, 242, 178, 235, 124, 2, 199, 140, 52, 34, 42, 67, 113, 64, 200, 111, 122, 60, 59, 88, 18, 249, 232, 211, 49, 121, 89, 246, 62, 1], +[1, 229, 13, 150, 169, 151, 141, 164, 34, 76, 185, 217, 92, 251, 168, 179, 128, 14, 122, 182, 44, 53, 58, 175, 240, 219, 36, 20, 211, 3, 173, 39, 193, 250, 196, 166, 235, 102, 228, 41, 137, 19, 239, 247, 23, 127, 42, 109, 32, 132, 159, 174, 11, 206, 143, 108, 60, 119, 9, 5, 117, 65, 236, 74, 241, 191, 49, 170, 123, 154, 57, 203, 227, 69, 124, 126, 70, 96, 139, 220, 8, 33, 104, 172, 67, 180, 100, 27, 15, 94, 195, 194, 222, 209, 59, 147, 253, 112, 205, 171, 95, 167, 207, 115, 121, 210, 31, 160, 146, 24, 99, 55, 2, 201, 26, 43, 81, 45, 25, 71, 68, 152, 113, 177, 184, 245, 79, 101, 256, 28, 244, 107, 88, 106, 116, 93, 223, 181, 72, 40, 165, 6, 89, 78, 129, 243, 135, 75, 213, 204, 199, 82, 17, 38, 221, 237, 46, 254, 84, 218, 64, 7, 61, 91, 22, 155, 29, 216, 120, 238, 18, 10, 234, 130, 215, 148, 225, 125, 98, 83, 246, 51, 114, 149, 197, 138, 248, 252, 140, 192, 21, 183, 16, 66, 208, 87, 134, 103, 200, 54, 30, 188, 133, 131, 187, 161, 118, 37, 249, 224, 153, 85, 190, 77, 157, 230, 242, 163, 62, 63, 35, 48, 198, 110, 4, 145, 52, 86, 162, 90, 50, 142, 136, 47, 226, 97, 111, 233, 158, 202, 255, 56, 231, 214, 176, 212, 232, 186, 189, 105, 144, 80, 73, 12, 178, 156, 1], +[1, 230, 215, 106, 222, 174, 185, 145, 197, 78, 207, 65, 44, 97, 208, 38, 2, 203, 173, 212, 187, 91, 113, 33, 137, 156, 157, 130, 88, 194, 159, 76, 4, 149, 89, 167, 117, 182, 226, 66, 17, 55, 57, 3, 176, 131, 61, 152, 8, 41, 178, 77, 234, 107, 195, 132, 34, 110, 114, 6, 95, 5, 122, 47, 16, 82, 99, 154, 211, 214, 133, 7, 68, 220, 228, 12, 190, 10, 244, 94, 32, 164, 198, 51, 165, 171, 9, 14, 136, 183, 199, 24, 123, 20, 231, 188, 64, 71, 139, 102, 73, 85, 18, 28, 15, 109, 141, 48, 246, 40, 205, 119, 128, 142, 21, 204, 146, 170, 36, 56, 30, 218, 25, 96, 235, 80, 153, 238, 256, 27, 42, 151, 35, 83, 72, 112, 60, 179, 50, 192, 213, 160, 49, 219, 255, 54, 84, 45, 70, 166, 144, 224, 120, 101, 100, 127, 169, 63, 98, 181, 253, 108, 168, 90, 140, 75, 31, 191, 240, 202, 200, 254, 81, 126, 196, 105, 249, 216, 79, 180, 23, 150, 62, 125, 223, 147, 143, 251, 162, 252, 135, 210, 241, 175, 158, 103, 46, 43, 124, 250, 189, 37, 29, 245, 67, 247, 13, 163, 225, 93, 59, 206, 92, 86, 248, 243, 121, 74, 58, 233, 134, 237, 26, 69, 193, 186, 118, 155, 184, 172, 239, 229, 242, 148, 116, 209, 11, 217, 52, 138, 129, 115, 236, 53, 111, 87, 221, 201, 227, 39, 232, 161, 22, 177, 104, 19, 1], +[1, 231, 162, 157, 30, 248, 234, 84, 129, 244, 81, 207, 15, 124, 117, 42, 193, 122, 169, 232, 136, 62, 187, 21, 225, 61, 213, 116, 68, 31, 222, 139, 241, 159, 235, 58, 34, 144, 111, 198, 249, 208, 246, 29, 17, 72, 184, 99, 253, 104, 123, 143, 137, 36, 92, 178, 255, 52, 190, 200, 197, 18, 46, 89, 256, 26, 95, 100, 227, 9, 23, 173, 128, 13, 176, 50, 242, 133, 140, 215, 64, 135, 88, 25, 121, 195, 70, 236, 32, 196, 44, 141, 189, 226, 35, 118, 16, 98, 22, 199, 223, 113, 146, 59, 8, 49, 11, 228, 240, 185, 73, 158, 4, 153, 134, 114, 120, 221, 165, 79, 2, 205, 67, 57, 60, 239, 211, 168, 1, 231, 162, 157, 30, 248, 234, 84, 129, 244, 81, 207, 15, 124, 117, 42, 193, 122, 169, 232, 136, 62, 187, 21, 225, 61, 213, 116, 68, 31, 222, 139, 241, 159, 235, 58, 34, 144, 111, 198, 249, 208, 246, 29, 17, 72, 184, 99, 253, 104, 123, 143, 137, 36, 92, 178, 255, 52, 190, 200, 197, 18, 46, 89, 256, 26, 95, 100, 227, 9, 23, 173, 128, 13, 176, 50, 242, 133, 140, 215, 64, 135, 88, 25, 121, 195, 70, 236, 32, 196, 44, 141, 189, 226, 35, 118, 16, 98, 22, 199, 223, 113, 146, 59, 8, 49, 11, 228, 240, 185, 73, 158, 4, 153, 134, 114, 120, 221, 165, 79, 2, 205, 67, 57, 60, 239, 211, 168, 1], +[1, 232, 111, 52, 242, 118, 134, 248, 225, 29, 46, 135, 223, 79, 81, 31, 253, 100, 70, 49, 60, 42, 235, 36, 128, 141, 73, 231, 136, 198, 190, 133, 16, 114, 234, 61, 17, 89, 88, 113, 2, 207, 222, 104, 227, 236, 11, 239, 193, 58, 92, 13, 189, 158, 162, 62, 249, 200, 140, 98, 120, 84, 213, 72, 256, 25, 146, 205, 15, 139, 123, 9, 32, 228, 211, 122, 34, 178, 176, 226, 4, 157, 187, 208, 197, 215, 22, 221, 129, 116, 184, 26, 121, 59, 67, 124, 241, 143, 23, 196, 240, 168, 169, 144, 255, 50, 35, 153, 30, 21, 246, 18, 64, 199, 165, 244, 68, 99, 95, 195, 8, 57, 117, 159, 137, 173, 44, 185, 1, 232, 111, 52, 242, 118, 134, 248, 225, 29, 46, 135, 223, 79, 81, 31, 253, 100, 70, 49, 60, 42, 235, 36, 128, 141, 73, 231, 136, 198, 190, 133, 16, 114, 234, 61, 17, 89, 88, 113, 2, 207, 222, 104, 227, 236, 11, 239, 193, 58, 92, 13, 189, 158, 162, 62, 249, 200, 140, 98, 120, 84, 213, 72, 256, 25, 146, 205, 15, 139, 123, 9, 32, 228, 211, 122, 34, 178, 176, 226, 4, 157, 187, 208, 197, 215, 22, 221, 129, 116, 184, 26, 121, 59, 67, 124, 241, 143, 23, 196, 240, 168, 169, 144, 255, 50, 35, 153, 30, 21, 246, 18, 64, 199, 165, 244, 68, 99, 95, 195, 8, 57, 117, 159, 137, 173, 44, 185, 1], +[1, 233, 62, 54, 246, 7, 89, 177, 121, 180, 49, 109, 211, 76, 232, 86, 249, 192, 18, 82, 88, 201, 59, 126, 60, 102, 122, 156, 111, 163, 200, 83, 64, 6, 113, 115, 67, 191, 42, 20, 34, 212, 52, 37, 140, 238, 199, 107, 2, 209, 124, 108, 235, 14, 178, 97, 242, 103, 98, 218, 165, 152, 207, 172, 241, 127, 36, 164, 176, 145, 118, 252, 120, 204, 244, 55, 222, 69, 143, 166, 128, 12, 226, 230, 134, 125, 84, 40, 68, 167, 104, 74, 23, 219, 141, 214, 4, 161, 248, 216, 213, 28, 99, 194, 227, 206, 196, 179, 73, 47, 157, 87, 225, 254, 72, 71, 95, 33, 236, 247, 240, 151, 231, 110, 187, 138, 29, 75, 256, 24, 195, 203, 11, 250, 168, 80, 136, 77, 208, 148, 46, 181, 25, 171, 8, 65, 239, 175, 169, 56, 198, 131, 197, 155, 135, 101, 146, 94, 57, 174, 193, 251, 144, 142, 190, 66, 215, 237, 223, 45, 205, 220, 117, 19, 58, 150, 255, 48, 133, 149, 22, 243, 79, 160, 15, 154, 159, 39, 92, 105, 50, 85, 16, 130, 221, 93, 81, 112, 139, 5, 137, 53, 13, 202, 35, 188, 114, 91, 129, 245, 31, 27, 123, 132, 173, 217, 189, 90, 153, 183, 234, 38, 116, 43, 253, 96, 9, 41, 44, 229, 158, 63, 30, 51, 61, 78, 184, 210, 100, 170, 32, 3, 185, 186, 162, 224, 21, 10, 17, 106, 26, 147, 70, 119, 228, 182, 1], +[1, 234, 15, 169, 225, 222, 34, 246, 253, 92, 197, 95, 128, 140, 121, 44, 16, 146, 240, 134, 2, 211, 30, 81, 193, 187, 68, 235, 249, 184, 137, 190, 256, 23, 242, 88, 32, 35, 223, 11, 4, 165, 60, 162, 129, 117, 136, 213, 241, 111, 17, 123, 255, 46, 227, 176, 64, 70, 189, 22, 8, 73, 120, 67, 1, 234, 15, 169, 225, 222, 34, 246, 253, 92, 197, 95, 128, 140, 121, 44, 16, 146, 240, 134, 2, 211, 30, 81, 193, 187, 68, 235, 249, 184, 137, 190, 256, 23, 242, 88, 32, 35, 223, 11, 4, 165, 60, 162, 129, 117, 136, 213, 241, 111, 17, 123, 255, 46, 227, 176, 64, 70, 189, 22, 8, 73, 120, 67, 1, 234, 15, 169, 225, 222, 34, 246, 253, 92, 197, 95, 128, 140, 121, 44, 16, 146, 240, 134, 2, 211, 30, 81, 193, 187, 68, 235, 249, 184, 137, 190, 256, 23, 242, 88, 32, 35, 223, 11, 4, 165, 60, 162, 129, 117, 136, 213, 241, 111, 17, 123, 255, 46, 227, 176, 64, 70, 189, 22, 8, 73, 120, 67, 1, 234, 15, 169, 225, 222, 34, 246, 253, 92, 197, 95, 128, 140, 121, 44, 16, 146, 240, 134, 2, 211, 30, 81, 193, 187, 68, 235, 249, 184, 137, 190, 256, 23, 242, 88, 32, 35, 223, 11, 4, 165, 60, 162, 129, 117, 136, 213, 241, 111, 17, 123, 255, 46, 227, 176, 64, 70, 189, 22, 8, 73, 120, 67, 1], +[1, 235, 227, 146, 129, 246, 242, 73, 193, 123, 121, 165, 225, 190, 189, 211, 241, 95, 223, 234, 249, 176, 240, 117, 253, 88, 120, 187, 255, 44, 60, 222, 256, 22, 30, 111, 128, 11, 15, 184, 64, 134, 136, 92, 32, 67, 68, 46, 16, 162, 34, 23, 8, 81, 17, 140, 4, 169, 137, 70, 2, 213, 197, 35, 1, 235, 227, 146, 129, 246, 242, 73, 193, 123, 121, 165, 225, 190, 189, 211, 241, 95, 223, 234, 249, 176, 240, 117, 253, 88, 120, 187, 255, 44, 60, 222, 256, 22, 30, 111, 128, 11, 15, 184, 64, 134, 136, 92, 32, 67, 68, 46, 16, 162, 34, 23, 8, 81, 17, 140, 4, 169, 137, 70, 2, 213, 197, 35, 1, 235, 227, 146, 129, 246, 242, 73, 193, 123, 121, 165, 225, 190, 189, 211, 241, 95, 223, 234, 249, 176, 240, 117, 253, 88, 120, 187, 255, 44, 60, 222, 256, 22, 30, 111, 128, 11, 15, 184, 64, 134, 136, 92, 32, 67, 68, 46, 16, 162, 34, 23, 8, 81, 17, 140, 4, 169, 137, 70, 2, 213, 197, 35, 1, 235, 227, 146, 129, 246, 242, 73, 193, 123, 121, 165, 225, 190, 189, 211, 241, 95, 223, 234, 249, 176, 240, 117, 253, 88, 120, 187, 255, 44, 60, 222, 256, 22, 30, 111, 128, 11, 15, 184, 64, 134, 136, 92, 32, 67, 68, 46, 16, 162, 34, 23, 8, 81, 17, 140, 4, 169, 137, 70, 2, 213, 197, 35, 1], +[1, 236, 184, 248, 189, 143, 81, 98, 255, 42, 146, 18, 136, 228, 95, 61, 4, 173, 222, 221, 242, 58, 67, 135, 249, 168, 70, 72, 30, 141, 123, 244, 16, 178, 117, 113, 197, 232, 11, 26, 225, 158, 23, 31, 120, 50, 235, 205, 64, 198, 211, 195, 17, 157, 44, 104, 129, 118, 92, 124, 223, 200, 169, 49, 256, 21, 73, 9, 68, 114, 176, 159, 2, 215, 111, 239, 121, 29, 162, 196, 253, 84, 35, 36, 15, 199, 190, 122, 8, 89, 187, 185, 227, 116, 134, 13, 241, 79, 140, 144, 60, 25, 246, 231, 32, 99, 234, 226, 137, 207, 22, 52, 193, 59, 46, 62, 240, 100, 213, 153, 128, 139, 165, 133, 34, 57, 88, 208, 1, 236, 184, 248, 189, 143, 81, 98, 255, 42, 146, 18, 136, 228, 95, 61, 4, 173, 222, 221, 242, 58, 67, 135, 249, 168, 70, 72, 30, 141, 123, 244, 16, 178, 117, 113, 197, 232, 11, 26, 225, 158, 23, 31, 120, 50, 235, 205, 64, 198, 211, 195, 17, 157, 44, 104, 129, 118, 92, 124, 223, 200, 169, 49, 256, 21, 73, 9, 68, 114, 176, 159, 2, 215, 111, 239, 121, 29, 162, 196, 253, 84, 35, 36, 15, 199, 190, 122, 8, 89, 187, 185, 227, 116, 134, 13, 241, 79, 140, 144, 60, 25, 246, 231, 32, 99, 234, 226, 137, 207, 22, 52, 193, 59, 46, 62, 240, 100, 213, 153, 128, 139, 165, 133, 34, 57, 88, 208, 1], +[1, 237, 143, 224, 146, 164, 61, 65, 242, 43, 168, 238, 123, 110, 113, 53, 225, 126, 50, 28, 211, 149, 104, 233, 223, 166, 21, 94, 176, 78, 239, 103, 253, 80, 199, 132, 187, 115, 13, 254, 60, 85, 99, 76, 22, 74, 62, 45, 128, 10, 57, 145, 184, 175, 98, 96, 136, 107, 173, 138, 67, 202, 72, 102, 16, 194, 232, 243, 23, 54, 205, 12, 17, 174, 118, 210, 169, 218, 9, 77, 2, 217, 29, 191, 35, 71, 122, 130, 227, 86, 79, 219, 246, 220, 226, 106, 193, 252, 100, 56, 165, 41, 208, 209, 189, 75, 42, 188, 95, 156, 221, 206, 249, 160, 141, 7, 117, 230, 26, 251, 120, 170, 198, 152, 44, 148, 124, 90, 256, 20, 114, 33, 111, 93, 196, 192, 15, 214, 89, 19, 134, 147, 144, 204, 32, 131, 207, 229, 46, 108, 153, 24, 34, 91, 236, 163, 81, 179, 18, 154, 4, 177, 58, 125, 70, 142, 244, 3, 197, 172, 158, 181, 235, 183, 195, 212, 129, 247, 200, 112, 73, 82, 159, 161, 121, 150, 84, 119, 190, 55, 185, 155, 241, 63, 25, 14, 234, 203, 52, 245, 240, 83, 139, 47, 88, 39, 248, 180, 255, 40, 228, 66, 222, 186, 135, 127, 30, 171, 178, 38, 11, 37, 31, 151, 64, 5, 157, 201, 92, 216, 49, 48, 68, 182, 215, 69, 162, 101, 36, 51, 8, 97, 116, 250, 140, 27, 231, 6, 137, 87, 59, 105, 213, 109, 133, 167, 1], +[1, 238, 104, 80, 22, 96, 232, 218, 227, 56, 221, 170, 111, 204, 236, 142, 129, 119, 52, 40, 11, 48, 116, 109, 242, 28, 239, 85, 184, 102, 118, 71, 193, 188, 26, 20, 134, 24, 58, 183, 121, 14, 248, 171, 92, 51, 59, 164, 225, 94, 13, 10, 67, 12, 29, 220, 189, 7, 124, 214, 46, 154, 158, 82, 241, 47, 135, 5, 162, 6, 143, 110, 223, 132, 62, 107, 23, 77, 79, 41, 249, 152, 196, 131, 81, 3, 200, 55, 240, 66, 31, 182, 140, 167, 168, 149, 253, 76, 98, 194, 169, 130, 100, 156, 120, 33, 144, 91, 70, 212, 84, 203, 255, 38, 49, 97, 213, 65, 50, 78, 60, 145, 72, 174, 35, 106, 42, 230, 256, 19, 153, 177, 235, 161, 25, 39, 30, 201, 36, 87, 146, 53, 21, 115, 128, 138, 205, 217, 246, 209, 141, 148, 15, 229, 18, 172, 73, 155, 139, 186, 64, 69, 231, 237, 123, 233, 199, 74, 136, 243, 9, 86, 165, 206, 198, 93, 32, 163, 244, 247, 190, 245, 228, 37, 68, 250, 133, 43, 211, 103, 99, 175, 16, 210, 122, 252, 95, 251, 114, 147, 34, 125, 195, 150, 234, 180, 178, 216, 8, 105, 61, 126, 176, 254, 57, 202, 17, 191, 226, 75, 117, 90, 89, 108, 4, 181, 159, 63, 88, 127, 157, 101, 137, 224, 113, 166, 187, 45, 173, 54, 2, 219, 208, 160, 44, 192, 207, 179, 197, 112, 185, 83, 222, 151, 215, 27, 1], +[1, 239, 67, 79, 120, 153, 73, 228, 8, 113, 22, 118, 189, 196, 70, 25, 64, 133, 176, 173, 227, 26, 46, 200, 255, 36, 123, 99, 17, 208, 111, 58, 241, 31, 213, 21, 136, 122, 117, 207, 129, 248, 162, 168, 60, 205, 165, 114, 4, 185, 11, 59, 223, 98, 35, 141, 32, 195, 88, 215, 242, 13, 23, 100, 256, 18, 190, 178, 137, 104, 184, 29, 249, 144, 235, 139, 68, 61, 187, 232, 193, 124, 81, 84, 30, 231, 211, 57, 2, 221, 134, 158, 240, 49, 146, 199, 16, 226, 44, 236, 121, 135, 140, 50, 128, 9, 95, 89, 197, 52, 92, 143, 253, 72, 246, 198, 34, 159, 222, 116, 225, 62, 169, 42, 15, 244, 234, 157, 1, 239, 67, 79, 120, 153, 73, 228, 8, 113, 22, 118, 189, 196, 70, 25, 64, 133, 176, 173, 227, 26, 46, 200, 255, 36, 123, 99, 17, 208, 111, 58, 241, 31, 213, 21, 136, 122, 117, 207, 129, 248, 162, 168, 60, 205, 165, 114, 4, 185, 11, 59, 223, 98, 35, 141, 32, 195, 88, 215, 242, 13, 23, 100, 256, 18, 190, 178, 137, 104, 184, 29, 249, 144, 235, 139, 68, 61, 187, 232, 193, 124, 81, 84, 30, 231, 211, 57, 2, 221, 134, 158, 240, 49, 146, 199, 16, 226, 44, 236, 121, 135, 140, 50, 128, 9, 95, 89, 197, 52, 92, 143, 253, 72, 246, 198, 34, 159, 222, 116, 225, 62, 169, 42, 15, 244, 234, 157, 1], +[1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1], +[1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1], +[1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1], +[1, 243, 196, 83, 123, 77, 207, 186, 223, 219, 18, 5, 187, 209, 158, 101, 128, 7, 159, 87, 67, 90, 25, 164, 17, 19, 248, 126, 35, 24, 178, 78, 193, 125, 49, 85, 95, 212, 116, 175, 120, 119, 133, 194, 111, 245, 168, 218, 32, 66, 104, 86, 81, 151, 199, 41, 197, 69, 62, 160, 73, 6, 173, 148, 241, 224, 205, 214, 88, 53, 29, 108, 30, 94, 226, 177, 92, 254, 42, 183, 8, 145, 26, 150, 213, 102, 114, 203, 242, 210, 144, 40, 211, 130, 236, 37, 253, 56, 244, 182, 22, 206, 200, 27, 136, 152, 185, 237, 23, 192, 139, 110, 2, 229, 135, 166, 246, 154, 157, 115, 189, 181, 36, 10, 117, 161, 59, 202, 256, 14, 61, 174, 134, 180, 50, 71, 34, 38, 239, 252, 70, 48, 99, 156, 129, 250, 98, 170, 190, 167, 232, 93, 240, 238, 9, 131, 222, 233, 79, 179, 64, 132, 208, 172, 162, 45, 141, 82, 137, 138, 124, 63, 146, 12, 89, 39, 225, 191, 153, 171, 176, 106, 58, 216, 60, 188, 195, 97, 184, 251, 84, 109, 16, 33, 52, 43, 169, 204, 228, 149, 227, 163, 31, 80, 165, 3, 215, 74, 249, 112, 231, 107, 44, 155, 143, 54, 15, 47, 113, 217, 46, 127, 21, 220, 4, 201, 13, 75, 235, 51, 57, 230, 121, 105, 72, 20, 234, 65, 118, 147, 255, 28, 122, 91, 11, 103, 100, 142, 68, 76, 221, 247, 140, 96, 198, 55, 1], +[1, 244, 169, 116, 34, 72, 92, 89, 128, 135, 44, 199, 240, 221, 211, 84, 193, 61, 235, 29, 137, 18, 23, 215, 32, 98, 11, 114, 60, 248, 117, 21, 241, 208, 123, 200, 227, 133, 70, 118, 8, 153, 67, 157, 15, 62, 222, 198, 253, 52, 95, 50, 121, 226, 146, 158, 2, 231, 81, 232, 68, 144, 184, 178, 256, 13, 88, 141, 223, 185, 165, 168, 129, 122, 213, 58, 17, 36, 46, 173, 64, 196, 22, 228, 120, 239, 234, 42, 225, 159, 246, 143, 197, 9, 140, 236, 16, 49, 134, 57, 30, 124, 187, 139, 249, 104, 190, 100, 242, 195, 35, 59, 4, 205, 162, 207, 136, 31, 111, 99, 255, 26, 176, 25, 189, 113, 73, 79, 1, 244, 169, 116, 34, 72, 92, 89, 128, 135, 44, 199, 240, 221, 211, 84, 193, 61, 235, 29, 137, 18, 23, 215, 32, 98, 11, 114, 60, 248, 117, 21, 241, 208, 123, 200, 227, 133, 70, 118, 8, 153, 67, 157, 15, 62, 222, 198, 253, 52, 95, 50, 121, 226, 146, 158, 2, 231, 81, 232, 68, 144, 184, 178, 256, 13, 88, 141, 223, 185, 165, 168, 129, 122, 213, 58, 17, 36, 46, 173, 64, 196, 22, 228, 120, 239, 234, 42, 225, 159, 246, 143, 197, 9, 140, 236, 16, 49, 134, 57, 30, 124, 187, 139, 249, 104, 190, 100, 242, 195, 35, 59, 4, 205, 162, 207, 136, 31, 111, 99, 255, 26, 176, 25, 189, 113, 73, 79, 1], +[1, 245, 144, 71, 176, 201, 158, 160, 136, 167, 52, 147, 35, 94, 157, 172, 249, 96, 133, 203, 134, 191, 21, 5, 197, 206, 98, 109, 234, 19, 29, 166, 64, 3, 221, 175, 213, 14, 89, 217, 223, 151, 244, 156, 184, 105, 25, 214, 2, 233, 31, 142, 95, 145, 59, 63, 15, 77, 104, 37, 70, 188, 57, 87, 241, 192, 9, 149, 11, 125, 42, 10, 137, 155, 196, 218, 211, 38, 58, 75, 128, 6, 185, 93, 169, 28, 178, 177, 189, 45, 231, 55, 111, 210, 50, 171, 4, 209, 62, 27, 190, 33, 118, 126, 30, 154, 208, 74, 140, 119, 114, 174, 225, 127, 18, 41, 22, 250, 84, 20, 17, 53, 135, 179, 165, 76, 116, 150, 256, 12, 113, 186, 81, 56, 99, 97, 121, 90, 205, 110, 222, 163, 100, 85, 8, 161, 124, 54, 123, 66, 236, 252, 60, 51, 159, 148, 23, 238, 228, 91, 193, 254, 36, 82, 44, 243, 168, 40, 34, 106, 13, 101, 73, 152, 232, 43, 255, 24, 226, 115, 162, 112, 198, 194, 242, 180, 153, 220, 187, 69, 200, 170, 16, 65, 248, 108, 246, 132, 215, 247, 120, 102, 61, 39, 46, 219, 199, 182, 129, 251, 72, 164, 88, 229, 79, 80, 68, 212, 26, 202, 146, 47, 207, 86, 253, 48, 195, 230, 67, 224, 139, 131, 227, 103, 49, 183, 117, 138, 143, 83, 32, 130, 239, 216, 235, 7, 173, 237, 240, 204, 122, 78, 92, 181, 141, 107, 1], +[1, 246, 121, 211, 249, 88, 60, 111, 64, 67, 34, 140, 2, 235, 242, 165, 241, 176, 120, 222, 128, 134, 68, 23, 4, 213, 227, 73, 225, 95, 240, 187, 256, 11, 136, 46, 8, 169, 197, 146, 193, 190, 223, 117, 255, 22, 15, 92, 16, 81, 137, 35, 129, 123, 189, 234, 253, 44, 30, 184, 32, 162, 17, 70, 1, 246, 121, 211, 249, 88, 60, 111, 64, 67, 34, 140, 2, 235, 242, 165, 241, 176, 120, 222, 128, 134, 68, 23, 4, 213, 227, 73, 225, 95, 240, 187, 256, 11, 136, 46, 8, 169, 197, 146, 193, 190, 223, 117, 255, 22, 15, 92, 16, 81, 137, 35, 129, 123, 189, 234, 253, 44, 30, 184, 32, 162, 17, 70, 1, 246, 121, 211, 249, 88, 60, 111, 64, 67, 34, 140, 2, 235, 242, 165, 241, 176, 120, 222, 128, 134, 68, 23, 4, 213, 227, 73, 225, 95, 240, 187, 256, 11, 136, 46, 8, 169, 197, 146, 193, 190, 223, 117, 255, 22, 15, 92, 16, 81, 137, 35, 129, 123, 189, 234, 253, 44, 30, 184, 32, 162, 17, 70, 1, 246, 121, 211, 249, 88, 60, 111, 64, 67, 34, 140, 2, 235, 242, 165, 241, 176, 120, 222, 128, 134, 68, 23, 4, 213, 227, 73, 225, 95, 240, 187, 256, 11, 136, 46, 8, 169, 197, 146, 193, 190, 223, 117, 255, 22, 15, 92, 16, 81, 137, 35, 129, 123, 189, 234, 253, 44, 30, 184, 32, 162, 17, 70, 1], +[1, 247, 100, 28, 234, 230, 13, 127, 15, 107, 215, 163, 169, 109, 195, 106, 225, 63, 141, 132, 222, 93, 98, 48, 34, 174, 59, 181, 246, 110, 185, 206, 253, 40, 114, 145, 92, 108, 205, 6, 197, 86, 168, 119, 95, 78, 248, 90, 128, 5, 207, 243, 140, 142, 122, 65, 121, 75, 21, 47, 44, 74, 31, 204, 16, 97, 58, 191, 146, 82, 208, 233, 240, 170, 99, 38, 134, 202, 36, 154, 2, 237, 200, 56, 211, 203, 26, 254, 30, 214, 173, 69, 81, 218, 133, 212, 193, 126, 25, 7, 187, 186, 196, 96, 68, 91, 118, 105, 235, 220, 113, 155, 249, 80, 228, 33, 184, 216, 153, 12, 137, 172, 79, 238, 190, 156, 239, 180, 256, 10, 157, 229, 23, 27, 244, 130, 242, 150, 42, 94, 88, 148, 62, 151, 32, 194, 116, 125, 35, 164, 159, 209, 223, 83, 198, 76, 11, 147, 72, 51, 4, 217, 143, 112, 165, 149, 52, 251, 60, 171, 89, 138, 162, 179, 9, 167, 129, 252, 50, 14, 117, 115, 135, 192, 136, 182, 236, 210, 213, 183, 226, 53, 241, 160, 199, 66, 111, 175, 49, 24, 17, 87, 158, 219, 123, 55, 221, 103, 255, 20, 57, 201, 46, 54, 231, 3, 227, 43, 84, 188, 176, 39, 124, 45, 64, 131, 232, 250, 70, 71, 61, 161, 189, 166, 139, 152, 22, 37, 144, 102, 8, 177, 29, 224, 73, 41, 104, 245, 120, 85, 178, 19, 67, 101, 18, 77, 1], +[1, 248, 81, 42, 136, 61, 222, 58, 249, 72, 123, 178, 197, 26, 23, 50, 64, 195, 44, 118, 223, 49, 73, 114, 2, 239, 162, 84, 15, 122, 187, 116, 241, 144, 246, 99, 137, 52, 46, 100, 128, 133, 88, 236, 189, 98, 146, 228, 4, 221, 67, 168, 30, 244, 117, 232, 225, 31, 235, 198, 17, 104, 92, 200, 256, 9, 176, 215, 121, 196, 35, 199, 8, 185, 134, 79, 60, 231, 234, 207, 193, 62, 213, 139, 34, 208, 184, 143, 255, 18, 95, 173, 242, 135, 70, 141, 16, 113, 11, 158, 120, 205, 211, 157, 129, 124, 169, 21, 68, 159, 111, 29, 253, 36, 190, 89, 227, 13, 140, 25, 32, 226, 22, 59, 240, 153, 165, 57, 1, 248, 81, 42, 136, 61, 222, 58, 249, 72, 123, 178, 197, 26, 23, 50, 64, 195, 44, 118, 223, 49, 73, 114, 2, 239, 162, 84, 15, 122, 187, 116, 241, 144, 246, 99, 137, 52, 46, 100, 128, 133, 88, 236, 189, 98, 146, 228, 4, 221, 67, 168, 30, 244, 117, 232, 225, 31, 235, 198, 17, 104, 92, 200, 256, 9, 176, 215, 121, 196, 35, 199, 8, 185, 134, 79, 60, 231, 234, 207, 193, 62, 213, 139, 34, 208, 184, 143, 255, 18, 95, 173, 242, 135, 70, 141, 16, 113, 11, 158, 120, 205, 211, 157, 129, 124, 169, 21, 68, 159, 111, 29, 253, 36, 190, 89, 227, 13, 140, 25, 32, 226, 22, 59, 240, 153, 165, 57, 1], +[1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1], +[1, 250, 49, 171, 88, 155, 200, 142, 34, 19, 124, 160, 165, 130, 118, 202, 128, 132, 104, 43, 213, 51, 157, 186, 240, 119, 195, 177, 46, 192, 198, 156, 193, 191, 205, 107, 22, 103, 50, 164, 137, 69, 31, 40, 234, 161, 158, 179, 32, 33, 26, 75, 246, 77, 232, 175, 60, 94, 113, 237, 140, 48, 178, 39, 241, 112, 244, 91, 134, 90, 141, 41, 227, 210, 72, 10, 187, 233, 168, 109, 8, 201, 135, 83, 190, 212, 58, 108, 15, 152, 221, 252, 35, 12, 173, 74, 253, 28, 61, 87, 162, 151, 228, 203, 121, 181, 18, 131, 111, 251, 42, 220, 2, 243, 98, 85, 176, 53, 143, 27, 68, 38, 248, 63, 73, 3, 236, 147, 256, 7, 208, 86, 169, 102, 57, 115, 223, 238, 133, 97, 92, 127, 139, 55, 129, 125, 153, 214, 44, 206, 100, 71, 17, 138, 62, 80, 211, 65, 59, 101, 64, 66, 52, 150, 235, 154, 207, 93, 120, 188, 226, 217, 23, 96, 99, 78, 225, 224, 231, 182, 11, 180, 25, 82, 197, 163, 144, 20, 117, 209, 79, 218, 16, 145, 13, 166, 123, 167, 116, 216, 30, 47, 185, 247, 70, 24, 89, 148, 249, 56, 122, 174, 67, 45, 199, 149, 242, 105, 36, 5, 222, 245, 84, 183, 4, 229, 196, 170, 95, 106, 29, 54, 136, 76, 239, 126, 146, 6, 215, 37, 255, 14, 159, 172, 81, 204, 114, 230, 189, 219, 9, 194, 184, 254, 21, 110, 1], +[1, 251, 36, 41, 11, 191, 139, 194, 121, 45, 244, 78, 46, 238, 114, 87, 249, 48, 226, 186, 169, 14, 173, 247, 60, 154, 104, 147, 146, 152, 116, 75, 64, 130, 248, 54, 190, 145, 158, 80, 34, 53, 196, 109, 117, 69, 100, 171, 2, 245, 72, 82, 22, 125, 21, 131, 242, 90, 231, 156, 92, 219, 228, 174, 241, 96, 195, 115, 81, 28, 89, 237, 120, 51, 208, 37, 35, 47, 232, 150, 128, 3, 239, 108, 123, 33, 59, 160, 68, 106, 135, 218, 234, 138, 200, 85, 4, 233, 144, 164, 44, 250, 42, 5, 227, 180, 205, 55, 184, 181, 199, 91, 225, 192, 133, 230, 162, 56, 178, 217, 240, 102, 159, 74, 70, 94, 207, 43, 256, 6, 221, 216, 246, 66, 118, 63, 136, 212, 13, 179, 211, 19, 143, 170, 8, 209, 31, 71, 88, 243, 84, 10, 197, 103, 153, 110, 111, 105, 141, 182, 193, 127, 9, 203, 67, 112, 99, 177, 223, 204, 61, 148, 140, 188, 157, 86, 255, 12, 185, 175, 235, 132, 236, 126, 15, 167, 26, 101, 165, 38, 29, 83, 16, 161, 62, 142, 176, 229, 168, 20, 137, 206, 49, 220, 222, 210, 25, 107, 129, 254, 18, 149, 134, 224, 198, 97, 189, 151, 122, 39, 23, 119, 57, 172, 253, 24, 113, 93, 213, 7, 215, 252, 30, 77, 52, 202, 73, 76, 58, 166, 32, 65, 124, 27, 95, 201, 79, 40, 17, 155, 98, 183, 187, 163, 50, 214, 1], +[1, 252, 25, 132, 111, 216, 205, 3, 242, 75, 139, 76, 134, 101, 9, 212, 225, 160, 228, 145, 46, 27, 122, 161, 223, 170, 178, 138, 81, 109, 226, 155, 253, 20, 157, 243, 70, 164, 208, 245, 60, 214, 215, 210, 235, 110, 221, 180, 128, 131, 116, 191, 73, 149, 26, 127, 136, 91, 59, 219, 190, 78, 124, 151, 16, 177, 143, 56, 234, 115, 196, 48, 17, 172, 168, 188, 88, 74, 144, 51, 2, 247, 50, 7, 222, 175, 153, 6, 227, 150, 21, 152, 11, 202, 18, 167, 193, 63, 199, 33, 92, 54, 244, 65, 189, 83, 99, 19, 162, 218, 195, 53, 249, 40, 57, 229, 140, 71, 159, 233, 120, 171, 173, 163, 213, 220, 185, 103, 256, 5, 232, 125, 146, 41, 52, 254, 15, 182, 118, 181, 123, 156, 248, 45, 32, 97, 29, 112, 211, 230, 135, 96, 34, 87, 79, 119, 176, 148, 31, 102, 4, 237, 100, 14, 187, 93, 49, 12, 197, 43, 42, 47, 22, 147, 36, 77, 129, 126, 141, 66, 184, 108, 231, 130, 121, 166, 198, 38, 67, 179, 133, 106, 241, 80, 114, 201, 23, 142, 61, 209, 240, 85, 89, 69, 169, 183, 113, 206, 255, 10, 207, 250, 35, 82, 104, 251, 30, 107, 236, 105, 246, 55, 239, 90, 64, 194, 58, 224, 165, 203, 13, 192, 68, 174, 158, 238, 95, 39, 62, 204, 8, 217, 200, 28, 117, 186, 98, 24, 137, 86, 84, 94, 44, 37, 72, 154, 1], +[1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1], +[1, 254, 9, 230, 81, 14, 215, 126, 136, 106, 196, 183, 222, 105, 199, 174, 249, 24, 185, 216, 123, 145, 79, 20, 197, 180, 231, 78, 23, 188, 207, 150, 64, 65, 62, 71, 44, 125, 139, 97, 223, 102, 208, 147, 73, 38, 143, 85, 2, 251, 18, 203, 162, 28, 173, 252, 15, 212, 135, 109, 187, 210, 141, 91, 241, 48, 113, 175, 246, 33, 158, 40, 137, 103, 205, 156, 46, 119, 157, 43, 128, 130, 124, 142, 88, 250, 21, 194, 189, 204, 159, 37, 146, 76, 29, 170, 4, 245, 36, 149, 67, 56, 89, 247, 30, 167, 13, 218, 117, 163, 25, 182, 225, 96, 226, 93, 235, 66, 59, 80, 17, 206, 153, 55, 92, 238, 57, 86, 256, 3, 248, 27, 176, 243, 42, 131, 121, 151, 61, 74, 35, 152, 58, 83, 8, 233, 72, 41, 134, 112, 178, 237, 60, 77, 26, 179, 234, 69, 50, 107, 193, 192, 195, 186, 213, 132, 118, 160, 34, 155, 49, 110, 184, 219, 114, 172, 255, 6, 239, 54, 95, 229, 84, 5, 242, 45, 122, 148, 70, 47, 116, 166, 16, 209, 144, 82, 11, 224, 99, 217, 120, 154, 52, 101, 211, 138, 100, 214, 129, 127, 133, 115, 169, 7, 236, 63, 68, 53, 98, 220, 111, 181, 228, 87, 253, 12, 221, 108, 190, 201, 168, 10, 227, 90, 244, 39, 140, 94, 232, 75, 32, 161, 31, 164, 22, 191, 198, 177, 240, 51, 104, 202, 165, 19, 200, 171, 1], +[1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1], +[1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1], +]; + +fn main(x: Field, y: pub Field) { + let mut acc: Field = 0; + for i in 0..257 { + for j in 0..257 { + acc += EXPONENTIATE[i][j]; + } + } + assert(!acc.lt(x)); + assert(x != y); +} diff --git a/test_programs/execution_success/regression_struct_array_conditional/Nargo.toml b/test_programs/execution_success/regression_struct_array_conditional/Nargo.toml new file mode 100644 index 00000000000..a0587210464 --- /dev/null +++ b/test_programs/execution_success/regression_struct_array_conditional/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_struct_array_conditional" +version = "0.1.0" +type = "bin" +authors = [""] + +[dependencies] diff --git a/test_programs/execution_success/regression_struct_array_conditional/Prover.toml b/test_programs/execution_success/regression_struct_array_conditional/Prover.toml new file mode 100644 index 00000000000..ef97f9d482a --- /dev/null +++ b/test_programs/execution_success/regression_struct_array_conditional/Prover.toml @@ -0,0 +1,18 @@ +y = 1 +z = 1 + +[[x]] +value = "0x23de33be058ce5504e1ade738db8bdacfe268fa9dbde777092bf1d38519bdf59" +counter = "10" +dummy = "0" + +[[x]] +value = "3" +counter = "2" +dummy = "0" + +[[x]] +value = "2" +counter = "0" +dummy = "0" + diff --git a/test_programs/execution_success/regression_struct_array_conditional/src/main.nr b/test_programs/execution_success/regression_struct_array_conditional/src/main.nr new file mode 100644 index 00000000000..17502a9fe50 --- /dev/null +++ b/test_programs/execution_success/regression_struct_array_conditional/src/main.nr @@ -0,0 +1,38 @@ +struct foo { + value: Field, + counter: u8, + dummy: u8, +} +struct bar { + dummy: [u8;3], + value: Field, + counter: u8, +} +struct bar_field { + dummy: [Field;3], + value: Field, + counter: u8, +} +fn main(x: [foo; 3], y: u32, z: u32) -> pub u8 { + let a = [y, z, x[y].counter as u32]; + let mut b = [bar { value: 0, counter: 0, dummy: [0; 3] }; 3]; + let mut c = [bar_field { value: 0, counter: 0, dummy: [0; 3] }; 3]; + for i in 0..3 { + b[i].value = x[i].value; + b[i].counter = x[i].counter; + b[i].dummy[0] = x[i].dummy; + c[i].value = x[i].value; + c[i].counter = x[i].counter; + c[i].dummy[0] = x[i].dummy as Field; + } + if z == 0 { + // offset + assert(y as u8 < x[y].counter); + assert(y <= a[y]); + // first element is compatible + assert(y as u8 < b[y].counter); + // fallback + assert(y as u8 < c[y].counter); + } + x[0].counter +} diff --git a/test_programs/execution_success/scalar_mul/Prover.toml b/test_programs/execution_success/scalar_mul/Prover.toml deleted file mode 100644 index 69b91cb5f31..00000000000 --- a/test_programs/execution_success/scalar_mul/Prover.toml +++ /dev/null @@ -1,7 +0,0 @@ -a = "1" -a_pub_x = "0x0000000000000000000000000000000000000000000000000000000000000001" -a_pub_y = "0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c" - -b = "2" -b_pub_x = "0x06ce1b0827aafa85ddeb49cdaa36306d19a74caa311e13d46d8bc688cdbffffe" -b_pub_y = "0x1c122f81a3a14964909ede0ba2a6855fc93faf6fa1a788bf467be7e7a43f80ac" \ No newline at end of file diff --git a/test_programs/execution_success/scalar_mul/src/main.nr b/test_programs/execution_success/scalar_mul/src/main.nr deleted file mode 100644 index e20f47907db..00000000000 --- a/test_programs/execution_success/scalar_mul/src/main.nr +++ /dev/null @@ -1,31 +0,0 @@ -use dep::std; - -fn main( - a: Field, - a_pub_x: pub Field, - a_pub_y: pub Field, - b: Field, - b_pub_x: pub Field, - b_pub_y: pub Field -) { - let mut priv_key = a; - let mut pub_x: Field = a_pub_x; - let mut pub_y: Field = a_pub_y; - if a != 1 { - // Change `a` in Prover.toml to test input `b` - priv_key = b; - pub_x = b_pub_x; - pub_y = b_pub_y; - } - let res = std::scalar_mul::fixed_base_embedded_curve(priv_key, 0); - assert(res[0] == pub_x); - assert(res[1] == pub_y); - let pub_point= std::scalar_mul::EmbeddedCurvePoint { x: pub_x, y: pub_y }; - let g1_y = 17631683881184975370165255887551781615748388533673675138860; - let g1= std::scalar_mul::EmbeddedCurvePoint { x: 1, y: g1_y }; - - let res = pub_point.double(); - let double = g1.add(g1); - - assert(double.x == res.x); -} diff --git a/test_programs/execution_success/sha256/src/main.nr b/test_programs/execution_success/sha256/src/main.nr index fd5340e2384..d4240ded8b3 100644 --- a/test_programs/execution_success/sha256/src/main.nr +++ b/test_programs/execution_success/sha256/src/main.nr @@ -14,6 +14,8 @@ use dep::std; fn main(x: Field, result: [u8; 32]) { // We use the `as` keyword here to denote the fact that we want to take just the first byte from the x Field // The padding is taken care of by the program - let digest = std::hash::sha256([x as u8]); + // docs:start:sha256_var + let digest = std::hash::sha256_var([x as u8], 1); + // docs:end:sha256_var assert(digest == result); } diff --git a/test_programs/compile_success_empty/simple_array_param/Nargo.toml b/test_programs/execution_success/simple_array_param/Nargo.toml similarity index 100% rename from test_programs/compile_success_empty/simple_array_param/Nargo.toml rename to test_programs/execution_success/simple_array_param/Nargo.toml diff --git a/test_programs/compile_success_empty/simple_array_param/Prover.toml b/test_programs/execution_success/simple_array_param/Prover.toml similarity index 100% rename from test_programs/compile_success_empty/simple_array_param/Prover.toml rename to test_programs/execution_success/simple_array_param/Prover.toml diff --git a/test_programs/compile_success_empty/simple_array_param/src/main.nr b/test_programs/execution_success/simple_array_param/src/main.nr similarity index 100% rename from test_programs/compile_success_empty/simple_array_param/src/main.nr rename to test_programs/execution_success/simple_array_param/src/main.nr diff --git a/test_programs/execution_success/simple_shield/src/main.nr b/test_programs/execution_success/simple_shield/src/main.nr index c46d3b4594c..548ba17d462 100644 --- a/test_programs/execution_success/simple_shield/src/main.nr +++ b/test_programs/execution_success/simple_shield/src/main.nr @@ -13,7 +13,7 @@ fn main( to_pubkey_y: Field ) -> pub [Field; 2] { // Compute public key from private key to show ownership - let pubkey = std::scalar_mul::fixed_base_embedded_curve(priv_key, 0); + let pubkey = std::embedded_curve_ops::fixed_base_scalar_mul(priv_key, 0); let pubkey_x = pubkey[0]; let pubkey_y = pubkey[1]; // Compute input note commitment diff --git a/test_programs/execution_success/slice_coercion/src/main.nr b/test_programs/execution_success/slice_coercion/src/main.nr index a3785e79afa..a7ba0443bd1 100644 --- a/test_programs/execution_success/slice_coercion/src/main.nr +++ b/test_programs/execution_success/slice_coercion/src/main.nr @@ -16,4 +16,12 @@ fn main(expected: pub Field, first: Field) { let mut hasher = Hasher::new(); hasher.add(first); assert(hasher.fields[0] == expected); + + regression_4967(); +} + +fn regression_4967() { + let var1: [(i32, u8)] = [(1, 2)]; + assert(var1.len() == 1); + dep::std::println(var1); } diff --git a/test_programs/execution_success/slice_init_with_complex_type/Nargo.toml b/test_programs/execution_success/slice_init_with_complex_type/Nargo.toml new file mode 100644 index 00000000000..a372caf92e9 --- /dev/null +++ b/test_programs/execution_success/slice_init_with_complex_type/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "slice_init_with_complex_type" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/noir_test_success/bounded_vec/Prover.toml b/test_programs/execution_success/slice_init_with_complex_type/Prover.toml similarity index 100% rename from test_programs/noir_test_success/bounded_vec/Prover.toml rename to test_programs/execution_success/slice_init_with_complex_type/Prover.toml diff --git a/test_programs/execution_success/slice_init_with_complex_type/src/main.nr b/test_programs/execution_success/slice_init_with_complex_type/src/main.nr new file mode 100644 index 00000000000..01ccf2fdeff --- /dev/null +++ b/test_programs/execution_success/slice_init_with_complex_type/src/main.nr @@ -0,0 +1,17 @@ +struct strct1 { + elem1: Field, +} + +fn main() { + let var1: [[i32; 1]] = [[0]]; + let var2: [[i32; 1]] = var1; + + let var1: [(i32, u8)] = [(1, 2)]; + let var2: [(i32, u8)] = var1; + + let var3: [strct1] = [strct1 { elem1: 1321351 }]; + let var4: [strct1] = var3; + + let var1: [i32; 1] = [0]; + let var2: [[i32; 1]] = [var1]; +} diff --git a/test_programs/execution_success/u128/src/main.nr b/test_programs/execution_success/u128/src/main.nr index dc586408795..a403571ea74 100644 --- a/test_programs/execution_success/u128/src/main.nr +++ b/test_programs/execution_success/u128/src/main.nr @@ -34,11 +34,11 @@ fn main(mut x: u32, y: u32, z: u32, big_int: U128, hexa: str<7>) { let mut small_int = U128::from_integer(x); assert(small_int.lo == x as Field); assert(x == small_int.to_integer()); - let shift = small_int << small_int; - assert(shift == U128::from_integer(x << x)); - assert(shift >> small_int == small_int); - assert(shift >> U128::from_integer(127) == U128::from_integer(0)); - assert(shift << U128::from_integer(127) == U128::from_integer(0)); + let shift = small_int << (x as u8); + assert(shift == U128::from_integer(x << (x as u8))); + assert(shift >> (x as u8) == small_int); + assert(shift >> 127 == U128::from_integer(0)); + assert(shift << 127 == U128::from_integer(0)); assert(U128::from_integer(3).to_integer() == 3); } diff --git a/test_programs/noir_test_success/brillig_overflow_checks/Prover.toml b/test_programs/noir_test_success/brillig_overflow_checks/Prover.toml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test_programs/noir_test_success/comptime_globals/Nargo.toml b/test_programs/noir_test_success/comptime_globals/Nargo.toml new file mode 100644 index 00000000000..d4f349f537a --- /dev/null +++ b/test_programs/noir_test_success/comptime_globals/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "comptime_globals" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/noir_test_success/comptime_globals/src/main.nr b/test_programs/noir_test_success/comptime_globals/src/main.nr new file mode 100644 index 00000000000..efe9f0742b9 --- /dev/null +++ b/test_programs/noir_test_success/comptime_globals/src/main.nr @@ -0,0 +1,21 @@ +// Normal globals can be evaluated in a comptime context too, +// but comptime globals can only be evaluated in a comptime context. +comptime global FOO: Field = foo(); + +// Due to this function's mutability and branching, SSA currently fails +// to fold this function into a constant before the assert_constant check +// is evaluated before loop unrolling. +fn foo() -> Field { + let mut three = 3; + if three == 3 { 5 } else { 6 } +} + +#[test] +fn foo_global_constant() { + assert_constant(FOO); +} + +#[test(should_fail)] +fn foo_function_not_constant() { + assert_constant(foo()); +} diff --git a/test_programs/noir_test_success/field_comparisons/Prover.toml b/test_programs/noir_test_success/field_comparisons/Prover.toml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test_programs/noir_test_success/ignored_oracle/Nargo.toml b/test_programs/noir_test_success/ignored_oracle/Nargo.toml new file mode 100644 index 00000000000..0d9b77c01d7 --- /dev/null +++ b/test_programs/noir_test_success/ignored_oracle/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ignored_oracle" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] diff --git a/test_programs/noir_test_success/ignored_oracle/src/main.nr b/test_programs/noir_test_success/ignored_oracle/src/main.nr new file mode 100644 index 00000000000..9e0bc189939 --- /dev/null +++ b/test_programs/noir_test_success/ignored_oracle/src/main.nr @@ -0,0 +1,23 @@ +// In `nargo test` we want to avoid the need for an external oracle resolver service to be required in the situation +// where its existence doesn't affect whether the tests will pass or fail. We then want to be able to handle any +// oracles which return zero field elements. + +// Note that this custom oracle doesn't return any new values into the program. +// We can then safely continue execution even in the case where there is no oracle resolver to handle it. +#[oracle(custom_debug)] +unconstrained fn custom_debug() {} + +// However this oracle call should return a field element. We expect the ACVM to raise an error when it +// doesn't receive this value. +#[oracle(custom_getter)] +unconstrained fn custom_getter() -> Field {} + +#[test] +unconstrained fn unit_return_oracle_ignored() { + custom_debug(); +} + +#[test(should_fail_with = "0 output values were provided as a foreign call result for 1 destination slots")] +unconstrained fn field_return_oracle_fails() { + let _ = custom_getter(); +} diff --git a/test_programs/noir_test_success/mock_oracle/Prover.toml b/test_programs/noir_test_success/mock_oracle/Prover.toml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml b/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test_programs/noir_test_success/should_fail_with_matches/Prover.toml b/test_programs/noir_test_success/should_fail_with_matches/Prover.toml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test_programs/noir_test_success/should_fail_with_matches/src/main.nr b/test_programs/noir_test_success/should_fail_with_matches/src/main.nr index d2b7d155a32..56ee5cfa586 100644 --- a/test_programs/noir_test_success/should_fail_with_matches/src/main.nr +++ b/test_programs/noir_test_success/should_fail_with_matches/src/main.nr @@ -17,3 +17,67 @@ fn test_should_fail_with_runtime_match() { fn test_should_fail_without_runtime_match() { assert_eq(dep::std::hash::pedersen_commitment([27]).x, 0); } + +struct InvalidPointError { + point: dep::std::hash::PedersenPoint, +} + +#[test(should_fail_with = "InvalidPointError { point: PedersenPoint { x: 0x1cea3a116d01eb94d568ef04c3dfbc39f96f015ed801ab8958e360d406503ce0, y: 0x2721b237df87234acc36a238b8f231a3d31d18fe3845fff4cc59f0bd873818f8 } }")] +fn test_should_fail_with_struct() { + let hash = dep::std::hash::pedersen_commitment([27]); + assert_eq(hash.x, 0, InvalidPointError { point: hash }); +} + +#[test(should_fail_with = "A: 0x00 is not 1!")] +fn test_should_fail_with_basic_type_fmt_string() { + let a = 0; + let b = 1; + assert_eq(a, b, f"A: {a} is not 1!"); +} + +#[test(should_fail_with = "Invalid hash: PedersenPoint { x: 0x1cea3a116d01eb94d568ef04c3dfbc39f96f015ed801ab8958e360d406503ce0, y: 0x2721b237df87234acc36a238b8f231a3d31d18fe3845fff4cc59f0bd873818f8 }")] +fn test_should_fail_with_struct_fmt_string() { + let hash = dep::std::hash::pedersen_commitment([27]); + assert_eq(hash.x, 0, f"Invalid hash: {hash}"); +} + +// Also test unconstrained versions + +#[test(should_fail_with = "Not equal")] +unconstrained fn unconstrained_test_should_fail_with_match() { + assert_eq(0, 1, "Not equal"); +} + +#[test(should_fail)] +unconstrained fn unconstrained_test_should_fail_without_match() { + assert_eq(0, 1); +} + +#[test(should_fail_with = "Not equal")] +unconstrained fn unconstrained_test_should_fail_with_runtime_match() { + assert_eq(dep::std::hash::pedersen_commitment([27]).x, 0, "Not equal"); +} + +#[test(should_fail)] +unconstrained fn unconstrained_test_should_fail_without_runtime_match() { + assert_eq(dep::std::hash::pedersen_commitment([27]).x, 0); +} + +#[test(should_fail_with = "InvalidPointError { point: PedersenPoint { x: 0x1cea3a116d01eb94d568ef04c3dfbc39f96f015ed801ab8958e360d406503ce0, y: 0x2721b237df87234acc36a238b8f231a3d31d18fe3845fff4cc59f0bd873818f8 } }")] +unconstrained fn unconstrained_test_should_fail_with_struct() { + let hash = dep::std::hash::pedersen_commitment([27]); + assert_eq(hash.x, 0, InvalidPointError { point: hash }); +} + +#[test(should_fail_with = "A: 0x00 is not 1!")] +unconstrained fn unconstrained_test_should_fail_with_basic_type_fmt_string() { + let a = 0; + let b = 1; + assert_eq(a, b, f"A: {a} is not 1!"); +} + +#[test(should_fail_with = "Invalid hash: PedersenPoint { x: 0x1cea3a116d01eb94d568ef04c3dfbc39f96f015ed801ab8958e360d406503ce0, y: 0x2721b237df87234acc36a238b8f231a3d31d18fe3845fff4cc59f0bd873818f8 }")] +unconstrained fn unconstrained_test_should_fail_with_struct_fmt_string() { + let hash = dep::std::hash::pedersen_commitment([27]); + assert_eq(hash.x, 0, f"Invalid hash: {hash}"); +} diff --git a/test_programs/rebuild.sh b/test_programs/rebuild.sh index a3137920fd5..51e97278281 100755 --- a/test_programs/rebuild.sh +++ b/test_programs/rebuild.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -e +NO_PARALLEL=${1:-} + process_dir() { local dir=$1 local current_dir=$2 @@ -46,10 +48,17 @@ done # Process each directory in parallel pids=() +if [ -z $NO_PARALLEL ]; then for dir in "${dirs_to_process[@]}"; do process_dir "$dir" "$current_dir" & pids+=($!) done +else +for dir in "${dirs_to_process[@]}"; do + process_dir "$dir" "$current_dir" + pids+=($!) +done +fi # Check the exit status of each background job. for pid in "${pids[@]}"; do @@ -58,5 +67,7 @@ done # Exit with a failure status if any job failed. if [ ! -z "$exit_status" ]; then + echo "Rebuild failed!" exit $exit_status -fi \ No newline at end of file +fi +echo "Rebuild Succeeded!" \ No newline at end of file diff --git a/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs b/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs index 75a6d323e7b..cdaebb95fc9 100644 --- a/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs +++ b/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs @@ -21,7 +21,7 @@ const INFO_RESPONSE: &str = r#"{ "pedersen_hash", "ecdsa_secp256k1", "ecdsa_secp256r1", - "fixed_base_scalar_mul", + "multi_scalar_mul", "recursive_aggregation" ] }"#; diff --git a/tooling/debugger/ignored-tests.txt b/tooling/debugger/ignored-tests.txt index 3b63f8d5542..cda26169421 100644 --- a/tooling/debugger/ignored-tests.txt +++ b/tooling/debugger/ignored-tests.txt @@ -17,4 +17,11 @@ fold_basic_nested_call fold_call_witness_condition fold_after_inlined_calls fold_numeric_generic_poseidon - +no_predicates_basic +no_predicates_numeric_generic_poseidon +regression_4709 +fold_distinct_return +fold_fibonacci +fold_complex_outputs +slice_init_with_complex_type +hashmap diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 9b535075484..ea32c864a0b 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -2,7 +2,6 @@ use crate::foreign_calls::DebugForeignCallExecutor; use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; -use acvm::brillig_vm::brillig::ForeignCallResult; use acvm::brillig_vm::MemoryValue; use acvm::pwg::{ ACVMStatus, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, StepResult, ACVM, @@ -34,6 +33,7 @@ pub(super) struct DebugContext<'a, B: BlackBoxFunctionSolver> { debug_artifact: &'a DebugArtifact, breakpoints: HashSet, source_to_opcodes: BTreeMap>, + unconstrained_functions: &'a [BrilligBytecode], } impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { @@ -53,12 +53,14 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { &circuit.opcodes, initial_witness, unconstrained_functions, + &circuit.assert_messages, ), brillig_solver: None, foreign_call_executor, debug_artifact, breakpoints: HashSet::new(), source_to_opcodes, + unconstrained_functions, } } @@ -215,7 +217,9 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { self.get_opcodes() .iter() .map(|opcode| match opcode { - Opcode::Brillig(brillig_block) => brillig_block.bytecode.len(), + Opcode::BrilligCall { id, .. } => { + self.unconstrained_functions[*id as usize].bytecode.len() + } _ => 1, }) .collect() @@ -296,19 +300,22 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { None => String::from("invalid"), Some(OpcodeLocation::Acir(acir_index)) => { let opcode = &opcodes[*acir_index]; - if let Opcode::Brillig(ref brillig) = opcode { - let first_opcode = &brillig.bytecode[0]; - format!("BRILLIG {first_opcode:?}") - } else { - format!("{opcode:?}") + match opcode { + Opcode::BrilligCall { id, .. } => { + let first_opcode = &self.unconstrained_functions[*id as usize].bytecode[0]; + format!("BRILLIG CALL {first_opcode:?}") + } + _ => format!("{opcode:?}"), } } Some(OpcodeLocation::Brillig { acir_index, brillig_index }) => { - if let Opcode::Brillig(ref brillig) = opcodes[*acir_index] { - let opcode = &brillig.bytecode[*brillig_index]; - format!(" | {opcode:?}") - } else { - String::from(" | invalid") + match &opcodes[*acir_index] { + Opcode::BrilligCall { id, .. } => { + let bytecode = &self.unconstrained_functions[*id as usize].bytecode; + let opcode = &bytecode[*brillig_index]; + format!(" | {opcode:?}") + } + _ => String::from(" | invalid"), } } } @@ -349,9 +356,6 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { let foreign_call_result = self.foreign_call_executor.execute(&foreign_call); match foreign_call_result { Ok(foreign_call_result) => { - let foreign_call_result = foreign_call_result - .get_brillig_output() - .unwrap_or(ForeignCallResult::default()); if let Some(mut solver) = self.brillig_solver.take() { solver.resolve_pending_foreign_call(foreign_call_result); self.brillig_solver = Some(solver); @@ -400,7 +404,7 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { return self.step_brillig_opcode(); } - match self.acvm.step_into_brillig_opcode() { + match self.acvm.step_into_brillig() { StepResult::IntoBrillig(solver) => { self.brillig_solver = Some(solver); self.step_brillig_opcode() @@ -409,20 +413,6 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } - fn currently_executing_brillig(&self) -> bool { - if self.brillig_solver.is_some() { - return true; - } - - match self.get_current_opcode_location() { - Some(OpcodeLocation::Brillig { .. }) => true, - Some(OpcodeLocation::Acir(acir_index)) => { - matches!(self.get_opcodes()[acir_index], Opcode::Brillig(_)) - } - _ => false, - } - } - fn get_current_acir_index(&self) -> Option { self.get_current_opcode_location().map(|opcode_location| match opcode_location { OpcodeLocation::Acir(acir_index) => acir_index, @@ -446,8 +436,22 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } + pub(super) fn is_executing_brillig(&self) -> bool { + if self.brillig_solver.is_some() { + return true; + } + + match self.get_current_opcode_location() { + Some(OpcodeLocation::Brillig { .. }) => true, + Some(OpcodeLocation::Acir(acir_index)) => { + matches!(self.get_opcodes()[acir_index], Opcode::BrilligCall { .. }) + } + _ => false, + } + } + pub(super) fn step_acir_opcode(&mut self) -> DebugCommandResult { - if self.currently_executing_brillig() { + if self.is_executing_brillig() { self.step_out_of_brillig_opcode() } else { let status = self.acvm.solve_opcode(); @@ -511,12 +515,6 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } - pub(super) fn is_executing_brillig(&self) -> bool { - let opcodes = self.get_opcodes(); - let acir_index = self.acvm.instruction_pointer(); - acir_index < opcodes.len() && matches!(opcodes[acir_index], Opcode::Brillig(..)) - } - pub(super) fn get_brillig_memory(&self) -> Option<&[MemoryValue]> { self.brillig_solver.as_ref().map(|solver| solver.get_memory()) } @@ -552,15 +550,17 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { match *location { OpcodeLocation::Acir(acir_index) => acir_index < opcodes.len(), OpcodeLocation::Brillig { acir_index, brillig_index } => { - acir_index < opcodes.len() - && matches!(opcodes[acir_index], Opcode::Brillig(..)) - && { - if let Opcode::Brillig(ref brillig) = opcodes[acir_index] { - brillig_index < brillig.bytecode.len() - } else { - false + if acir_index < opcodes.len() { + match &opcodes[acir_index] { + Opcode::BrilligCall { id, .. } => { + let bytecode = &self.unconstrained_functions[*id as usize].bytecode; + brillig_index < bytecode.len() } + _ => false, } + } else { + false + } } } } @@ -649,7 +649,7 @@ mod tests { use acvm::{ acir::{ circuit::{ - brillig::{Brillig, BrilligInputs, BrilligOutputs}, + brillig::{BrilligInputs, BrilligOutputs}, opcodes::BlockId, }, native_types::Expression, @@ -666,12 +666,7 @@ mod tests { let fe_1 = FieldElement::one(); let w_x = Witness(1); - let brillig_opcodes = Brillig { - inputs: vec![BrilligInputs::Single(Expression { - linear_combinations: vec![(fe_1, w_x)], - ..Expression::default() - })], - outputs: vec![], + let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::CalldataCopy { destination_address: MemoryAddress(0), @@ -692,9 +687,17 @@ mod tests { }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, ], - predicate: None, }; - let opcodes = vec![Opcode::Brillig(brillig_opcodes)]; + let opcodes = vec![Opcode::BrilligCall { + id: 0, + inputs: vec![BrilligInputs::Single(Expression { + linear_combinations: vec![(fe_1, w_x)], + ..Expression::default() + })], + outputs: vec![], + predicate: None, + }]; + let brillig_funcs = &vec![brillig_bytecode]; let current_witness_index = 2; let circuit = &Circuit { current_witness_index, opcodes, ..Circuit::default() }; @@ -707,7 +710,6 @@ mod tests { let foreign_call_executor = Box::new(DefaultDebugForeignCallExecutor::from_artifact(true, debug_artifact)); - let brillig_funcs = &vec![]; let mut context = DebugContext::new( &StubbedBlackBoxSolver, circuit, @@ -766,18 +768,7 @@ mod tests { let w_z = Witness(3); // This Brillig block is equivalent to: z = x + y - let brillig_opcodes = Brillig { - inputs: vec![ - BrilligInputs::Single(Expression { - linear_combinations: vec![(fe_1, w_x)], - ..Expression::default() - }), - BrilligInputs::Single(Expression { - linear_combinations: vec![(fe_1, w_y)], - ..Expression::default() - }), - ], - outputs: vec![BrilligOutputs::Simple(w_z)], + let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::CalldataCopy { destination_address: MemoryAddress(0), @@ -792,11 +783,24 @@ mod tests { }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], - predicate: None, }; let opcodes = vec![ // z = x + y - Opcode::Brillig(brillig_opcodes), + Opcode::BrilligCall { + id: 0, + inputs: vec![ + BrilligInputs::Single(Expression { + linear_combinations: vec![(fe_1, w_x)], + ..Expression::default() + }), + BrilligInputs::Single(Expression { + linear_combinations: vec![(fe_1, w_y)], + ..Expression::default() + }), + ], + outputs: vec![BrilligOutputs::Simple(w_z)], + predicate: None, + }, // x + y - z = 0 Opcode::AssertZero(Expression { mul_terms: vec![], @@ -816,7 +820,7 @@ mod tests { let foreign_call_executor = Box::new(DefaultDebugForeignCallExecutor::from_artifact(true, debug_artifact)); - let brillig_funcs = &vec![]; + let brillig_funcs = &vec![brillig_bytecode]; let mut context = DebugContext::new( &StubbedBlackBoxSolver, circuit, @@ -848,34 +852,24 @@ mod tests { #[test] fn test_offset_opcode_location() { + let brillig_bytecode = BrilligBytecode { + bytecode: vec![ + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, + ], + }; + let opcodes = vec![ - Opcode::Brillig(Brillig { - inputs: vec![], - outputs: vec![], - bytecode: vec![ - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, - ], - predicate: None, - }), + Opcode::BrilligCall { id: 0, inputs: vec![], outputs: vec![], predicate: None }, Opcode::MemoryInit { block_id: BlockId(0), init: vec![] }, - Opcode::Brillig(Brillig { - inputs: vec![], - outputs: vec![], - bytecode: vec![ - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, - ], - predicate: None, - }), + Opcode::BrilligCall { id: 0, inputs: vec![], outputs: vec![], predicate: None }, Opcode::AssertZero(Expression::default()), ]; let circuit = Circuit { opcodes, ..Circuit::default() }; let debug_artifact = DebugArtifact { debug_symbols: vec![], file_map: BTreeMap::new(), warnings: vec![] }; - let brillig_funcs = &vec![]; + let brillig_funcs = &vec![brillig_bytecode]; let context = DebugContext::new( &StubbedBlackBoxSolver, &circuit, diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index f11ac22cd75..209439f5f92 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -5,7 +5,7 @@ use acvm::{ }; use nargo::{ artifacts::debug::{DebugArtifact, DebugVars, StackFrame}, - ops::{DefaultForeignCallExecutor, ForeignCallExecutor, NargoForeignCallResult}, + ops::{DefaultForeignCallExecutor, ForeignCallExecutor}, }; use noirc_errors::debug_info::{DebugFnId, DebugVarId}; use noirc_printable_type::ForeignCallError; @@ -94,7 +94,7 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { fn execute( &mut self, foreign_call: &ForeignCallWaitInfo, - ) -> Result { + ) -> Result { let foreign_call_name = foreign_call.function.as_str(); match DebugForeignCall::lookup(foreign_call_name) { Some(DebugForeignCall::VarAssign) => { @@ -105,7 +105,7 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { foreign_call.inputs[1..].iter().flat_map(|x| x.fields()).collect(); self.debug_vars.assign_var(var_id, &values); } - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } Some(DebugForeignCall::VarDrop) => { let fcp_var_id = &foreign_call.inputs[0]; @@ -113,7 +113,7 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { let var_id = debug_var_id(var_id_value); self.debug_vars.drop_var(var_id); } - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } Some(DebugForeignCall::MemberAssign(arity)) => { if let Some(ForeignCallParam::Single(var_id_value)) = foreign_call.inputs.first() { @@ -141,7 +141,7 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { .collect(); self.debug_vars.assign_field(var_id, indexes, &values); } - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } Some(DebugForeignCall::DerefAssign) => { let fcp_var_id = &foreign_call.inputs[0]; @@ -150,7 +150,7 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { let var_id = debug_var_id(var_id_value); self.debug_vars.assign_deref(var_id, &fcp_value.fields()); } - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } Some(DebugForeignCall::FnEnter) => { let fcp_fn_id = &foreign_call.inputs[0]; @@ -159,11 +159,11 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { }; let fn_id = debug_fn_id(fn_id_value); self.debug_vars.push_fn(fn_id); - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } Some(DebugForeignCall::FnExit) => { self.debug_vars.pop_fn(); - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } None => self.executor.execute(foreign_call), } diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 2a92698e5ce..8f908a38ffc 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -3,6 +3,7 @@ use crate::context::{DebugCommandResult, DebugContext}; use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; +use acvm::brillig_vm::brillig::Opcode as BrilligOpcode; use acvm::{BlackBoxFunctionSolver, FieldElement}; use crate::foreign_calls::DefaultDebugForeignCallExecutor; @@ -68,23 +69,18 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { Some(location) => { match location { OpcodeLocation::Acir(ip) => { - // Default Brillig display is too bloated for this context, - // so we limit it to denoting it's the start of a Brillig - // block. The user can still use the `opcodes` command to - // take a look at the whole block. - let opcode_summary = match opcodes[ip] { - Opcode::Brillig(..) => "BRILLIG: ...".into(), - _ => format!("{}", opcodes[ip]), - }; - println!("At opcode {}: {}", ip, opcode_summary); + println!("At opcode {}: {}", ip, opcodes[ip]); } OpcodeLocation::Brillig { acir_index, brillig_index } => { - let Opcode::Brillig(ref brillig) = opcodes[acir_index] else { - unreachable!("Brillig location does not contain a Brillig block"); - }; + let brillig_bytecode = + if let Opcode::BrilligCall { id, .. } = opcodes[acir_index] { + &self.unconstrained_functions[id as usize].bytecode + } else { + unreachable!("Brillig location does not contain Brillig opcodes"); + }; println!( "At opcode {}.{}: {:?}", - acir_index, brillig_index, brillig.bytecode[brillig_index] + acir_index, brillig_index, brillig_bytecode[brillig_index] ); } } @@ -104,12 +100,15 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { ) } OpcodeLocation::Brillig { acir_index, brillig_index } => { - let Opcode::Brillig(ref brillig) = opcodes[*acir_index] else { - unreachable!("Brillig location does not contain a Brillig block"); + let brillig_bytecode = if let Opcode::BrilligCall { id, .. } = opcodes[*acir_index] + { + &self.unconstrained_functions[id as usize].bytecode + } else { + unreachable!("Brillig location does not contain Brillig opcodes"); }; println!( "Frame #{index}, opcode {}.{}: {:?}", - acir_index, brillig_index, brillig.bytecode[*brillig_index] + acir_index, brillig_index, brillig_bytecode[*brillig_index] ); } } @@ -162,22 +161,30 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { "" } }; + let print_brillig_bytecode = |acir_index, bytecode: &[BrilligOpcode]| { + for (brillig_index, brillig_opcode) in bytecode.iter().enumerate() { + println!( + "{:>3}.{:<2} |{:2} {:?}", + acir_index, + brillig_index, + brillig_marker(acir_index, brillig_index), + brillig_opcode + ); + } + }; for (acir_index, opcode) in opcodes.iter().enumerate() { let marker = outer_marker(acir_index); - if let Opcode::Brillig(brillig) = opcode { - println!("{:>3} {:2} BRILLIG inputs={:?}", acir_index, marker, brillig.inputs); - println!(" | outputs={:?}", brillig.outputs); - for (brillig_index, brillig_opcode) in brillig.bytecode.iter().enumerate() { + match &opcode { + Opcode::BrilligCall { id, inputs, outputs, .. } => { println!( - "{:>3}.{:<2} |{:2} {:?}", - acir_index, - brillig_index, - brillig_marker(acir_index, brillig_index), - brillig_opcode + "{:>3} {:2} BRILLIG CALL id={} inputs={:?}", + acir_index, marker, id, inputs ); + println!(" | outputs={:?}", outputs); + let bytecode = &self.unconstrained_functions[*id as usize].bytecode; + print_brillig_bytecode(acir_index, bytecode); } - } else { - println!("{:>3} {:2} {:?}", acir_index, marker, opcode); + _ => println!("{:>3} {:2} {:?}", acir_index, marker, opcode), } } } diff --git a/tooling/lsp/src/solver.rs b/tooling/lsp/src/solver.rs index 0fea9b16b54..249406effaf 100644 --- a/tooling/lsp/src/solver.rs +++ b/tooling/lsp/src/solver.rs @@ -24,12 +24,12 @@ impl BlackBoxFunctionSolver for WrapperSolver { self.0.pedersen_commitment(inputs, domain_separator) } - fn fixed_base_scalar_mul( + fn multi_scalar_mul( &self, - low: &acvm::FieldElement, - high: &acvm::FieldElement, + points: &[acvm::FieldElement], + scalars: &[acvm::FieldElement], ) -> Result<(acvm::FieldElement, acvm::FieldElement), acvm::BlackBoxResolutionError> { - self.0.fixed_base_scalar_mul(low, high) + self.0.multi_scalar_mul(points, scalars) } fn pedersen_hash( diff --git a/tooling/nargo/src/artifacts/debug_vars.rs b/tooling/nargo/src/artifacts/debug_vars.rs index 6a42a4c3311..3695fa47842 100644 --- a/tooling/nargo/src/artifacts/debug_vars.rs +++ b/tooling/nargo/src/artifacts/debug_vars.rs @@ -96,13 +96,11 @@ impl DebugVars { PrintableType::Array { length, typ }, ) => { assert!(!*is_slice, "slice has array type"); - if let Some(len) = length { - if *index as u64 >= *len { - panic!("unexpected field index past array length") - } - if *len != array_elements.len() as u64 { - panic!("type/array length mismatch") - } + if *index as u64 >= *length { + panic!("unexpected field index past array length") + } + if *length != array_elements.len() as u64 { + panic!("type/array length mismatch") } (array_elements.get_mut(*index as usize).unwrap(), &*Box::leak(typ.clone())) } @@ -110,7 +108,7 @@ impl DebugVars { PrintableValue::Vec { array_elements, is_slice }, PrintableType::Slice { typ }, ) => { - assert!(*is_slice, "array has slice type"); + assert!(*is_slice, "slice doesn't have slice type"); (array_elements.get_mut(*index as usize).unwrap(), &*Box::leak(typ.clone())) } ( diff --git a/tooling/nargo/src/errors.rs b/tooling/nargo/src/errors.rs index ac03330a7c8..63a72247e2f 100644 --- a/tooling/nargo/src/errors.rs +++ b/tooling/nargo/src/errors.rs @@ -1,7 +1,13 @@ +use std::collections::BTreeMap; + use acvm::{ - acir::circuit::{OpcodeLocation, ResolvedOpcodeLocation}, + acir::circuit::{ + ErrorSelector, OpcodeLocation, RawAssertionPayload, ResolvedAssertionPayload, + ResolvedOpcodeLocation, + }, pwg::{ErrorLocation, OpcodeResolutionError}, }; +use noirc_abi::{display_abi_error, Abi, AbiErrorType}; use noirc_errors::{ debug_info::DebugInfo, reporter::ReportedErrors, CustomDiagnostic, FileDiagnostic, }; @@ -53,24 +59,34 @@ impl NargoError { /// /// We want to extract the user defined error so that we can compare it /// in tests to expected failure messages - pub fn user_defined_failure_message(&self) -> Option<&str> { + pub fn user_defined_failure_message( + &self, + error_types: &BTreeMap, + ) -> Option { let execution_error = match self { NargoError::ExecutionError(error) => error, _ => return None, }; match execution_error { - ExecutionError::AssertionFailed(message, _) => Some(message), + ExecutionError::AssertionFailed(payload, _) => match payload { + ResolvedAssertionPayload::String(message) => Some(message.to_string()), + ResolvedAssertionPayload::Raw(raw) => { + let abi_type = error_types.get(&raw.selector)?; + let decoded = display_abi_error(&raw.data, abi_type.clone()); + Some(decoded.to_string()) + } + }, ExecutionError::SolvingError(error, _) => match error { OpcodeResolutionError::IndexOutOfBounds { .. } | OpcodeResolutionError::OpcodeNotSolvable(_) | OpcodeResolutionError::UnsatisfiedConstrain { .. } | OpcodeResolutionError::AcirMainCallAttempted { .. } + | OpcodeResolutionError::BrilligFunctionFailed { .. } | OpcodeResolutionError::AcirCallOutputsMismatch { .. } => None, - OpcodeResolutionError::BrilligFunctionFailed { message, .. } => { - message.as_ref().map(|s| s.as_str()) + OpcodeResolutionError::BlackBoxFunctionFailed(_, reason) => { + Some(reason.to_string()) } - OpcodeResolutionError::BlackBoxFunctionFailed(_, reason) => Some(reason), }, } } @@ -78,8 +94,8 @@ impl NargoError { #[derive(Debug, Error)] pub enum ExecutionError { - #[error("Failed assertion: '{}'", .0)] - AssertionFailed(String, Vec), + #[error("Failed assertion")] + AssertionFailed(ResolvedAssertionPayload, Vec), #[error("Failed to solve program: '{}'", .0)] SolvingError(OpcodeResolutionError, Option>), @@ -101,7 +117,7 @@ fn extract_locations_from_error( acir_call_stack, ) | ExecutionError::SolvingError( - OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: error_location }, + OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: error_location, .. }, acir_call_stack, ) => match error_location { ErrorLocation::Unresolved => { @@ -144,11 +160,27 @@ fn extract_locations_from_error( ) } -fn extract_message_from_error(nargo_err: &NargoError) -> String { +fn extract_message_from_error( + error_types: &BTreeMap, + nargo_err: &NargoError, +) -> String { match nargo_err { - NargoError::ExecutionError(ExecutionError::AssertionFailed(message, _)) => { + NargoError::ExecutionError(ExecutionError::AssertionFailed( + ResolvedAssertionPayload::String(message), + _, + )) => { format!("Assertion failed: '{message}'") } + NargoError::ExecutionError(ExecutionError::AssertionFailed( + ResolvedAssertionPayload::Raw(RawAssertionPayload { selector, data }), + .., + )) => { + if let Some(error_type) = error_types.get(selector) { + format!("Assertion failed: {}", display_abi_error(data, error_type.clone())) + } else { + "Assertion failed".to_string() + } + } NargoError::ExecutionError(ExecutionError::SolvingError( OpcodeResolutionError::IndexOutOfBounds { index, array_size, .. }, _, @@ -166,6 +198,7 @@ fn extract_message_from_error(nargo_err: &NargoError) -> String { /// Tries to generate a runtime diagnostic from a nargo error. It will successfully do so if it's a runtime error with a call stack. pub fn try_to_diagnose_runtime_error( nargo_err: &NargoError, + abi: &Abi, debug: &[DebugInfo], ) -> Option { let source_locations = match nargo_err { @@ -177,7 +210,7 @@ pub fn try_to_diagnose_runtime_error( // The location of the error itself will be the location at the top // of the call stack (the last item in the Vec). let location = source_locations.last()?; - let message = extract_message_from_error(nargo_err); + let message = extract_message_from_error(&abi.error_types, nargo_err); Some( CustomDiagnostic::simple_error(message, String::new(), location.span) .in_file(location.file) diff --git a/tooling/nargo/src/ops/execute.rs b/tooling/nargo/src/ops/execute.rs index 34755d14ed2..4a75212ba47 100644 --- a/tooling/nargo/src/ops/execute.rs +++ b/tooling/nargo/src/ops/execute.rs @@ -1,7 +1,6 @@ use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::circuit::{OpcodeLocation, Program, ResolvedOpcodeLocation}; use acvm::acir::native_types::WitnessStack; -use acvm::brillig_vm::brillig::ForeignCallResult; use acvm::pwg::{ACVMStatus, ErrorLocation, OpcodeNotSolvable, OpcodeResolutionError, ACVM}; use acvm::BlackBoxFunctionSolver; use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; @@ -9,7 +8,7 @@ use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; use crate::errors::ExecutionError; use crate::NargoError; -use super::foreign_calls::{ForeignCallExecutor, NargoForeignCallResult}; +use super::foreign_calls::ForeignCallExecutor; struct ProgramExecutor<'a, B: BlackBoxFunctionSolver, F: ForeignCallExecutor> { functions: &'a [Circuit], @@ -63,10 +62,9 @@ impl<'a, B: BlackBoxFunctionSolver, F: ForeignCallExecutor> ProgramExecutor<'a, &circuit.opcodes, initial_witness, self.unconstrained_functions, + &circuit.assert_messages, ); - // This message should be resolved by a nargo foreign call only when we have an unsatisfied assertion. - let mut assert_message: Option = None; loop { let solver_status = acvm.solve(); @@ -79,6 +77,7 @@ impl<'a, B: BlackBoxFunctionSolver, F: ForeignCallExecutor> ProgramExecutor<'a, let call_stack = match &error { OpcodeResolutionError::UnsatisfiedConstrain { opcode_location: ErrorLocation::Resolved(opcode_location), + .. } | OpcodeResolutionError::IndexOutOfBounds { opcode_location: ErrorLocation::Resolved(opcode_location), @@ -103,55 +102,25 @@ impl<'a, B: BlackBoxFunctionSolver, F: ForeignCallExecutor> ProgramExecutor<'a, _ => None, }; - return Err(NargoError::ExecutionError(match call_stack { - Some(call_stack) => { - // First check whether we have a runtime assertion message that should be resolved on an ACVM failure - // If we do not have a runtime assertion message, we check whether the error is a brillig error with a user-defined message, - // and finally we should check whether the circuit has any hardcoded messages associated with a specific `OpcodeLocation`. - // Otherwise return the provided opcode resolution error. - if let Some(assert_message) = assert_message { - ExecutionError::AssertionFailed( - assert_message.to_owned(), - call_stack, - ) - } else if let OpcodeResolutionError::BrilligFunctionFailed { - message: Some(message), - .. - } = &error - { - ExecutionError::AssertionFailed(message.to_owned(), call_stack) - } else if let Some(assert_message) = circuit.get_assert_message( - call_stack - .last() - .expect("Call stacks should not be empty") - .opcode_location, - ) { - ExecutionError::AssertionFailed( - assert_message.to_owned(), - call_stack, - ) - } else { - ExecutionError::SolvingError(error, Some(call_stack)) - } + let assertion_payload = match &error { + OpcodeResolutionError::BrilligFunctionFailed { payload, .. } + | OpcodeResolutionError::UnsatisfiedConstrain { payload, .. } => { + payload.clone() } - None => ExecutionError::SolvingError(error, None), + _ => None, + }; + + return Err(NargoError::ExecutionError(match assertion_payload { + Some(payload) => ExecutionError::AssertionFailed( + payload, + call_stack.expect("Should have call stack for an assertion failure"), + ), + None => ExecutionError::SolvingError(error, call_stack), })); } ACVMStatus::RequiresForeignCall(foreign_call) => { let foreign_call_result = self.foreign_call_executor.execute(&foreign_call)?; - match foreign_call_result { - NargoForeignCallResult::BrilligOutput(foreign_call_result) => { - acvm.resolve_pending_foreign_call(foreign_call_result); - } - NargoForeignCallResult::ResolvedAssertMessage(message) => { - if assert_message.is_some() { - unreachable!("Resolving an assert message should happen only once as the VM should have failed"); - } - assert_message = Some(message); - - acvm.resolve_pending_foreign_call(ForeignCallResult::default()); - } - } + acvm.resolve_pending_foreign_call(foreign_call_result); } ACVMStatus::RequiresAcirCall(call_info) => { // Store the parent function index whose context we are currently executing diff --git a/tooling/nargo/src/ops/foreign_calls.rs b/tooling/nargo/src/ops/foreign_calls.rs index 33767314a37..c314a230cef 100644 --- a/tooling/nargo/src/ops/foreign_calls.rs +++ b/tooling/nargo/src/ops/foreign_calls.rs @@ -10,69 +10,13 @@ pub trait ForeignCallExecutor { fn execute( &mut self, foreign_call: &ForeignCallWaitInfo, - ) -> Result; -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum NargoForeignCallResult { - BrilligOutput(ForeignCallResult), - ResolvedAssertMessage(String), -} - -impl NargoForeignCallResult { - pub fn get_assert_message(self) -> Option { - match self { - Self::ResolvedAssertMessage(msg) => Some(msg), - _ => None, - } - } - - pub fn get_brillig_output(self) -> Option { - match self { - Self::BrilligOutput(foreign_call_result) => Some(foreign_call_result), - _ => None, - } - } -} - -impl From for NargoForeignCallResult { - fn from(value: ForeignCallResult) -> Self { - Self::BrilligOutput(value) - } -} - -impl From for NargoForeignCallResult { - fn from(value: String) -> Self { - Self::ResolvedAssertMessage(value) - } -} - -impl From for NargoForeignCallResult { - fn from(value: FieldElement) -> Self { - let foreign_call_result: ForeignCallResult = value.into(); - foreign_call_result.into() - } -} - -impl From> for NargoForeignCallResult { - fn from(values: Vec) -> Self { - let foreign_call_result: ForeignCallResult = values.into(); - foreign_call_result.into() - } -} - -impl From> for NargoForeignCallResult { - fn from(values: Vec) -> Self { - let foreign_call_result: ForeignCallResult = values.into(); - foreign_call_result.into() - } + ) -> Result; } /// This enumeration represents the Brillig foreign calls that are natively supported by nargo. /// After resolution of a foreign call, nargo will restart execution of the ACVM pub enum ForeignCall { Print, - AssertMessage, CreateMock, SetMockParams, GetMockLastParams, @@ -91,7 +35,6 @@ impl ForeignCall { pub(crate) fn name(&self) -> &'static str { match self { ForeignCall::Print => "print", - ForeignCall::AssertMessage => "assert_message", ForeignCall::CreateMock => "create_mock", ForeignCall::SetMockParams => "set_mock_params", ForeignCall::GetMockLastParams => "get_mock_last_params", @@ -104,7 +47,6 @@ impl ForeignCall { pub(crate) fn lookup(op_name: &str) -> Option { match op_name { "print" => Some(ForeignCall::Print), - "assert_message" => Some(ForeignCall::AssertMessage), "create_mock" => Some(ForeignCall::CreateMock), "set_mock_params" => Some(ForeignCall::SetMockParams), "get_mock_last_params" => Some(ForeignCall::GetMockLastParams), @@ -223,13 +165,6 @@ impl DefaultForeignCallExecutor { Ok(()) } - fn execute_assert_message( - foreign_call_inputs: &[ForeignCallParam], - ) -> Result { - let display_string = Self::format_printable_value(foreign_call_inputs, true)?; - Ok(display_string.into()) - } - fn format_printable_value( foreign_call_inputs: &[ForeignCallParam], skip_newline: bool, @@ -246,16 +181,15 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { fn execute( &mut self, foreign_call: &ForeignCallWaitInfo, - ) -> Result { + ) -> Result { let foreign_call_name = foreign_call.function.as_str(); match ForeignCall::lookup(foreign_call_name) { Some(ForeignCall::Print) => { if self.show_output { Self::execute_print(&foreign_call.inputs)?; } - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } - Some(ForeignCall::AssertMessage) => Self::execute_assert_message(&foreign_call.inputs), Some(ForeignCall::CreateMock) => { let mock_oracle_name = Self::parse_string(&foreign_call.inputs[0]); assert!(ForeignCall::lookup(&mock_oracle_name).is_none()); @@ -271,7 +205,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { .unwrap_or_else(|| panic!("Unknown mock id {}", id)) .params = Some(params.to_vec()); - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } Some(ForeignCall::GetMockLastParams) => { let (id, _) = Self::extract_mock_id(&foreign_call.inputs)?; @@ -291,7 +225,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { .unwrap_or_else(|| panic!("Unknown mock id {}", id)) .result = ForeignCallResult { values: params.to_vec() }; - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } Some(ForeignCall::SetMockTimes) => { let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?; @@ -302,12 +236,12 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { .unwrap_or_else(|| panic!("Unknown mock id {}", id)) .times_left = Some(times); - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } Some(ForeignCall::ClearMock) => { let (id, _) = Self::extract_mock_id(&foreign_call.inputs)?; self.mocked_responses.retain(|response| response.id != id); - Ok(ForeignCallResult::default().into()) + Ok(ForeignCallResult::default()) } None => { let mock_response_position = self @@ -315,43 +249,49 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor { .iter() .position(|response| response.matches(foreign_call_name, &foreign_call.inputs)); - match (mock_response_position, &self.external_resolver) { - (Some(response_position), _) => { - let mock = self - .mocked_responses - .get_mut(response_position) - .expect("Invalid position of mocked response"); + if let Some(response_position) = mock_response_position { + // If the program has registered a mocked response to this oracle call then we prefer responding + // with that. - mock.last_called_params = Some(foreign_call.inputs.clone()); + let mock = self + .mocked_responses + .get_mut(response_position) + .expect("Invalid position of mocked response"); - let result = mock.result.values.clone(); + mock.last_called_params = Some(foreign_call.inputs.clone()); - if let Some(times_left) = &mut mock.times_left { - *times_left -= 1; - if *times_left == 0 { - self.mocked_responses.remove(response_position); - } - } + let result = mock.result.values.clone(); - Ok(result.into()) + if let Some(times_left) = &mut mock.times_left { + *times_left -= 1; + if *times_left == 0 { + self.mocked_responses.remove(response_position); + } } - (None, Some(external_resolver)) => { - let encoded_params: Vec<_> = - foreign_call.inputs.iter().map(build_json_rpc_arg).collect(); - let req = - external_resolver.build_request(foreign_call_name, &encoded_params); + Ok(result.into()) + } else if let Some(external_resolver) = &self.external_resolver { + // If the user has registered an external resolver then we forward any remaining oracle calls there. - let response = external_resolver.send_request(req)?; + let encoded_params: Vec<_> = + foreign_call.inputs.iter().map(build_json_rpc_arg).collect(); - let parsed_response: ForeignCallResult = response.result()?; + let req = external_resolver.build_request(foreign_call_name, &encoded_params); - Ok(parsed_response.into()) - } - (None, None) => panic!( - "No mock for foreign call {}({:?})", - foreign_call_name, &foreign_call.inputs - ), + let response = external_resolver.send_request(req)?; + + let parsed_response: ForeignCallResult = response.result()?; + + Ok(parsed_response) + } else { + // If there's no registered mock oracle response and no registered resolver then we cannot + // return a correct response to the ACVM. The best we can do is to return an empty response, + // this allows us to ignore any foreign calls which exist solely to pass information from inside + // the circuit to the environment (e.g. custom logging) as the execution will still be able to progress. + // + // We optimistically return an empty response for all oracle calls as the ACVM will error + // should a response have been required. + Ok(ForeignCallResult::default()) } } } @@ -423,7 +363,7 @@ mod tests { }; let result = executor.execute(&foreign_call); - assert_eq!(result.unwrap(), ForeignCallResult { values: foreign_call.inputs }.into()); + assert_eq!(result.unwrap(), ForeignCallResult { values: foreign_call.inputs }); server.close(); } diff --git a/tooling/nargo/src/ops/mod.rs b/tooling/nargo/src/ops/mod.rs index 2f5e6ebb7d4..cada2f0e915 100644 --- a/tooling/nargo/src/ops/mod.rs +++ b/tooling/nargo/src/ops/mod.rs @@ -3,9 +3,7 @@ pub use self::compile::{ compile_workspace, report_errors, }; pub use self::execute::execute_program; -pub use self::foreign_calls::{ - DefaultForeignCallExecutor, ForeignCall, ForeignCallExecutor, NargoForeignCallResult, -}; +pub use self::foreign_calls::{DefaultForeignCallExecutor, ForeignCall, ForeignCallExecutor}; pub use self::optimize::{optimize_contract, optimize_program}; pub use self::transform::{transform_contract, transform_program}; diff --git a/tooling/nargo/src/ops/test.rs b/tooling/nargo/src/ops/test.rs index b216fff827d..86dd8cd7cd5 100644 --- a/tooling/nargo/src/ops/test.rs +++ b/tooling/nargo/src/ops/test.rs @@ -2,9 +2,9 @@ use acvm::{ acir::native_types::{WitnessMap, WitnessStack}, BlackBoxFunctionSolver, }; +use noirc_abi::Abi; use noirc_driver::{compile_no_check, CompileError, CompileOptions}; use noirc_errors::{debug_info::DebugInfo, FileDiagnostic}; -use noirc_evaluator::errors::RuntimeError; use noirc_frontend::hir::{def_map::TestFunction, Context}; use crate::{errors::try_to_diagnose_runtime_error, NargoError}; @@ -44,6 +44,7 @@ pub fn run_test( ); test_status_program_compile_pass( test_function, + compiled_program.abi, compiled_program.debug, circuit_execution, ) @@ -64,18 +65,7 @@ fn test_status_program_compile_fail(err: CompileError, test_function: &TestFunct return TestStatus::CompileError(err.into()); } - // The test has failed compilation, extract the assertion message if present and check if it's expected. - let assert_message = if let CompileError::RuntimeError(RuntimeError::FailedConstraint { - assert_message, - .. - }) = &err - { - assert_message.clone() - } else { - None - }; - - check_expected_failure_message(test_function, assert_message, Some(err.into())) + check_expected_failure_message(test_function, None, Some(err.into())) } /// The test function compiled successfully. @@ -84,6 +74,7 @@ fn test_status_program_compile_fail(err: CompileError, test_function: &TestFunct /// passed/failed to determine the test status. fn test_status_program_compile_pass( test_function: &TestFunction, + abi: Abi, debug: Vec, circuit_execution: Result, ) -> TestStatus { @@ -105,7 +96,7 @@ fn test_status_program_compile_pass( // If we reach here, then the circuit execution failed. // // Check if the function should have passed - let diagnostic = try_to_diagnose_runtime_error(&circuit_execution_err, &debug); + let diagnostic = try_to_diagnose_runtime_error(&circuit_execution_err, &abi, &debug); let test_should_have_passed = !test_function.should_fail(); if test_should_have_passed { return TestStatus::Fail { @@ -116,7 +107,7 @@ fn test_status_program_compile_pass( check_expected_failure_message( test_function, - circuit_execution_err.user_defined_failure_message().map(|s| s.to_string()), + circuit_execution_err.user_defined_failure_message(&abi.error_types), diagnostic, ) } diff --git a/tooling/nargo_cli/src/cli/execute_cmd.rs b/tooling/nargo_cli/src/cli/execute_cmd.rs index a353065491f..854ad559012 100644 --- a/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -154,7 +154,9 @@ pub(crate) fn execute_program( warnings: compiled_program.warnings.clone(), }; - if let Some(diagnostic) = try_to_diagnose_runtime_error(&err, &compiled_program.debug) { + if let Some(diagnostic) = + try_to_diagnose_runtime_error(&err, &compiled_program.abi, &compiled_program.debug) + { diagnostic.report(&debug_artifact, false); } diff --git a/tooling/nargo_cli/src/cli/fmt_cmd.rs b/tooling/nargo_cli/src/cli/fmt_cmd.rs index 2e0ca5632f1..8f66a0a328f 100644 --- a/tooling/nargo_cli/src/cli/fmt_cmd.rs +++ b/tooling/nargo_cli/src/cli/fmt_cmd.rs @@ -48,7 +48,7 @@ pub(crate) fn run(args: FormatCommand, config: NargoConfig) -> Result<(), CliErr let errors = errors .into_iter() .map(|error| { - let error: CustomDiagnostic = error.into(); + let error = CustomDiagnostic::from(&error); error.in_file(file_id) }) .collect(); diff --git a/tooling/nargo_cli/src/cli/fs/inputs.rs b/tooling/nargo_cli/src/cli/fs/inputs.rs index 023195010ac..bd038c51ad5 100644 --- a/tooling/nargo_cli/src/cli/fs/inputs.rs +++ b/tooling/nargo_cli/src/cli/fs/inputs.rs @@ -107,6 +107,7 @@ mod tests { // Neither of these should be relevant so we leave them empty. param_witnesses: BTreeMap::new(), return_witnesses: Vec::new(), + error_types: BTreeMap::new(), }; let input_map = BTreeMap::from([ ("foo".to_owned(), InputValue::Field(42u128.into())), diff --git a/tooling/nargo_fmt/src/visitor/item.rs b/tooling/nargo_fmt/src/visitor/item.rs index 82cfefba632..a5d042dc71e 100644 --- a/tooling/nargo_fmt/src/visitor/item.rs +++ b/tooling/nargo_fmt/src/visitor/item.rs @@ -6,7 +6,7 @@ use crate::{ }, visitor::expr::{format_seq, NewlineMode}, }; -use noirc_frontend::ast::{Distinctness, NoirFunction, Visibility}; +use noirc_frontend::ast::{NoirFunction, Visibility}; use noirc_frontend::{ hir::resolution::errors::Span, parser::{Item, ItemKind}, @@ -118,10 +118,6 @@ impl super::FmtVisitor<'_> { if let Some(span) = return_type_span { result.push_str(" -> "); - if let Distinctness::Distinct = func.def.return_distinctness { - result.push_str("distinct "); - } - let visibility = match func.def.return_visibility { Visibility::Public => "pub", Visibility::DataBus => "return_data", diff --git a/tooling/nargo_fmt/src/visitor/stmt.rs b/tooling/nargo_fmt/src/visitor/stmt.rs index e41827c94a1..8e05fe3f5c5 100644 --- a/tooling/nargo_fmt/src/visitor/stmt.rs +++ b/tooling/nargo_fmt/src/visitor/stmt.rs @@ -103,7 +103,7 @@ impl super::FmtVisitor<'_> { StatementKind::Error => unreachable!(), StatementKind::Break => self.push_rewrite("break;".into(), span), StatementKind::Continue => self.push_rewrite("continue;".into(), span), - StatementKind::Comptime(statement) => self.visit_stmt(*statement, span, is_last), + StatementKind::Comptime(statement) => self.visit_stmt(statement.kind, span, is_last), } } } diff --git a/tooling/nargo_fmt/tests/expected/fn.nr b/tooling/nargo_fmt/tests/expected/fn.nr index 0088dba6a8f..3d231cd3f7f 100644 --- a/tooling/nargo_fmt/tests/expected/fn.nr +++ b/tooling/nargo_fmt/tests/expected/fn.nr @@ -36,7 +36,7 @@ fn apply_binary_field_op( registers: &mut Registers ) -> bool {} -fn main() -> distinct pub [Field; 2] {} +fn main() -> pub [Field; 2] {} fn ret_normal_lambda1() -> ((fn() -> Field)) {} diff --git a/tooling/nargo_fmt/tests/expected/impl_trait_fn_parameter.nr b/tooling/nargo_fmt/tests/expected/impl_trait_fn_parameter.nr new file mode 100644 index 00000000000..5ace5c60dcf --- /dev/null +++ b/tooling/nargo_fmt/tests/expected/impl_trait_fn_parameter.nr @@ -0,0 +1,3 @@ +fn func_name(x: impl Eq) {} + +fn func_name(x: impl Eq, y: T) where T: SomeTrait + Eq {} diff --git a/tooling/nargo_fmt/tests/input/fn.nr b/tooling/nargo_fmt/tests/input/fn.nr index 26ff5933802..1c6d201fa39 100644 --- a/tooling/nargo_fmt/tests/input/fn.nr +++ b/tooling/nargo_fmt/tests/input/fn.nr @@ -23,7 +23,7 @@ fn main(tape: [Field; TAPE_LEN], initial_registers: [Field; REGISTER_COUNT], ini fn apply_binary_field_op(lhs: RegisterIndex, rhs: RegisterIndex, result: RegisterIndex, op: u8, registers: &mut Registers) -> bool {} -fn main() -> distinct pub [Field;2] {} +fn main() -> pub [Field;2] {} fn ret_normal_lambda1() -> ((fn() -> Field)) {} diff --git a/tooling/nargo_fmt/tests/input/impl_trait_fn_parameter.nr b/tooling/nargo_fmt/tests/input/impl_trait_fn_parameter.nr new file mode 100644 index 00000000000..5ace5c60dcf --- /dev/null +++ b/tooling/nargo_fmt/tests/input/impl_trait_fn_parameter.nr @@ -0,0 +1,3 @@ +fn func_name(x: impl Eq) {} + +fn func_name(x: impl Eq, y: T) where T: SomeTrait + Eq {} diff --git a/tooling/noir_codegen/package.json b/tooling/noir_codegen/package.json index 569841b2c6a..fa3df8ce101 100644 --- a/tooling/noir_codegen/package.json +++ b/tooling/noir_codegen/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.27.0", + "version": "0.29.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/tooling/noir_js/package.json b/tooling/noir_js/package.json index 838f317c622..325ba0fb9a7 100644 --- a/tooling/noir_js/package.json +++ b/tooling/noir_js/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.27.0", + "version": "0.29.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", diff --git a/tooling/noir_js/scripts/compile_test_programs.sh b/tooling/noir_js/scripts/compile_test_programs.sh index 5257aaae696..0642159aa69 100755 --- a/tooling/noir_js/scripts/compile_test_programs.sh +++ b/tooling/noir_js/scripts/compile_test_programs.sh @@ -3,3 +3,5 @@ rm -rf ./test/noir_compiled_examples/**/target nargo --program-dir ./test/noir_compiled_examples/assert_lt compile --force nargo --program-dir ./test/noir_compiled_examples/assert_msg_runtime compile --force +nargo --program-dir ./test/noir_compiled_examples/fold_fibonacci compile --force +nargo --program-dir ./test/noir_compiled_examples/assert_raw_payload compile --force diff --git a/tooling/noir_js/src/index.ts b/tooling/noir_js/src/index.ts index bacb391a464..e7f356a582e 100644 --- a/tooling/noir_js/src/index.ts +++ b/tooling/noir_js/src/index.ts @@ -16,6 +16,7 @@ export { InputMap } from '@noir-lang/noirc_abi'; export { WitnessMap, ForeignCallHandler, ForeignCallInput, ForeignCallOutput } from '@noir-lang/acvm_js'; export { Noir } from './program.js'; +export { ErrorWithPayload } from './witness_generation.js'; /** @ignore */ export { acvm, abi }; diff --git a/tooling/noir_js/src/program.ts b/tooling/noir_js/src/program.ts index 8d80ec3a247..86aa0f60ddf 100644 --- a/tooling/noir_js/src/program.ts +++ b/tooling/noir_js/src/program.ts @@ -2,7 +2,7 @@ import { Backend, CompiledCircuit, ProofData } from '@noir-lang/types'; import { generateWitness } from './witness_generation.js'; import initAbi, { abiDecode, InputMap, InputValue } from '@noir-lang/noirc_abi'; -import initACVM, { compressWitness, ForeignCallHandler } from '@noir-lang/acvm_js'; +import initACVM, { compressWitnessStack, ForeignCallHandler } from '@noir-lang/acvm_js'; export class Noir { constructor( @@ -55,9 +55,10 @@ export class Noir { foreignCallHandler?: ForeignCallHandler, ): Promise<{ witness: Uint8Array; returnValue: InputValue }> { await this.init(); - const witness = await generateWitness(this.circuit, inputs, foreignCallHandler); - const { return_value: returnValue } = abiDecode(this.circuit.abi, witness); - return { witness: compressWitness(witness), returnValue }; + const witness_stack = await generateWitness(this.circuit, inputs, foreignCallHandler); + const main_witness = witness_stack[0].witness; + const { return_value: returnValue } = abiDecode(this.circuit.abi, main_witness); + return { witness: compressWitnessStack(witness_stack), returnValue }; } /** diff --git a/tooling/noir_js/src/witness_generation.ts b/tooling/noir_js/src/witness_generation.ts index cef1d817d9b..7d018c81d53 100644 --- a/tooling/noir_js/src/witness_generation.ts +++ b/tooling/noir_js/src/witness_generation.ts @@ -1,14 +1,15 @@ -import { abiEncode, InputMap } from '@noir-lang/noirc_abi'; +import { abiDecodeError, abiEncode, InputMap } from '@noir-lang/noirc_abi'; import { base64Decode } from './base64_decode.js'; import { - WitnessMap, + WitnessStack, ForeignCallHandler, ForeignCallInput, createBlackBoxSolver, WasmBlackBoxFunctionSolver, - executeCircuitWithBlackBoxSolver, + executeProgramWithBlackBoxSolver, + ExecutionError, } from '@noir-lang/acvm_js'; -import { CompiledCircuit } from '@noir-lang/types'; +import { Abi, CompiledCircuit } from '@noir-lang/types'; let solver: Promise; @@ -26,29 +27,50 @@ const defaultForeignCallHandler: ForeignCallHandler = async (name: string, args: // // If a user needs to print values then they should provide a custom foreign call handler. return []; - } else if (name == 'assert_message') { - // By default we do not do anything for `assert_message` foreign calls due to a need for formatting, - // however we provide an empty response in order to not halt execution. - // - // If a user needs to use dynamic assertion messages then they should provide a custom foreign call handler. - return []; } throw Error(`Unexpected oracle during execution: ${name}(${args.join(', ')})`); }; +// Payload is any since it can be of any type defined by the circuit dev. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ErrorWithPayload = ExecutionError & { decodedAssertionPayload?: any }; + +function parseErrorPayload(abi: Abi, originalError: ExecutionError): Error { + const payload = originalError.rawAssertionPayload; + if (!payload) return originalError; + const enrichedError = originalError as ErrorWithPayload; + + try { + // Decode the payload + const decodedPayload = abiDecodeError(abi, payload); + + if (typeof decodedPayload === 'string') { + // If it's a string, just add it to the error message + enrichedError.message = `Circuit execution failed: ${decodedPayload}`; + } else { + // If not, attach the payload to the original error + enrichedError.decodedAssertionPayload = decodedPayload; + } + } catch (_errorDecoding) { + // Ignore errors decoding the payload + } + + return enrichedError; +} + // Generates the witnesses needed to feed into the chosen proving system export async function generateWitness( compiledProgram: CompiledCircuit, inputs: InputMap, foreignCallHandler: ForeignCallHandler = defaultForeignCallHandler, -): Promise { +): Promise { // Throws on ABI encoding error const witnessMap = abiEncode(compiledProgram.abi, inputs); // Execute the circuit to generate the rest of the witnesses and serialize // them into a Uint8Array. try { - const solvedWitness = await executeCircuitWithBlackBoxSolver( + const solvedWitness = await executeProgramWithBlackBoxSolver( await getSolver(), base64Decode(compiledProgram.bytecode), witnessMap, @@ -56,6 +78,10 @@ export async function generateWitness( ); return solvedWitness; } catch (err) { + // Typescript types catched errors as unknown or any, so we need to narrow its type to check if it has raw assertion payload. + if (typeof err === 'object' && err !== null && 'rawAssertionPayload' in err) { + throw parseErrorPayload(compiledProgram.abi, err as ExecutionError); + } throw new Error(`Circuit execution failed: ${err}`); } } diff --git a/tooling/noir_js/test/node/e2e.test.ts b/tooling/noir_js/test/node/e2e.test.ts index 979841c47e6..dbb9abcc964 100644 --- a/tooling/noir_js/test/node/e2e.test.ts +++ b/tooling/noir_js/test/node/e2e.test.ts @@ -1,10 +1,12 @@ import { expect } from 'chai'; import assert_lt_json from '../noir_compiled_examples/assert_lt/target/assert_lt.json' assert { type: 'json' }; +import fold_fibonacci_json from '../noir_compiled_examples/fold_fibonacci/target/fold_fibonacci.json' assert { type: 'json' }; import { Noir } from '@noir-lang/noir_js'; import { BarretenbergBackend as Backend, BarretenbergVerifier as Verifier } from '@noir-lang/backend_barretenberg'; import { CompiledCircuit } from '@noir-lang/types'; const assert_lt_program = assert_lt_json as CompiledCircuit; +const fold_fibonacci_program = fold_fibonacci_json as CompiledCircuit; it('end-to-end proof creation and verification (outer)', async () => { // Noir.Js part @@ -149,3 +151,24 @@ it('[BUG] -- bb.js null function or function signature mismatch (outer-inner) ', const isValidInner = await prover.verifyProof(_proofInner); expect(isValidInner).to.be.true; }); + +it('end-to-end proof creation and verification for multiple ACIR circuits (inner)', async () => { + // Noir.Js part + const inputs = { + x: '10', + }; + + const program = new Noir(fold_fibonacci_program); + + const { witness } = await program.execute(inputs); + + // bb.js part + // + // Proof creation + const backend = new Backend(fold_fibonacci_program); + const proof = await backend.generateProof(witness); + + // Proof verification + const isValid = await backend.verifyProof(proof); + expect(isValid).to.be.true; +}); diff --git a/tooling/noir_js/test/node/execute.test.ts b/tooling/noir_js/test/node/execute.test.ts index 491bcb0dfc4..b2e76e54efc 100644 --- a/tooling/noir_js/test/node/execute.test.ts +++ b/tooling/noir_js/test/node/execute.test.ts @@ -1,11 +1,15 @@ import assert_lt_json from '../noir_compiled_examples/assert_lt/target/assert_lt.json' assert { type: 'json' }; import assert_msg_json from '../noir_compiled_examples/assert_msg_runtime/target/assert_msg_runtime.json' assert { type: 'json' }; -import { Noir } from '@noir-lang/noir_js'; +import fold_fibonacci_json from '../noir_compiled_examples/fold_fibonacci/target/fold_fibonacci.json' assert { type: 'json' }; +import assert_raw_payload_json from '../noir_compiled_examples/assert_raw_payload/target/assert_raw_payload.json' assert { type: 'json' }; + +import { Noir, ErrorWithPayload } from '@noir-lang/noir_js'; import { CompiledCircuit } from '@noir-lang/types'; import { expect } from 'chai'; const assert_lt_program = assert_lt_json as CompiledCircuit; const assert_msg_runtime = assert_msg_json as CompiledCircuit; +const fold_fibonacci_program = fold_fibonacci_json as CompiledCircuit; it('returns the return value of the circuit', async () => { const inputs = { @@ -17,13 +21,97 @@ it('returns the return value of the circuit', async () => { expect(returnValue).to.be.eq('0x05'); }); -it('circuit with a dynamic assert message should fail on an assert failure not the foreign call handler', async () => { +it('circuit with a fmt string assert message should fail with the resolved assertion message', async () => { const inputs = { x: '10', y: '5', }; try { await new Noir(assert_msg_runtime).execute(inputs); + } catch (error) { + const knownError = error as Error; + expect(knownError.message).to.equal('Circuit execution failed: Expected x < y but got 10 < 5'); + } +}); + +it('circuit with a raw assert payload should fail with the decoded payload', async () => { + const inputs = { + x: '7', + y: '5', + }; + try { + await new Noir(assert_raw_payload_json).execute(inputs); + } catch (error) { + const knownError = error as ErrorWithPayload; + const invalidXYErrorSelector = Object.keys(assert_raw_payload_json.abi.error_types)[0]; + expect(knownError.rawAssertionPayload!.selector).to.equal(invalidXYErrorSelector); + expect(knownError.decodedAssertionPayload).to.deep.equal({ + x: '0x07', + y: '0x05', + }); + } +}); + +it('successfully executes a program with multiple acir circuits', async () => { + const inputs = { + x: '10', + }; + try { + await new Noir(fold_fibonacci_program).execute(inputs); + } catch (error) { + const knownError = error as Error; + expect(knownError.message).to.equal('Circuit execution failed: Expected x < y but got 10 < 5'); + } +}); + +it('circuit with a raw assert payload should fail with the decoded payload', async () => { + const inputs = { + x: '7', + y: '5', + }; + try { + await new Noir(assert_raw_payload_json).execute(inputs); + } catch (error) { + const knownError = error as ErrorWithPayload; + const invalidXYErrorSelector = Object.keys(assert_raw_payload_json.abi.error_types)[0]; + expect(knownError.rawAssertionPayload!.selector).to.equal(invalidXYErrorSelector); + expect(knownError.decodedAssertionPayload).to.deep.equal({ + x: '0x07', + y: '0x05', + }); + } +}); + +it('successfully executes a program with multiple acir circuits', async () => { + const inputs = { + x: '10', + }; + try { + await new Noir(fold_fibonacci_program).execute(inputs); + } catch (error) { + const knownError = error as Error; + expect(knownError.message).to.equal('Circuit execution failed: Error: Cannot satisfy constraint'); + } +}); + +it('successfully executes a program with multiple acir circuits', async () => { + const inputs = { + x: '10', + }; + try { + await new Noir(fold_fibonacci_program).execute(inputs); + } catch (error) { + const knownError = error as Error; + expect(knownError.message).to.equal('Circuit execution failed: Error: Cannot satisfy constraint'); + } +}); + +it('successfully executes a program with multiple acir circuits', async () => { + const inputs = { + x: '10', + }; + try { + await new Noir(fold_fibonacci_program).execute(inputs); } catch (error) { const knownError = error as Error; expect(knownError.message).to.equal('Circuit execution failed: Error: Cannot satisfy constraint'); diff --git a/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr b/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr index 40e447cad02..0bcd5c58c24 100644 --- a/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr +++ b/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr @@ -1,6 +1,4 @@ fn main(x: u64, y: pub u64) { - // A dynamic assertion message is used to show that noirJS will ignore the call and continue execution - // We need this assertion to fail as the `assert_message` oracle in Noir is only called - // upon a failing condition in an assert. + // A fmtstr assertion message is used to show that noirJS will decode the error payload as a string. assert(x < y, f"Expected x < y but got {x} < {y}"); } diff --git a/tooling/noir_js/test/noir_compiled_examples/assert_raw_payload/Nargo.toml b/tooling/noir_js/test/noir_compiled_examples/assert_raw_payload/Nargo.toml new file mode 100644 index 00000000000..f88832264ea --- /dev/null +++ b/tooling/noir_js/test/noir_compiled_examples/assert_raw_payload/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "assert_raw_payload" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] diff --git a/tooling/noir_js/test/noir_compiled_examples/assert_raw_payload/src/main.nr b/tooling/noir_js/test/noir_compiled_examples/assert_raw_payload/src/main.nr new file mode 100644 index 00000000000..4c981330b31 --- /dev/null +++ b/tooling/noir_js/test/noir_compiled_examples/assert_raw_payload/src/main.nr @@ -0,0 +1,9 @@ +struct InvalidXYError { + x: u64, + y: u64, +} + +fn main(x: u64, y: pub u64) { + // A raw assertion payload is used to show that noirJS will decode the error payload as a struct. + assert(x < y, InvalidXYError { x, y }); +} diff --git a/tooling/noir_js/test/noir_compiled_examples/fold_fibonacci/Nargo.toml b/tooling/noir_js/test/noir_compiled_examples/fold_fibonacci/Nargo.toml new file mode 100644 index 00000000000..6d8214689b0 --- /dev/null +++ b/tooling/noir_js/test/noir_compiled_examples/fold_fibonacci/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "fold_fibonacci" +type = "bin" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] \ No newline at end of file diff --git a/tooling/noir_js/test/noir_compiled_examples/fold_fibonacci/src/main.nr b/tooling/noir_js/test/noir_compiled_examples/fold_fibonacci/src/main.nr new file mode 100644 index 00000000000..e150a586086 --- /dev/null +++ b/tooling/noir_js/test/noir_compiled_examples/fold_fibonacci/src/main.nr @@ -0,0 +1,12 @@ +fn main(x: u32) { + assert(fibonacci(x) == 55); +} + +#[fold] +fn fibonacci(x: u32) -> u32 { + if x <= 1 { + x + } else { + fibonacci(x - 1) + fibonacci(x - 2) + } +} diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index af9e47a8e63..c6985f4b037 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.27.0", + "version": "0.29.0", "packageManager": "yarn@3.5.1", "license": "(MIT OR Apache-2.0)", "type": "module", @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.35.1", + "@aztec/bb.js": "portal:../../../../barretenberg/ts", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts b/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts index 079a1ad268b..cfd43eff250 100644 --- a/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts +++ b/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts @@ -55,6 +55,7 @@ const abi: Abi = { visibility: 'public', }, return_witnesses: [2, 13, 13], + error_types: {}, }; it('flattens a witness map in order of its witness indices', async () => { diff --git a/tooling/noir_js_types/package.json b/tooling/noir_js_types/package.json index 316612a7c51..5332ce20cc7 100644 --- a/tooling/noir_js_types/package.json +++ b/tooling/noir_js_types/package.json @@ -4,7 +4,7 @@ "The Noir Team " ], "packageManager": "yarn@3.5.1", - "version": "0.27.0", + "version": "0.29.0", "license": "(MIT OR Apache-2.0)", "homepage": "https://noir-lang.org/", "repository": { diff --git a/tooling/noir_js_types/src/types.ts b/tooling/noir_js_types/src/types.ts index 456e5a57f40..0258f2f90c9 100644 --- a/tooling/noir_js_types/src/types.ts +++ b/tooling/noir_js_types/src/types.ts @@ -19,6 +19,20 @@ export type AbiParameter = { visibility: Visibility; }; +export type AbiErrorType = + | { + error_kind: 'fmtstring'; + length: number; + item_types: AbiType[]; + } + | ({ error_kind: 'custom' } & AbiType); + +// The payload for a raw assertion error returned on execution. +export type RawAssertionPayload = { + selector: string; + data: string[]; +}; + // Map from witness index to hex string value of witness. export type WitnessMap = Map; @@ -27,6 +41,7 @@ export type Abi = { param_witnesses: Record; return_type: { abi_type: AbiType; visibility: Visibility } | null; return_witnesses: number[]; + error_types: Record; }; export interface VerifierBackend { diff --git a/tooling/noirc_abi/Cargo.toml b/tooling/noirc_abi/Cargo.toml index 3258ea04c40..040f8a0dc79 100644 --- a/tooling/noirc_abi/Cargo.toml +++ b/tooling/noirc_abi/Cargo.toml @@ -12,6 +12,7 @@ license.workspace = true acvm.workspace = true iter-extended.workspace = true noirc_frontend.workspace = true +noirc_printable_type.workspace = true toml.workspace = true serde_json = "1.0" serde.workspace = true diff --git a/tooling/noirc_abi/src/input_parser/mod.rs b/tooling/noirc_abi/src/input_parser/mod.rs index 4cf66820b8d..9629ddc87ab 100644 --- a/tooling/noirc_abi/src/input_parser/mod.rs +++ b/tooling/noirc_abi/src/input_parser/mod.rs @@ -270,6 +270,7 @@ mod serialization_tests { // These two fields are unused when serializing/deserializing to file. param_witnesses: BTreeMap::new(), return_witnesses: Vec::new(), + error_types: Default::default(), }; let input_map: BTreeMap = BTreeMap::from([ diff --git a/tooling/noirc_abi/src/lib.rs b/tooling/noirc_abi/src/lib.rs index 8ff0154d32c..7e89a102a98 100644 --- a/tooling/noirc_abi/src/lib.rs +++ b/tooling/noirc_abi/src/lib.rs @@ -4,7 +4,10 @@ #![warn(clippy::semicolon_if_nothing_returned)] use acvm::{ - acir::native_types::{Witness, WitnessMap}, + acir::{ + circuit::ErrorSelector, + native_types::{Witness, WitnessMap}, + }, FieldElement, }; use errors::AbiError; @@ -12,8 +15,12 @@ use input_parser::InputValue; use iter_extended::{try_btree_map, try_vecmap, vecmap}; use noirc_frontend::ast::{Signedness, Visibility}; use noirc_frontend::{hir::Context, Type, TypeBinding, TypeVariableKind}; +use noirc_printable_type::{ + decode_value as printable_type_decode_value, PrintableType, PrintableValue, + PrintableValueDisplay, +}; use serde::{Deserialize, Serialize}; -use std::ops::Range; +use std::{borrow::Borrow, ops::Range}; use std::{collections::BTreeMap, str}; // This is the ABI used to bridge the different TOML formats for the initial // witness, the partial witness generator and the interpreter. @@ -203,6 +210,38 @@ impl AbiType { } } +impl From<&AbiType> for PrintableType { + fn from(value: &AbiType) -> Self { + match value { + AbiType::Field => PrintableType::Field, + AbiType::String { length } => PrintableType::String { length: *length }, + AbiType::Tuple { fields } => { + let fields = fields.iter().map(|field| field.into()).collect(); + PrintableType::Tuple { types: fields } + } + AbiType::Array { length, typ } => { + let borrowed: &AbiType = typ.borrow(); + PrintableType::Array { length: *length, typ: Box::new(borrowed.into()) } + } + AbiType::Boolean => PrintableType::Boolean, + AbiType::Struct { path, fields } => { + let fields = + fields.iter().map(|(name, field)| (name.clone(), field.into())).collect(); + PrintableType::Struct { + name: path.split("::").last().unwrap_or_default().to_string(), + fields, + } + } + AbiType::Integer { sign: Sign::Unsigned, width } => { + PrintableType::UnsignedInteger { width: *width } + } + AbiType::Integer { sign: Sign::Signed, width } => { + PrintableType::SignedInteger { width: *width } + } + } + } +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] /// An argument or return value of the circuit's `main` function. pub struct AbiParameter { @@ -223,6 +262,7 @@ pub struct AbiReturnType { pub abi_type: AbiType, pub visibility: AbiVisibility, } + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Abi { /// An ordered list of the arguments to the program's `main` function, specifying their types and visibility. @@ -232,6 +272,7 @@ pub struct Abi { pub param_witnesses: BTreeMap>>, pub return_type: Option, pub return_witnesses: Vec, + pub error_types: BTreeMap, } impl Abi { @@ -281,6 +322,7 @@ impl Abi { param_witnesses, return_type: self.return_type, return_witnesses: self.return_witnesses, + error_types: self.error_types, } } @@ -444,7 +486,7 @@ impl Abi { } } -fn decode_value( +pub fn decode_value( field_iterator: &mut impl Iterator, value_type: &AbiType, ) -> Result { @@ -547,6 +589,57 @@ fn range_to_vec(ranges: &[Range]) -> Vec { result } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "error_kind", rename_all = "lowercase")] +pub enum AbiErrorType { + FmtString { length: u64, item_types: Vec }, + Custom(AbiType), +} +impl AbiErrorType { + pub fn from_type(context: &Context, typ: &Type) -> Self { + match typ { + Type::FmtString(len, item_types) => { + let length = len.evaluate_to_u64().expect("Cannot evaluate fmt length"); + let Type::Tuple(item_types) = item_types.as_ref() else { + unreachable!("FmtString items must be a tuple") + }; + let item_types = + item_types.iter().map(|typ| AbiType::from_type(context, typ)).collect(); + Self::FmtString { length, item_types } + } + _ => Self::Custom(AbiType::from_type(context, typ)), + } + } +} + +pub fn display_abi_error( + fields: &[FieldElement], + error_type: AbiErrorType, +) -> PrintableValueDisplay { + match error_type { + AbiErrorType::FmtString { length, item_types } => { + let mut fields_iter = fields.iter().copied(); + let PrintableValue::String(string) = + printable_type_decode_value(&mut fields_iter, &PrintableType::String { length }) + else { + unreachable!("Got non-string from string decoding"); + }; + let _length_of_items = fields_iter.next(); + let items = item_types.into_iter().map(|abi_type| { + let printable_typ = (&abi_type).into(); + let decoded = printable_type_decode_value(&mut fields_iter, &printable_typ); + (decoded, printable_typ) + }); + PrintableValueDisplay::FmtString(string, items.collect()) + } + AbiErrorType::Custom(abi_typ) => { + let printable_type = (&abi_typ).into(); + let decoded = printable_type_decode_value(&mut fields.iter().copied(), &printable_type); + PrintableValueDisplay::Plain(decoded, printable_type) + } + } +} + #[cfg(test)] mod test { use std::collections::BTreeMap; @@ -583,6 +676,7 @@ mod test { visibility: AbiVisibility::Public, }), return_witnesses: vec![Witness(3)], + error_types: BTreeMap::default(), }; // Note we omit return value from inputs diff --git a/tooling/noirc_abi_wasm/build.sh b/tooling/noirc_abi_wasm/build.sh index 16fb26e55db..c07d2d8a4c1 100755 --- a/tooling/noirc_abi_wasm/build.sh +++ b/tooling/noirc_abi_wasm/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -require_command wasm-opt +#require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/tooling/noirc_abi_wasm/package.json b/tooling/noirc_abi_wasm/package.json index 0e4aaceeae3..ac7d1606298 100644 --- a/tooling/noirc_abi_wasm/package.json +++ b/tooling/noirc_abi_wasm/package.json @@ -3,7 +3,7 @@ "contributors": [ "The Noir Team " ], - "version": "0.27.0", + "version": "0.29.0", "license": "(MIT OR Apache-2.0)", "homepage": "https://noir-lang.org/", "repository": { diff --git a/tooling/noirc_abi_wasm/src/lib.rs b/tooling/noirc_abi_wasm/src/lib.rs index fad5abaebba..10c0c43b352 100644 --- a/tooling/noirc_abi_wasm/src/lib.rs +++ b/tooling/noirc_abi_wasm/src/lib.rs @@ -5,12 +5,16 @@ // See Cargo.toml for explanation. use getrandom as _; -use acvm::acir::native_types::{WitnessMap, WitnessStack}; +use acvm::acir::{ + circuit::RawAssertionPayload, + native_types::{WitnessMap, WitnessStack}, +}; use iter_extended::try_btree_map; use noirc_abi::{ + decode_value, display_abi_error, errors::InputParserError, input_parser::{json::JsonTypes, InputValue}, - Abi, MAIN_RETURN_NAME, + Abi, AbiErrorType, MAIN_RETURN_NAME, }; use serde::Serialize; use std::collections::BTreeMap; @@ -26,8 +30,8 @@ use js_witness_map::JsWitnessMap; #[wasm_bindgen(typescript_custom_section)] const INPUT_MAP: &'static str = r#" -import { Field, InputValue, InputMap, Visibility, Sign, AbiType, AbiParameter, Abi, WitnessMap } from "@noir-lang/types"; -export { Field, InputValue, InputMap, Visibility, Sign, AbiType, AbiParameter, Abi, WitnessMap } from "@noir-lang/types"; +import { Field, InputValue, InputMap, Visibility, Sign, AbiType, AbiParameter, Abi, WitnessMap, RawAssertionPayload } from "@noir-lang/types"; +export { Field, InputValue, InputMap, Visibility, Sign, AbiType, AbiParameter, Abi, WitnessMap, RawAssertionPayload } from "@noir-lang/types"; "#; #[wasm_bindgen] @@ -40,6 +44,10 @@ extern "C" { #[derive(Clone, Debug, PartialEq, Eq)] pub type JsInputValue; + #[wasm_bindgen(extends = js_sys::Object, js_name = "RawAssertionPayload", typescript_type = "RawAssertionPayload")] + #[derive(Clone, Debug, PartialEq, Eq)] + pub type JsRawAssertionPayload; + #[wasm_bindgen(extends = js_sys::Object, js_name = "Abi", typescript_type = "Abi")] #[derive(Clone, Debug, PartialEq, Eq)] pub type JsAbi; @@ -122,3 +130,30 @@ pub fn serialise_witness(witness_map: JsWitnessMap) -> Result, JsAbiErro let output = witness_stack.try_into(); output.map_err(|_| JsAbiError::new("Failed to convert to Vec".to_string())) } + +#[wasm_bindgen(js_name = abiDecodeError)] +pub fn abi_decode_error( + abi: JsAbi, + raw_error: JsRawAssertionPayload, +) -> Result { + console_error_panic_hook::set_once(); + let mut abi: Abi = + JsValueSerdeExt::into_serde(&JsValue::from(abi)).map_err(|err| err.to_string())?; + + let raw_error: RawAssertionPayload = + JsValueSerdeExt::into_serde(&JsValue::from(raw_error)).map_err(|err| err.to_string())?; + + let error_type = abi.error_types.remove(&raw_error.selector).expect("Missing error type"); + match error_type { + AbiErrorType::FmtString { .. } => { + let string = display_abi_error(&raw_error.data, error_type).to_string(); + Ok(JsValue::from_str(&string)) + } + AbiErrorType::Custom(typ) => { + let input_value = decode_value(&mut raw_error.data.into_iter(), &typ)?; + let json_types = JsonTypes::try_from_input_value(&input_value, &typ)?; + ::from_serde(&json_types) + .map_err(|err| err.to_string().into()) + } + } +} diff --git a/tooling/noirc_abi_wasm/test/browser/decode_error.test.ts b/tooling/noirc_abi_wasm/test/browser/decode_error.test.ts new file mode 100644 index 00000000000..2407ddc6535 --- /dev/null +++ b/tooling/noirc_abi_wasm/test/browser/decode_error.test.ts @@ -0,0 +1,64 @@ +import { expect } from '@esm-bundle/chai'; +import initNoirAbi, { RawAssertionPayload, abiDecodeError } from '@noir-lang/noirc_abi'; + +beforeEach(async () => { + await initNoirAbi(); +}); + +it('Recovers custom field errors', async () => { + const { FAKE_FIELD_SELECTOR, abi } = await import('../shared/decode_error'); + + const payload: RawAssertionPayload = { + selector: FAKE_FIELD_SELECTOR, + data: ['0x000001'], + }; + + const decoded = abiDecodeError(abi, payload); + expect(decoded).to.equal('0x01'); +}); + +it('Recovers custom tuple errors', async () => { + const { FAKE_TUPLE_SELECTOR, abi } = await import('../shared/decode_error'); + + const payload: RawAssertionPayload = { + selector: FAKE_TUPLE_SELECTOR, + data: ['0x000001', '0x000002'], + }; + + const decoded = abiDecodeError(abi, payload); + expect(decoded).to.deep.equal(['0x01', '0x02']); +}); + +it('Recovers custom fmt string errors', async () => { + const { FAKE_FMT_STRING_SELECTOR, abi, SAMPLE_FMT_STRING } = await import('../shared/decode_error'); + + // FmtStrings contain the string serialized to fields + const data = [...SAMPLE_FMT_STRING].map((c) => `0x${c.charCodeAt(0).toString(16)}`); + // Then they contain the length of the values to replace + data.push('0x01'); + // And then the value to replace + data.push('0x07'); + + const payload: RawAssertionPayload = { + selector: FAKE_FMT_STRING_SELECTOR, + data, + }; + + const decoded = abiDecodeError(abi, payload); + expect(decoded).to.equal('hello 0x07'); +}); + +it('Recovers struct errors', async () => { + const { FAKE_STRUCT_SELECTOR, abi } = await import('../shared/decode_error'); + + const payload: RawAssertionPayload = { + selector: FAKE_STRUCT_SELECTOR, + data: ['0x01', '0x02'], + }; + + const decoded = abiDecodeError(abi, payload); + expect(decoded).to.deep.equal({ + a: '0x01', + b: '0x02', + }); +}); diff --git a/tooling/noirc_abi_wasm/test/node/decode_error.test.ts b/tooling/noirc_abi_wasm/test/node/decode_error.test.ts new file mode 100644 index 00000000000..711653ad077 --- /dev/null +++ b/tooling/noirc_abi_wasm/test/node/decode_error.test.ts @@ -0,0 +1,60 @@ +import { expect } from 'chai'; +import { RawAssertionPayload, abiDecodeError } from '@noir-lang/noirc_abi'; + +it('Recovers custom field errors', async () => { + const { FAKE_FIELD_SELECTOR, abi } = await import('../shared/decode_error'); + + const payload: RawAssertionPayload = { + selector: FAKE_FIELD_SELECTOR, + data: ['0x000001'], + }; + + const decoded = abiDecodeError(abi, payload); + expect(decoded).to.equal('0x01'); +}); + +it('Recovers custom tuple errors', async () => { + const { FAKE_TUPLE_SELECTOR, abi } = await import('../shared/decode_error'); + + const payload: RawAssertionPayload = { + selector: FAKE_TUPLE_SELECTOR, + data: ['0x000001', '0x000002'], + }; + + const decoded = abiDecodeError(abi, payload); + expect(decoded).to.deep.equal(['0x01', '0x02']); +}); + +it('Recovers custom fmt string errors', async () => { + const { FAKE_FMT_STRING_SELECTOR, abi, SAMPLE_FMT_STRING } = await import('../shared/decode_error'); + + // FmtStrings contain the string serialized to fields + const data = [...SAMPLE_FMT_STRING].map((c) => `0x${c.charCodeAt(0).toString(16)}`); + // Then they contain the length of the values to replace + data.push('0x01'); + // And then the value to replace + data.push('0x07'); + + const payload: RawAssertionPayload = { + selector: FAKE_FMT_STRING_SELECTOR, + data, + }; + + const decoded = abiDecodeError(abi, payload); + expect(decoded).to.equal('hello 0x07'); +}); + +it('Recovers struct errors', async () => { + const { FAKE_STRUCT_SELECTOR, abi } = await import('../shared/decode_error'); + + const payload: RawAssertionPayload = { + selector: FAKE_STRUCT_SELECTOR, + data: ['0x01', '0x02'], + }; + + const decoded = abiDecodeError(abi, payload); + expect(decoded).to.deep.equal({ + a: '0x01', + b: '0x02', + }); +}); diff --git a/tooling/noirc_abi_wasm/test/shared/abi_encode.ts b/tooling/noirc_abi_wasm/test/shared/abi_encode.ts index cb80c6710ba..f4ab8175700 100644 --- a/tooling/noirc_abi_wasm/test/shared/abi_encode.ts +++ b/tooling/noirc_abi_wasm/test/shared/abi_encode.ts @@ -12,6 +12,7 @@ export const abi: Abi = { param_witnesses: { foo: [{ start: 1, end: 2 }], bar: [{ start: 2, end: 4 }] }, return_type: null, return_witnesses: [], + error_types: {}, }; export const inputs: InputMap = { diff --git a/tooling/noirc_abi_wasm/test/shared/array_as_field.ts b/tooling/noirc_abi_wasm/test/shared/array_as_field.ts index 0cc0035fa68..3698b913c66 100644 --- a/tooling/noirc_abi_wasm/test/shared/array_as_field.ts +++ b/tooling/noirc_abi_wasm/test/shared/array_as_field.ts @@ -11,6 +11,7 @@ export const abi: Abi = { param_witnesses: { foo: [{ start: 1, end: 3 }] }, return_type: null, return_witnesses: [], + error_types: {}, }; export const inputs: InputMap = { diff --git a/tooling/noirc_abi_wasm/test/shared/decode_error.ts b/tooling/noirc_abi_wasm/test/shared/decode_error.ts new file mode 100644 index 00000000000..36eb18b5210 --- /dev/null +++ b/tooling/noirc_abi_wasm/test/shared/decode_error.ts @@ -0,0 +1,46 @@ +import { Abi } from '@noir-lang/noirc_abi'; + +export const FAKE_FIELD_SELECTOR = '1'; +export const FAKE_TUPLE_SELECTOR = '2'; +export const FAKE_FMT_STRING_SELECTOR = '3'; +export const FAKE_STRUCT_SELECTOR = '4'; + +export const SAMPLE_FMT_STRING = 'hello {a}'; + +export const abi: Abi = { + parameters: [ + { + name: 'foo', + type: { kind: 'array', length: 2, type: { kind: 'field' } }, + visibility: 'private', + }, + ], + param_witnesses: { foo: [{ start: 1, end: 3 }] }, + return_type: null, + return_witnesses: [], + error_types: { + [FAKE_FIELD_SELECTOR]: { + error_kind: 'custom', + kind: 'field', + }, + [FAKE_TUPLE_SELECTOR]: { + error_kind: 'custom', + kind: 'tuple', + fields: [{ kind: 'field' }, { kind: 'field' }], + }, + [FAKE_FMT_STRING_SELECTOR]: { + error_kind: 'fmtstring', + length: SAMPLE_FMT_STRING.length, + item_types: [{ kind: 'field' }], + }, + [FAKE_STRUCT_SELECTOR]: { + error_kind: 'custom', + kind: 'struct', + path: 'foo', + fields: [ + { name: 'a', type: { kind: 'field' } }, + { name: 'b', type: { kind: 'field' } }, + ], + }, + }, +}; diff --git a/tooling/noirc_abi_wasm/test/shared/field_as_array.ts b/tooling/noirc_abi_wasm/test/shared/field_as_array.ts index 6ae709459de..4e3e2fd12a8 100644 --- a/tooling/noirc_abi_wasm/test/shared/field_as_array.ts +++ b/tooling/noirc_abi_wasm/test/shared/field_as_array.ts @@ -11,6 +11,7 @@ export const abi: Abi = { param_witnesses: { foo: [{ start: 1, end: 3 }] }, return_type: null, return_witnesses: [], + error_types: {}, }; export const inputs: InputMap = { diff --git a/tooling/noirc_abi_wasm/test/shared/structs.ts b/tooling/noirc_abi_wasm/test/shared/structs.ts index 6614f8f278e..ee666e40e87 100644 --- a/tooling/noirc_abi_wasm/test/shared/structs.ts +++ b/tooling/noirc_abi_wasm/test/shared/structs.ts @@ -54,6 +54,7 @@ export const abi: Abi = { }, return_type: null, return_witnesses: [], + error_types: {}, }; export const inputs: InputMap = { diff --git a/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts b/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts index c6e066e2bcd..82a3e3998ca 100644 --- a/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts +++ b/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts @@ -11,6 +11,7 @@ export const abi: Abi = { param_witnesses: { foo: [{ start: 1, end: 2 }] }, return_type: null, return_witnesses: [], + error_types: {}, }; export const inputs: InputMap = { diff --git a/compiler/utils/iter-extended/Cargo.toml b/utils/iter-extended/Cargo.toml similarity index 100% rename from compiler/utils/iter-extended/Cargo.toml rename to utils/iter-extended/Cargo.toml diff --git a/compiler/utils/iter-extended/src/lib.rs b/utils/iter-extended/src/lib.rs similarity index 100% rename from compiler/utils/iter-extended/src/lib.rs rename to utils/iter-extended/src/lib.rs diff --git a/yarn.lock b/yarn.lock index e9915882fac..b45678f5d8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,19 +221,18 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.35.1": - version: 0.35.1 - resolution: "@aztec/bb.js@npm:0.35.1" +"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": + version: 0.0.0-use.local + resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 tslib: ^2.4.0 bin: - bb.js: dest/node/main.js - checksum: 8e3551f059523d9494af4721a9219e2c6e63c8ed1df447a2d0daa9f8526a794758ae708bd1d9c9b1fbfb89c56dc867d9f0b87250dbabfcde23ec02dabbb5a32a + bb.js: ./dest/node/main.js languageName: node - linkType: hard + linkType: soft "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -4396,7 +4395,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.35.1 + "@aztec/bb.js": "portal:../../../../barretenberg/ts" "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3 From 085cdbed8cb548a041f3e29584978f00b58fc28d Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 8 May 2024 12:21:43 +0100 Subject: [PATCH 2/4] chore: update barretenberg imports --- acvm-repo/acvm_js/build.sh | 2 +- tooling/bb_abstraction_leaks/build.rs | 2 +- tooling/noir_js_backend_barretenberg/package.json | 2 +- yarn.lock | 13 +++++++------ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/acvm-repo/acvm_js/build.sh b/acvm-repo/acvm_js/build.sh index c07d2d8a4c1..16fb26e55db 100755 --- a/acvm-repo/acvm_js/build.sh +++ b/acvm-repo/acvm_js/build.sh @@ -25,7 +25,7 @@ function run_if_available { require_command jq require_command cargo require_command wasm-bindgen -#require_command wasm-opt +require_command wasm-opt self_path=$(dirname "$(readlink -f "$0")") pname=$(cargo read-manifest | jq -r '.name') diff --git a/tooling/bb_abstraction_leaks/build.rs b/tooling/bb_abstraction_leaks/build.rs index b3dfff9e94c..45da7f9d00c 100644 --- a/tooling/bb_abstraction_leaks/build.rs +++ b/tooling/bb_abstraction_leaks/build.rs @@ -10,7 +10,7 @@ use const_format::formatcp; const USERNAME: &str = "AztecProtocol"; const REPO: &str = "aztec-packages"; -const VERSION: &str = "0.35.1"; +const VERSION: &str = "0.38.0"; const TAG: &str = formatcp!("aztec-packages-v{}", VERSION); const API_URL: &str = diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index c6985f4b037..3368dcd8a09 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "portal:../../../../barretenberg/ts", + "@aztec/bb.js": "0.38.0", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/yarn.lock b/yarn.lock index b45678f5d8b..85966ce3392 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,18 +221,19 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": - version: 0.0.0-use.local - resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" +"@aztec/bb.js@npm:0.38.0": + version: 0.38.0 + resolution: "@aztec/bb.js@npm:0.38.0" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 tslib: ^2.4.0 bin: - bb.js: ./dest/node/main.js + bb.js: dest/node/main.js + checksum: 5ebc2850f37993db1d0fe4306ec612e9df14c5d227e1451f1b2f96e63e61c64225c46b32d1e1d2a1a0c37795e50b2875362520e9eb49324312516ec9fd6de2c7 languageName: node - linkType: soft + linkType: hard "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -4395,7 +4396,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": "portal:../../../../barretenberg/ts" + "@aztec/bb.js": 0.38.0 "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3 From 35e2e6568ebcd98576c090d0f5c970a2d87c7e2a Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 8 May 2024 12:27:43 +0100 Subject: [PATCH 3/4] chore: format --- noir_stdlib/src/aes128.nr | 1 - 1 file changed, 1 deletion(-) diff --git a/noir_stdlib/src/aes128.nr b/noir_stdlib/src/aes128.nr index ac5c2b48ad8..e6e2a5e4997 100644 --- a/noir_stdlib/src/aes128.nr +++ b/noir_stdlib/src/aes128.nr @@ -1,4 +1,3 @@ - #[foreign(aes128_encrypt)] // docs:start:aes128 pub fn aes128_encrypt(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8] {} From 6a8098c269c4befd773493ca98ba0bf3f5ce4be1 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 8 May 2024 12:32:36 +0100 Subject: [PATCH 4/4] chore: format --- .../execution_success/brillig_embedded_curve/src/main.nr | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test_programs/execution_success/brillig_embedded_curve/src/main.nr b/test_programs/execution_success/brillig_embedded_curve/src/main.nr index 1a183bb13d9..8a1a7f08975 100644 --- a/test_programs/execution_success/brillig_embedded_curve/src/main.nr +++ b/test_programs/execution_success/brillig_embedded_curve/src/main.nr @@ -1,10 +1,6 @@ use dep::std; -unconstrained fn main( - priv_key: Field, - pub_x: pub Field, - pub_y: pub Field, -) { +unconstrained fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { let g1_y = 17631683881184975370165255887551781615748388533673675138860; let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: g1_y };