From 5c896b6a128df41e5ea5a35529f2c262221d6b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro=20Sousa?= Date: Mon, 16 Oct 2023 18:33:37 +0100 Subject: [PATCH] chore: adding docs (#3162) Co-authored-by: kevaundray --- .github/actions/docs/build-status/action.yml | 22 + .github/actions/docs/build-status/script.sh | 28 + .github/labeler.yml | 3 - .github/workflows/build-docs.yml | 96 + .github/workflows/labeler.yml | 45 - docs/.gitignore | 23 + docs/.prettierrc | 6 + docs/.yarnrc.yml | 1 + docs/CONTRIBUTING.md | 57 + docs/README.md | 38 + docs/babel.config.js | 3 + docs/docs/examples/merkle-proof.mdx | 48 + .../getting_started/00_nargo_installation.md | 256 + docs/docs/getting_started/01_hello_world.md | 147 + docs/docs/getting_started/02_breakdown.md | 198 + docs/docs/index.md | 99 + docs/docs/language_concepts/01_functions.md | 105 + .../docs/language_concepts/02_control_flow.md | 44 + docs/docs/language_concepts/03_ops.md | 97 + docs/docs/language_concepts/04_assert.md | 26 + .../language_concepts/05_unconstrained.md | 96 + docs/docs/language_concepts/06_generics.md | 113 + docs/docs/language_concepts/07_mutability.md | 92 + docs/docs/language_concepts/08_lambdas.md | 80 + docs/docs/language_concepts/09_comments.md | 32 + docs/docs/language_concepts/10_distinct.md | 63 + docs/docs/language_concepts/11_shadowing.md | 43 + docs/docs/language_concepts/data_types.md | 96 + .../language_concepts/data_types/00_fields.md | 165 + .../data_types/01_integers.md | 33 + .../data_types/02_booleans.md | 30 + .../data_types/03_strings.md | 63 + .../language_concepts/data_types/04_arrays.md | 244 + .../data_types/05_slices.mdx | 146 + .../data_types/06_vectors.mdx | 172 + .../language_concepts/data_types/07_tuples.md | 47 + .../data_types/08_structs.md | 73 + .../data_types/09_references.md | 22 + .../data_types/10_function_types.md | 25 + docs/docs/migration_notes.md | 83 + .../crates_and_packages.md | 42 + .../modules_packages_crates/dependencies.md | 123 + docs/docs/modules_packages_crates/modules.md | 104 + .../modules_packages_crates/workspaces.md | 39 + docs/docs/nargo/01_commands.md | 237 + docs/docs/nargo/02_testing.md | 61 + docs/docs/nargo/03_solidity_verifier.md | 129 + docs/docs/nargo/04_language_server.md | 40 + .../getting_started/01_tiny_noir_app.md | 250 + docs/docs/noir_js/noir_js.md | 22 + docs/docs/noir_js/reference/01_bb_backend.md | 272 + docs/docs/noir_js/reference/02_noirjs.md | 114 + docs/docs/standard_library/black_box_fns.md | 45 + .../cryptographic_primitives.md | 14 + .../cryptographic_primitives/00_hashes.mdx | 146 + .../cryptographic_primitives/01_scalar.mdx | 27 + .../cryptographic_primitives/02_schnorr.mdx | 37 + .../03_ecdsa_sig_verification.mdx | 45 + .../04_ec_primitives.md | 101 + .../cryptographic_primitives/05_eddsa.mdx | 17 + docs/docs/standard_library/logging.md | 62 + docs/docs/standard_library/merkle_trees.md | 58 + docs/docs/standard_library/options.md | 99 + docs/docs/standard_library/recursion.md | 96 + docs/docs/standard_library/zeroed.md | 25 + docs/docusaurus.config.js | 155 + docs/package.json | 42 + docs/sidebars.js | 137 + docs/src/components/GithubCode/index.js | 63 + docs/src/components/HomepageFeatures/index.js | 64 + .../HomepageFeatures/styles.module.css | 11 + docs/src/components/Notes/_blackbox.mdx | 5 + docs/src/components/Notes/_experimental.mdx | 6 + docs/src/css/custom.css | 70 + docs/static/.nojekyll | 0 docs/static/img/codelens_compile_execute.png | Bin 0 -> 5630 bytes docs/static/img/codelens_run_test.png | Bin 0 -> 4627 bytes docs/static/img/codelens_testing_panel.png | Bin 0 -> 18339 bytes docs/static/img/favicon.ico | Bin 0 -> 4286 bytes docs/static/img/logo.svg | 29 + docs/static/img/logoDark.svg | 29 + docs/static/img/noir_getting_started_0.png | Bin 0 -> 72108 bytes docs/static/img/noir_getting_started_1.png | Bin 0 -> 255402 bytes .../version-0.10.5/examples/merkle-proof.mdx | 48 + .../getting_started/00_nargo_installation.md | 285 + .../getting_started/01_hello_world.md | 147 + .../getting_started/02_breakdown.md | 200 + .../getting_started/03_language_server.md | 36 + docs/versioned_docs/version-0.10.5/index.md | 103 + .../language_concepts/01_functions.md | 99 + .../language_concepts/02_control_flow.md | 42 + .../language_concepts/03_ops.md | 97 + .../language_concepts/04_assert.md | 34 + .../language_concepts/05_unconstrained.md | 96 + .../language_concepts/06_generics.md | 113 + .../language_concepts/07_mutability.md | 92 + .../language_concepts/08_lambdas.md | 80 + .../language_concepts/09_comments.md | 32 + .../language_concepts/10_distinct.md | 63 + .../language_concepts/11_shadowing.md | 43 + .../language_concepts/data_types.md | 96 + .../language_concepts/data_types/00_fields.md | 165 + .../data_types/01_integers.md | 33 + .../data_types/02_booleans.md | 30 + .../data_types/03_strings.md | 43 + .../language_concepts/data_types/04_arrays.md | 237 + .../language_concepts/data_types/05_slices.md | 157 + .../data_types/06_vectors.md | 34 + .../language_concepts/data_types/07_tuples.md | 47 + .../data_types/08_structs.md | 73 + .../data_types/09_references.md | 22 + .../data_types/10_function_types.md | 25 + .../crates_and_packages.md | 42 + .../modules_packages_crates/dependencies.md | 123 + .../modules_packages_crates/modules.md | 104 + .../modules_packages_crates/workspaces.md | 39 + .../version-0.10.5/nargo/01_commands.md | 223 + .../version-0.10.5/nargo/02_testing.md | 42 + .../nargo/03_solidity_verifier.md | 129 + .../standard_library/black_box_fns.md | 45 + .../cryptographic_primitives.md | 14 + .../cryptographic_primitives/00_hashes.mdx | 146 + .../cryptographic_primitives/01_scalar.mdx | 33 + .../cryptographic_primitives/02_schnorr.mdx | 37 + .../03_ecdsa_sig_verification.mdx | 45 + .../04_ec_primitives.md | 101 + .../cryptographic_primitives/05_eddsa.mdx | 17 + .../common/_blackbox.mdx | 5 + .../standard_library/logging.md | 62 + .../standard_library/merkle_trees.md | 58 + .../standard_library/options.md | 99 + .../standard_library/recursion.md | 96 + .../version-0.10.5/standard_library/zeroed.md | 25 + .../version-0.10.5/typescript.md | 237 + .../version-0.6.0/examples/merkle-proof.md | 48 + .../getting_started/00_nargo_installation.md | 283 + .../getting_started/01_hello_world.md | 147 + .../getting_started/02_breakdown.md | 103 + docs/versioned_docs/version-0.6.0/index.md | 65 + .../language_concepts/00_data_types.md | 301 + .../language_concepts/01_functions.md | 88 + .../language_concepts/02_control_flow.md | 42 + .../version-0.6.0/language_concepts/03_ops.md | 96 + .../language_concepts/04_assert.md | 34 + .../language_concepts/05_constrain.md | 40 + .../language_concepts/06_generics.md | 116 + .../language_concepts/07_mutability.md | 118 + .../language_concepts/08_comments.md | 27 + .../language_concepts/09_distinct.md | 63 + .../crates_and_packages.md | 35 + .../modules_packages_crates/dependencies.md | 85 + .../modules_packages_crates/modules.md | 104 + .../version-0.6.0/nargo/01_commands.md | 130 + .../version-0.6.0/nargo/02_testing.md | 32 + .../nargo/03_solidity_verifier.md | 116 + .../standard_library/array_methods.md | 180 + .../standard_library/black_box_fns.md | 44 + .../cryptographic_primitives.md | 14 + .../cryptographic_primitives/00_hashes.mdx | 149 + .../cryptographic_primitives/01_scalar.mdx | 33 + .../cryptographic_primitives/02_schnorr.mdx | 37 + .../03_ecdsa_secp256k1.mdx | 25 + .../04_ec_primitives.md | 102 + .../common/_blackbox.mdx | 5 + .../standard_library/field_methods.md | 149 + .../version-0.6.0/standard_library/logging.md | 55 + .../standard_library/merkle_trees.md | 59 + .../version-0.6.0/standard_library/zeroed.md | 25 + .../version-0.6.0/typescript.md | 262 + .../version-0.7.1/examples/merkle-proof.md | 48 + .../getting_started/00_nargo_installation.md | 284 + .../getting_started/01_hello_world.md | 147 + .../getting_started/02_breakdown.md | 122 + .../getting_started/03_language_server.md | 31 + docs/versioned_docs/version-0.7.1/index.md | 103 + .../language_concepts/00_data_types.md | 305 + .../language_concepts/01_functions.md | 88 + .../language_concepts/02_control_flow.md | 42 + .../version-0.7.1/language_concepts/03_ops.md | 97 + .../language_concepts/04_assert.md | 34 + .../language_concepts/06_generics.md | 116 + .../language_concepts/07_mutability.md | 118 + .../language_concepts/08_comments.md | 27 + .../language_concepts/09_distinct.md | 63 + .../crates_and_packages.md | 35 + .../modules_packages_crates/dependencies.md | 110 + .../modules_packages_crates/modules.md | 104 + .../version-0.7.1/nargo/01_commands.md | 132 + .../version-0.7.1/nargo/02_testing.md | 32 + .../nargo/03_solidity_verifier.md | 129 + .../standard_library/array_methods.md | 180 + .../standard_library/black_box_fns.md | 44 + .../cryptographic_primitives.md | 14 + .../cryptographic_primitives/00_hashes.mdx | 146 + .../cryptographic_primitives/01_scalar.mdx | 33 + .../cryptographic_primitives/02_schnorr.mdx | 37 + .../03_ecdsa_secp256k1.mdx | 17 + .../04_ec_primitives.md | 101 + .../cryptographic_primitives/05_eddsa.mdx | 17 + .../common/_blackbox.mdx | 5 + .../standard_library/field_methods.md | 149 + .../version-0.7.1/standard_library/logging.md | 55 + .../standard_library/merkle_trees.md | 59 + .../version-0.7.1/standard_library/zeroed.md | 25 + .../version-0.7.1/typescript.md | 262 + .../version-0.9.0/examples/merkle-proof.mdx | 48 + .../getting_started/00_nargo_installation.md | 285 + .../getting_started/01_hello_world.md | 147 + .../getting_started/02_breakdown.md | 154 + .../getting_started/03_language_server.md | 31 + docs/versioned_docs/version-0.9.0/index.md | 103 + .../language_concepts/00_data_types.md | 405 + .../language_concepts/01_functions.md | 88 + .../language_concepts/02_control_flow.md | 42 + .../version-0.9.0/language_concepts/03_ops.md | 97 + .../language_concepts/04_assert.md | 34 + .../language_concepts/05_unconstrained.md | 96 + .../language_concepts/06_generics.md | 116 + .../language_concepts/07_mutability.md | 120 + .../language_concepts/08_comments.md | 32 + .../language_concepts/09_distinct.md | 63 + .../language_concepts/10_shadowing.md | 43 + .../crates_and_packages.md | 35 + .../modules_packages_crates/dependencies.md | 110 + .../modules_packages_crates/modules.md | 104 + .../version-0.9.0/nargo/01_commands.md | 139 + .../version-0.9.0/nargo/02_testing.md | 32 + .../nargo/03_solidity_verifier.md | 129 + .../standard_library/black_box_fns.md | 45 + .../cryptographic_primitives.md | 14 + .../cryptographic_primitives/00_hashes.mdx | 146 + .../cryptographic_primitives/01_scalar.mdx | 33 + .../cryptographic_primitives/02_schnorr.mdx | 37 + .../03_ecdsa_sig_verification.mdx | 45 + .../04_ec_primitives.md | 101 + .../cryptographic_primitives/05_eddsa.mdx | 17 + .../common/_blackbox.mdx | 5 + .../standard_library/field_methods.md | 149 + .../version-0.9.0/standard_library/logging.md | 42 + .../standard_library/merkle_trees.md | 58 + .../standard_library/recursion.md | 96 + .../standard_library/slice_methods.md | 279 + .../version-0.9.0/standard_library/zeroed.md | 25 + .../version-0.9.0/typescript.md | 243 + .../version-0.10.5-sidebars.json | 111 + .../version-0.6.0-sidebars.json | 90 + .../version-0.7.1-sidebars.json | 90 + .../version-0.9.0-sidebars.json | 91 + docs/versions.json | 6 + package.json | 3 +- yarn.lock | 9509 ++++++++++++++++- 251 files changed, 29939 insertions(+), 442 deletions(-) create mode 100644 .github/actions/docs/build-status/action.yml create mode 100755 .github/actions/docs/build-status/script.sh delete mode 100644 .github/labeler.yml create mode 100644 .github/workflows/build-docs.yml delete mode 100644 .github/workflows/labeler.yml create mode 100644 docs/.gitignore create mode 100644 docs/.prettierrc create mode 100644 docs/.yarnrc.yml create mode 100644 docs/CONTRIBUTING.md create mode 100644 docs/README.md create mode 100644 docs/babel.config.js create mode 100644 docs/docs/examples/merkle-proof.mdx create mode 100644 docs/docs/getting_started/00_nargo_installation.md create mode 100644 docs/docs/getting_started/01_hello_world.md create mode 100644 docs/docs/getting_started/02_breakdown.md create mode 100644 docs/docs/index.md create mode 100644 docs/docs/language_concepts/01_functions.md create mode 100644 docs/docs/language_concepts/02_control_flow.md create mode 100644 docs/docs/language_concepts/03_ops.md create mode 100644 docs/docs/language_concepts/04_assert.md create mode 100644 docs/docs/language_concepts/05_unconstrained.md create mode 100644 docs/docs/language_concepts/06_generics.md create mode 100644 docs/docs/language_concepts/07_mutability.md create mode 100644 docs/docs/language_concepts/08_lambdas.md create mode 100644 docs/docs/language_concepts/09_comments.md create mode 100644 docs/docs/language_concepts/10_distinct.md create mode 100644 docs/docs/language_concepts/11_shadowing.md create mode 100644 docs/docs/language_concepts/data_types.md create mode 100644 docs/docs/language_concepts/data_types/00_fields.md create mode 100644 docs/docs/language_concepts/data_types/01_integers.md create mode 100644 docs/docs/language_concepts/data_types/02_booleans.md create mode 100644 docs/docs/language_concepts/data_types/03_strings.md create mode 100644 docs/docs/language_concepts/data_types/04_arrays.md create mode 100644 docs/docs/language_concepts/data_types/05_slices.mdx create mode 100644 docs/docs/language_concepts/data_types/06_vectors.mdx create mode 100644 docs/docs/language_concepts/data_types/07_tuples.md create mode 100644 docs/docs/language_concepts/data_types/08_structs.md create mode 100644 docs/docs/language_concepts/data_types/09_references.md create mode 100644 docs/docs/language_concepts/data_types/10_function_types.md create mode 100644 docs/docs/migration_notes.md create mode 100644 docs/docs/modules_packages_crates/crates_and_packages.md create mode 100644 docs/docs/modules_packages_crates/dependencies.md create mode 100644 docs/docs/modules_packages_crates/modules.md create mode 100644 docs/docs/modules_packages_crates/workspaces.md create mode 100644 docs/docs/nargo/01_commands.md create mode 100644 docs/docs/nargo/02_testing.md create mode 100644 docs/docs/nargo/03_solidity_verifier.md create mode 100644 docs/docs/nargo/04_language_server.md create mode 100644 docs/docs/noir_js/getting_started/01_tiny_noir_app.md create mode 100644 docs/docs/noir_js/noir_js.md create mode 100644 docs/docs/noir_js/reference/01_bb_backend.md create mode 100644 docs/docs/noir_js/reference/02_noirjs.md create mode 100644 docs/docs/standard_library/black_box_fns.md create mode 100644 docs/docs/standard_library/cryptographic_primitives.md create mode 100644 docs/docs/standard_library/cryptographic_primitives/00_hashes.mdx create mode 100644 docs/docs/standard_library/cryptographic_primitives/01_scalar.mdx create mode 100644 docs/docs/standard_library/cryptographic_primitives/02_schnorr.mdx create mode 100644 docs/docs/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx create mode 100644 docs/docs/standard_library/cryptographic_primitives/04_ec_primitives.md create mode 100644 docs/docs/standard_library/cryptographic_primitives/05_eddsa.mdx create mode 100644 docs/docs/standard_library/logging.md create mode 100644 docs/docs/standard_library/merkle_trees.md create mode 100644 docs/docs/standard_library/options.md create mode 100644 docs/docs/standard_library/recursion.md create mode 100644 docs/docs/standard_library/zeroed.md create mode 100644 docs/docusaurus.config.js create mode 100644 docs/package.json create mode 100644 docs/sidebars.js create mode 100644 docs/src/components/GithubCode/index.js create mode 100644 docs/src/components/HomepageFeatures/index.js create mode 100644 docs/src/components/HomepageFeatures/styles.module.css create mode 100644 docs/src/components/Notes/_blackbox.mdx create mode 100644 docs/src/components/Notes/_experimental.mdx create mode 100644 docs/src/css/custom.css create mode 100644 docs/static/.nojekyll create mode 100644 docs/static/img/codelens_compile_execute.png create mode 100644 docs/static/img/codelens_run_test.png create mode 100644 docs/static/img/codelens_testing_panel.png create mode 100644 docs/static/img/favicon.ico create mode 100644 docs/static/img/logo.svg create mode 100644 docs/static/img/logoDark.svg create mode 100644 docs/static/img/noir_getting_started_0.png create mode 100644 docs/static/img/noir_getting_started_1.png create mode 100644 docs/versioned_docs/version-0.10.5/examples/merkle-proof.mdx create mode 100644 docs/versioned_docs/version-0.10.5/getting_started/00_nargo_installation.md create mode 100644 docs/versioned_docs/version-0.10.5/getting_started/01_hello_world.md create mode 100644 docs/versioned_docs/version-0.10.5/getting_started/02_breakdown.md create mode 100644 docs/versioned_docs/version-0.10.5/getting_started/03_language_server.md create mode 100644 docs/versioned_docs/version-0.10.5/index.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/01_functions.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/02_control_flow.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/03_ops.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/04_assert.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/05_unconstrained.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/06_generics.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/07_mutability.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/08_lambdas.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/09_comments.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/10_distinct.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/11_shadowing.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/00_fields.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/01_integers.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/02_booleans.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/03_strings.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/04_arrays.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/05_slices.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/06_vectors.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/07_tuples.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/08_structs.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/09_references.md create mode 100644 docs/versioned_docs/version-0.10.5/language_concepts/data_types/10_function_types.md create mode 100644 docs/versioned_docs/version-0.10.5/modules_packages_crates/crates_and_packages.md create mode 100644 docs/versioned_docs/version-0.10.5/modules_packages_crates/dependencies.md create mode 100644 docs/versioned_docs/version-0.10.5/modules_packages_crates/modules.md create mode 100644 docs/versioned_docs/version-0.10.5/modules_packages_crates/workspaces.md create mode 100644 docs/versioned_docs/version-0.10.5/nargo/01_commands.md create mode 100644 docs/versioned_docs/version-0.10.5/nargo/02_testing.md create mode 100644 docs/versioned_docs/version-0.10.5/nargo/03_solidity_verifier.md create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/black_box_fns.md create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives.md create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/00_hashes.mdx create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/01_scalar.mdx create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/02_schnorr.mdx create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/04_ec_primitives.md create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/05_eddsa.mdx create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/common/_blackbox.mdx create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/logging.md create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/merkle_trees.md create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/options.md create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/recursion.md create mode 100644 docs/versioned_docs/version-0.10.5/standard_library/zeroed.md create mode 100644 docs/versioned_docs/version-0.10.5/typescript.md create mode 100644 docs/versioned_docs/version-0.6.0/examples/merkle-proof.md create mode 100644 docs/versioned_docs/version-0.6.0/getting_started/00_nargo_installation.md create mode 100644 docs/versioned_docs/version-0.6.0/getting_started/01_hello_world.md create mode 100644 docs/versioned_docs/version-0.6.0/getting_started/02_breakdown.md create mode 100644 docs/versioned_docs/version-0.6.0/index.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/00_data_types.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/01_functions.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/02_control_flow.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/03_ops.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/04_assert.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/05_constrain.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/06_generics.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/07_mutability.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/08_comments.md create mode 100644 docs/versioned_docs/version-0.6.0/language_concepts/09_distinct.md create mode 100644 docs/versioned_docs/version-0.6.0/modules_packages_crates/crates_and_packages.md create mode 100644 docs/versioned_docs/version-0.6.0/modules_packages_crates/dependencies.md create mode 100644 docs/versioned_docs/version-0.6.0/modules_packages_crates/modules.md create mode 100644 docs/versioned_docs/version-0.6.0/nargo/01_commands.md create mode 100644 docs/versioned_docs/version-0.6.0/nargo/02_testing.md create mode 100644 docs/versioned_docs/version-0.6.0/nargo/03_solidity_verifier.md create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/array_methods.md create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/black_box_fns.md create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives.md create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/00_hashes.mdx create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/01_scalar.mdx create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/02_schnorr.mdx create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/04_ec_primitives.md create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/common/_blackbox.mdx create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/field_methods.md create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/logging.md create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/merkle_trees.md create mode 100644 docs/versioned_docs/version-0.6.0/standard_library/zeroed.md create mode 100644 docs/versioned_docs/version-0.6.0/typescript.md create mode 100644 docs/versioned_docs/version-0.7.1/examples/merkle-proof.md create mode 100644 docs/versioned_docs/version-0.7.1/getting_started/00_nargo_installation.md create mode 100644 docs/versioned_docs/version-0.7.1/getting_started/01_hello_world.md create mode 100644 docs/versioned_docs/version-0.7.1/getting_started/02_breakdown.md create mode 100644 docs/versioned_docs/version-0.7.1/getting_started/03_language_server.md create mode 100644 docs/versioned_docs/version-0.7.1/index.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/00_data_types.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/01_functions.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/02_control_flow.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/03_ops.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/04_assert.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/06_generics.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/07_mutability.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/08_comments.md create mode 100644 docs/versioned_docs/version-0.7.1/language_concepts/09_distinct.md create mode 100644 docs/versioned_docs/version-0.7.1/modules_packages_crates/crates_and_packages.md create mode 100644 docs/versioned_docs/version-0.7.1/modules_packages_crates/dependencies.md create mode 100644 docs/versioned_docs/version-0.7.1/modules_packages_crates/modules.md create mode 100644 docs/versioned_docs/version-0.7.1/nargo/01_commands.md create mode 100644 docs/versioned_docs/version-0.7.1/nargo/02_testing.md create mode 100644 docs/versioned_docs/version-0.7.1/nargo/03_solidity_verifier.md create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/array_methods.md create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/black_box_fns.md create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives.md create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/00_hashes.mdx create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/01_scalar.mdx create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/02_schnorr.mdx create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/04_ec_primitives.md create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/05_eddsa.mdx create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/common/_blackbox.mdx create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/field_methods.md create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/logging.md create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/merkle_trees.md create mode 100644 docs/versioned_docs/version-0.7.1/standard_library/zeroed.md create mode 100644 docs/versioned_docs/version-0.7.1/typescript.md create mode 100644 docs/versioned_docs/version-0.9.0/examples/merkle-proof.mdx create mode 100644 docs/versioned_docs/version-0.9.0/getting_started/00_nargo_installation.md create mode 100644 docs/versioned_docs/version-0.9.0/getting_started/01_hello_world.md create mode 100644 docs/versioned_docs/version-0.9.0/getting_started/02_breakdown.md create mode 100644 docs/versioned_docs/version-0.9.0/getting_started/03_language_server.md create mode 100644 docs/versioned_docs/version-0.9.0/index.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/00_data_types.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/01_functions.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/02_control_flow.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/03_ops.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/04_assert.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/05_unconstrained.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/06_generics.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/07_mutability.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/08_comments.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/09_distinct.md create mode 100644 docs/versioned_docs/version-0.9.0/language_concepts/10_shadowing.md create mode 100644 docs/versioned_docs/version-0.9.0/modules_packages_crates/crates_and_packages.md create mode 100644 docs/versioned_docs/version-0.9.0/modules_packages_crates/dependencies.md create mode 100644 docs/versioned_docs/version-0.9.0/modules_packages_crates/modules.md create mode 100644 docs/versioned_docs/version-0.9.0/nargo/01_commands.md create mode 100644 docs/versioned_docs/version-0.9.0/nargo/02_testing.md create mode 100644 docs/versioned_docs/version-0.9.0/nargo/03_solidity_verifier.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/black_box_fns.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/00_hashes.mdx create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/01_scalar.mdx create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/02_schnorr.mdx create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/04_ec_primitives.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/05_eddsa.mdx create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/common/_blackbox.mdx create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/field_methods.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/logging.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/merkle_trees.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/recursion.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/slice_methods.md create mode 100644 docs/versioned_docs/version-0.9.0/standard_library/zeroed.md create mode 100644 docs/versioned_docs/version-0.9.0/typescript.md create mode 100644 docs/versioned_sidebars/version-0.10.5-sidebars.json create mode 100644 docs/versioned_sidebars/version-0.6.0-sidebars.json create mode 100644 docs/versioned_sidebars/version-0.7.1-sidebars.json create mode 100644 docs/versioned_sidebars/version-0.9.0-sidebars.json create mode 100644 docs/versions.json diff --git a/.github/actions/docs/build-status/action.yml b/.github/actions/docs/build-status/action.yml new file mode 100644 index 00000000000..8206dd64776 --- /dev/null +++ b/.github/actions/docs/build-status/action.yml @@ -0,0 +1,22 @@ +name: 'Get build status' +description: 'Gets the build status of a Netlify site' +inputs: + branch-name: + description: 'Branch name' + required: true + site-id: + description: Netlify site id + required: true +outputs: + deploy_status: + description: "The deploy status" + value: ${{ steps.check_deploy_status.outputs.deploy_status }} +runs: + using: "composite" + steps: + - run: ${{ github.action_path }}/script.sh + shell: bash + id: check_deploy_status + env: + BRANCH_NAME: ${{ inputs.branch-name }} + SITE_ID: ${{ inputs.site-id }} diff --git a/.github/actions/docs/build-status/script.sh b/.github/actions/docs/build-status/script.sh new file mode 100755 index 00000000000..a8d31ff4f4b --- /dev/null +++ b/.github/actions/docs/build-status/script.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +BRANCH_NAME=$(echo "$BRANCH_NAME" | sed -e "s#refs/[^/]*/##") +DEPLOY_STATUS=$(curl -X GET "https://api.netlify.com/api/v1/sites/$SITE_ID/deploys?branch=$BRANCH_NAME" | jq -r '.[] | select(.created_at != null) | .state' | head -1) + +echo "$SITE_ID" +MAX_RETRIES=10 +COUNT=0 +while [[ "$DEPLOY_STATUS" != "ready" && $COUNT -lt $MAX_RETRIES ]]; do + sleep 20 + DEPLOY_STATUS=$(curl -X GET "https://api.netlify.com/api/v1/sites/$SITE_ID/deploys?branch=$BRANCH_NAME" | jq -r '.[] | select(.created_at != null) | .state' | head -1) + COUNT=$((COUNT+1)) + + echo "Deploy status: $DEPLOY_STATUS" + # If deploy status is ready, set the output and exit successfully + if [[ "$DEPLOY_STATUS" == "ready" ]]; then + echo "deploy_status=success" >> $GITHUB_OUTPUT + exit 0 + elif [[ "$DEPLOY_STATUS" == "error" ]]; then + echo "deploy_status=failure" >> $GITHUB_OUTPUT + exit 0 + fi + + echo "Deploy still running. Retrying..." +done + +echo "deploy_status=failure" >> $GITHUB_OUTPUT +exit 0 diff --git a/.github/labeler.yml b/.github/labeler.yml deleted file mode 100644 index dea78c8fb32..00000000000 --- a/.github/labeler.yml +++ /dev/null @@ -1,3 +0,0 @@ -# Add/remove 'doc needed' label if issue/PR contains the line '- [x] This PR requires documentation updates when merged.' -"doc needed": - - '- \[(x|X)\] This PR requires documentation updates when merged.' diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml new file mode 100644 index 00000000000..a387f6f49f9 --- /dev/null +++ b/.github/workflows/build-docs.yml @@ -0,0 +1,96 @@ +name: Build docs + +on: + pull_request: + paths: + - 'docs/**' + types: + - opened + - synchronize + - labeled + push: + paths: + - 'docs/**' + +jobs: + + build_and_deploy: + runs-on: ubuntu-latest + permissions: + pull-requests: write + if: contains(github.event.pull_request.labels.*.name, 'documentation') + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Netlify deploy + run: | + BRANCH_NAME=$(echo "${{ github.head_ref || github.ref }}" | sed -e "s#refs/[^/]*/##") + curl -X POST -d {} "https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_BUILD_HOOK }}?trigger_branch=$BRANCH_NAME" + - name: Get deploy preview + id: get_deploy_preview + run: | + BRANCH_NAME=$(echo "${{ github.head_ref || github.ref }}" | sed -e "s#refs/[^/]*/##") + curl -X GET "https://api.netlify.com/api/v1/sites/${{ secrets.NETLIFY_SITE_ID }}/deploys?branch=$BRANCH_NAME" > deploy.json + echo "::set-output name=deploy_url::$(cat deploy.json | jq -r '.[0].deploy_ssl_url')" + + - name: Add PR Comment + uses: mshick/add-pr-comment@v2 + with: + message: | + Hey @${{ github.event.pull_request.user.login }}! πŸ™Œ + + I'm the deployment bot for Noir Docs, and I've got some updates for you: + + ## Deployment Status + Your latest changes are being deployed for preview! πŸš€ + + Click the badge to see logs 🧐 + + [![Netlify Status](https://api.netlify.com/api/v1/badges/${{ secrets.NETLIFY_SITE_ID }}/deploy-status?branch=${{ github.head_ref || github.ref }})](https://app.netlify.com/sites/noir-docs-v2/deploys) + + If you have any questions about this process, refer to our contribution guide or feel free to ask around. + + + - name: Check on deploy status + uses: ./.github/actions/docs/build-status + id: check_deploy_status + with: + branch-name: ${{ github.head_ref || github.ref }} + site-id: ${{ secrets.NETLIFY_SITE_ID }} + continue-on-error: true + + - name: Debugging - print deploy_status + run: echo "${{ steps.check_deploy_status.outputs.deploy_status }}" + + - name: Change PR Comment for Successful Deployment + if: steps.check_deploy_status.outputs.deploy_status == 'success' + uses: mshick/add-pr-comment@v2 + with: + message-success: | + ![It's Alive!](https://i.imgflip.com/82hw5n.jpg) + + I'm a bot, beep boop πŸ€– + + ## Deployment Status: Success! + [![Netlify Status](https://api.netlify.com/api/v1/badges/${{ secrets.NETLIFY_SITE_ID }}/deploy-status?branch=${{ github.head_ref || github.ref }})](https://app.netlify.com/sites/noir-docs-v2/deploys) + + ## Preview + + 🌐 [View Deployment Preview](${{ steps.get_deploy_preview.outputs.deploy_url }}) + + + + - name: Change PR Comment for Failed Deployment + if: steps.check_deploy_status.outputs.deploy_status == 'failure' + uses: mshick/add-pr-comment@v2 + with: + message: | + ![docs CI troll](https://i.imgflip.com/82ht8f.jpg) + + I'm a bot, beep boop πŸ€– + + ## Deployment Status: Failed ❌ + Deployment didn't succeed. Please check logs below and resolve the issue 🧐 + + [![Netlify Status](https://api.netlify.com/api/v1/badges/${{ secrets.NETLIFY_SITE_ID }}/deploy-status?branch=${{ github.head_ref || github.ref }})](https://app.netlify.com/sites/noir-docs-v2/deploys) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml deleted file mode 100644 index 8a2c3d2100a..00000000000 --- a/.github/workflows/labeler.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: "Labeler" -on: - pull_request_target: - types: - - opened - - reopened - - edited - -permissions: - pull-requests: write - contents: read - -jobs: - triage: - runs-on: ubuntu-latest - steps: - - name: Label pull request - # We can switch hash to release number once it is tagged - uses: github/issue-labeler@6ae80f5cf189fd96d96a4a4125c60e87cba0578d - id: issue-labeler - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - configuration-path: .github/labeler.yml - enable-versioned-regex: 0 - sync-labels: 1 - - - name: Create documentation issue - if: ${{ steps.issue-labeler.outputs.labels-added }} - uses: benc-uk/workflow-dispatch@v1 - with: - workflow: new-migrated-issue.yml - repo: noir-lang/docs - ref: master - token: ${{ secrets.DOCS_REPO_TOKEN }} - inputs: '{ "pr-number": "${{ github.event.pull_request.number }}" }' - - - name: Close documentation issue - if: ${{ steps.issue-labeler.outputs.labels-removed }} - uses: benc-uk/workflow-dispatch@v1 - with: - workflow: delete-migrated-issue.yml - repo: noir-lang/docs - ref: master - token: ${{ secrets.DOCS_REPO_TOKEN }} - inputs: '{ "pr-number": "${{ github.event.pull_request.number }}" }' diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000000..96ecf9cbc03 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,23 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +.yarn + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +package-lock.json diff --git a/docs/.prettierrc b/docs/.prettierrc new file mode 100644 index 00000000000..6031f40b267 --- /dev/null +++ b/docs/.prettierrc @@ -0,0 +1,6 @@ +{ + "arrowParens": "avoid", + "singleQuote": true, + "trailingComma": "all", + "printWidth": 100 +} diff --git a/docs/.yarnrc.yml b/docs/.yarnrc.yml new file mode 100644 index 00000000000..3186f3f0795 --- /dev/null +++ b/docs/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 00000000000..2b1f293fd64 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,57 @@ +# Contributing to Noir + +Thank you for your interest in contributing to Noir documentation! We value your contributions in making Noir better. + +This guide will discuss how the Noir team handles [Commits](#commits), [Pull Requests](#pull-requests), [Merging](#merging), and [Versioning](#versioning). + +__Note:__ We won't force external contributors to follow this verbatim, but following these guidelines definitely helps us in accepting your contributions. + +## Commits + +We want to keep our commits small and focused. This allows for easily reviewing individual commits and/or splitting up pull requests when they grow too big. Additionally, this allows us to merge smaller changes quicker and release more often. + +When committing, it's often useful to use the `git add -p` workflow to decide on what parts of the changeset to stage for commit. + +We don't currently enforce any commit standard, however that may change at any time. Mind that the [Noir](https://github.com/noir-lang/noir) repo does enforce the [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) standard. + +## Pull Requests + +Before you create a pull request, search for any issues related to the change you are making. If none exist already, create an issue that thoroughly describes the problem that you are trying to solve. These are used to inform reviewers of the original intent and should be referenced via the pull request template. + +Pull Requests should be focused on the specific change they are working towards. If prerequisite work is required to complete the original pull request, that work should be submitted as a separate pull request. + +This strategy avoids scenarios where pull requests grow too large/out-of-scope and don't get proper reviewsβ€”we want to avoid "LGTM, I trust you" reviews. + +The easiest way to do this is to have multiple commits while you work and then you can cherry-pick the smaller changes into separate branches for pull requesting. + +### Reviews + +For any repository in the noir-lang organization, we require code review & approval by __one__ Noir team member before the changes are merged. However, while the docs repository is still getting up-to-speed with the current Noir fetures, we do allow for non-breaking pull requests to be merged at any time. Breaking pull requests should only be merged when the team has general agreement of the changes. + +The CI/CD workflow at Netlify should provide you with a preview of the website once merged. Use this preview to thoroughly test the changes before requesting reviews or merging. + +## Merging + +Once approved by the required number of team members, the pull request can be merged into the `master` branch. Sometimes, especially for external contributions, the final approver may merge the pull request instead of the submitter. + +### Merge Checklist + +Before merging, you should mentally review these questions: + +- Is continuous integration passing? +- Do you have the required amount of approvals? +- Does anyone else need to be pinged for thoughts? + +## Versioning + +The Noir documentation is versioned according to the [Docusaurus documentation](https://docusaurus.io/docs/versioning). In the `versioned_docs` and `versioned_sidebar` folders you will find the docs and configs for the previous versions. If any change needs to be made to older versions, please do it in this folder. + +In the `docs` folder, you'll find the current, unreleased version, which we call `dev`. Any change in this folder will be reflected in the next version, once the Noir team decides to release. + +We aim to have every version matching the versions of [Noir](https://github.com/noir-lang/noir). However, we would only cut a new version of the docs if there are breaking or otherwise significant changes, to avoid unecessary build time and size to the existent documentation. + +While the versioning is intended to be managed by the core maintainers, we feel it's important for external contributors to understand why and how is it maintained. To bump to a new version, run the following command, replacing with the intended version: + +`npm run 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`. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..21c6b7f7ad6 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,38 @@ +# Noir Docs + +This is the source code for the Noir documentation site at [noir-lang.org](https://noir-lang.org). + +This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website +generator. + +## Contributing + +Interested in contributing to the docs? + +Check out the contributing guide [here](./CONTRIBUTING.md). + +## Development + +### Installation + +``` +$ yarn +``` + +### Local Development + +``` +$ yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are +reflected live without having to restart the server. + +### Build + +``` +$ yarn build +``` + +This command generates static content into the `build` directory and can be served using any static +contents hosting service. diff --git a/docs/babel.config.js b/docs/babel.config.js new file mode 100644 index 00000000000..e00595dae7d --- /dev/null +++ b/docs/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/docs/docs/examples/merkle-proof.mdx b/docs/docs/examples/merkle-proof.mdx new file mode 100644 index 00000000000..6430780817c --- /dev/null +++ b/docs/docs/examples/merkle-proof.mdx @@ -0,0 +1,48 @@ +--- +title: Merkle Proof 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] +--- + +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); + 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` +instead. + +```rust +let leaf = std::hash::hash_to_field(message); +``` + +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/docs/getting_started/00_nargo_installation.md b/docs/docs/getting_started/00_nargo_installation.md new file mode 100644 index 00000000000..26a665a0d51 --- /dev/null +++ b/docs/docs/getting_started/00_nargo_installation.md @@ -0,0 +1,256 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, + verifying and more). Learn how to install and use Nargo for your projects with this comprehensive + guide. +keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] +--- + +`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, +verifying and more). + +Alternatively, the interactions can also be performed in [NoirJS](../noir_js/noir_js.md). + +### UltraPlonk + +Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. + +## Installation + +There are four approaches for installing Nargo: + +- [Option 1: Noirup](#option-1-noirup) +- [Option 2: Binaries](#option-2-binaries) +- [Option 3: Install via Nix](#option-3-install-via-nix) +- [Option 4: Compile from Source](#option-4-compile-from-source) + +Optionally you can also install [Noir VS Code extension] for syntax highlighting. + +### Option 1: Noirup + +If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a +terminal and run: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done, 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. + +#### GitHub Actions + +You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as +installing `noirup` and running tests in your GitHub Action `yml` file. + +See the +[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in +this repo containing hash functions in Noir for an example. + +#### Nightly versions + +To install the nightly version of Noir (updated daily) run: + +```bash +noirup -n +``` + +### Option 2: Binaries + +See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous +platform specific binaries. + +#### Step 1 + +Paste and run the following in the terminal to extract and install the binary: + +> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend +> `sudo` and re-run it. + +##### macOS (Apple Silicon) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### macOS (Intel) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### Windows (PowerShell) + +Open PowerShell as Administrator and run: + +```powershell +mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` +Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` +Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` +$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` +$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` +$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` +Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +``` + +##### Linux (Bash) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ +echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ +source ~/.bashrc +``` + +#### Step 2 + +Check if the installation was successful by running `nargo --help`. + +> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from +> Finder. Close the new terminal popped up and `nargo` should now be accessible. + +For a successful installation, you should see something similar to the following after running the +command: + +```sh +$ nargo --help + +Noir's package manager + +Usage: nargo + +Commands: + check Checks the constraint system for errors + 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 new binary project + 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 + gates Counts the occurrences of different gates in circuit + help Print this message or the help of the given subcommand(s) +``` + +### Option 3: Compile from Source + +Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. It helps mitigating ssues commonly associated with dependency management, such as conflicts between required package versions for different projects (often referred to as "dependency hell"). + +Combined with direnv, which automatically sets or unsets environment variables based on the directory, it further simplifies the development process by seamlessly integrating with the developer's shell, facilitating an efficient and reliable workflow for managing and deploying Noir projects with multiple dependencies. + +#### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +3. Install direnv into your Nix profile by running: + +```sh +nix profile install nixpkgs#direnv +``` + +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). + 1. For bash or zshell, add `eval "$(direnv hook bash)"` or `eval "$(direnv hook zsh)"` to your ~/.bashrc or ~/.zshrc file, respectively. +5. Restart your shell. + +#### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: + +```sh +git clone git@github.com:noir-lang/noir +``` + +> Replacing `noir` with whichever repository you want to work on. + +2. Navigate to the directory: + +```sh +cd noir +``` + +> Replacing `noir` with whichever repository you cloned. + +3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: + +```sh +direnv allow +``` + +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. + +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): + +```sh +code . +``` + +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +#### Building and testing + +Assuming you are using `direnv` to populate your environment, building and testing the project can be done +with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. + +If you want to build the entire project in an isolated sandbox, you can use Nix commands: + +1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. +2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. + +#### Without `direnv` + +If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. + +Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! + +## Uninstalling Nargo + +### Noirup + +If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` + +### Nix + +If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. + +```bash +rm ~/.nix-profile/bin/nargo +``` + +[noir vs code extension]: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir diff --git a/docs/docs/getting_started/01_hello_world.md b/docs/docs/getting_started/01_hello_world.md new file mode 100644 index 00000000000..8b4416beba1 --- /dev/null +++ b/docs/docs/getting_started/01_hello_world.md @@ -0,0 +1,147 @@ +--- +title: Create 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, + ] +--- + +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 +``` + +For Windows CMD, run: + +```sh +> mkdir "%USERPROFILE%\projects" +> cd /d "%USERPROFILE%\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_ that contains 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](../language_concepts/data_types) 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](../language_concepts/comments) 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 on 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](breakdown), we will go into more detail on each step performed. diff --git a/docs/docs/getting_started/02_breakdown.md b/docs/docs/getting_started/02_breakdown.md new file mode 100644 index 00000000000..bc0e742fb4e --- /dev/null +++ b/docs/docs/getting_started/02_breakdown.md @@ -0,0 +1,198 @@ +--- +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] +--- + +This section breaks down our hello world program in section _1.2_. We elaborate on the project +structure and what the `prove` and `verify` commands did in the previous section. + +## 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 = "noirstarter" +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](../modules_packages_crates/workspaces) will look a bit different. For example: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +#### Package section + +The package section requires 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` (optional) - specifies the version of the compiler to use. This is not currently enforced by the compiler, but will be in future versions. +- `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](../modules_packages_crates/dependencies) 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 the satisfaction of the condition (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 not equal 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 from usually external sources and +verifies the validity of the proof against it. + +Take a private asset transfer as an example: + +A user on browser as the prover would retrieve private inputs (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/docs/index.md b/docs/docs/index.md new file mode 100644 index 00000000000..9ebe1d54944 --- /dev/null +++ b/docs/docs/index.md @@ -0,0 +1,99 @@ +--- +title: Introducing Noir +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, + ] +slug: / +--- + +## What is Noir? + +Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. + +It's design choices are influenced heavily by Rust and focuses on a simple, familiar syntax. + +## Who is Noir for? + +Noir can be used for a variety of purposes. + +### Solidity Developers + +Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will +be modularised in the future; however, as of the alpha, you can use the [`nargo codegen-verifier`](./nargo/commands#nargo-codegen-verifier) command to create +a verifier contract. + +### Protocol Developers + +As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for +your stack, or maybe you simply want to use a different proving system. Since Noir does not compile +to a specific proof system, it is possible for protocol developers to replace the PLONK-based +proving system with a different proving system altogether. + +### Blockchain developers + +As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the +proving system and smart contract language has been pre-defined). In order for you to use Noir in +your blockchain, a proving system backend and a smart contract interface +must be implemented for it. + +## What's new about Noir? + +Noir is simple and flexible in its design, as it does not compile immediately to a fixed +NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled +to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). + +This in itself brings up a few challenges within the design process, but allows one to decouple the programming language completely from the backend. This is similar in theory to LLVM. + +## Current Features + +Compiler: + +- Module System +- For expressions +- Arrays +- Bit Operations +- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Unsigned integers +- If statements +- Structures and Tuples +- Generics + +ACIR Supported OPCODES: + +- Sha256 +- Blake2s +- Schnorr signature verification +- MerkleMembership +- Pedersen +- HashToField + +## 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 + +See the section on [dependencies](./modules_packages_crates/dependencies) for more information. diff --git a/docs/docs/language_concepts/01_functions.md b/docs/docs/language_concepts/01_functions.md new file mode 100644 index 00000000000..2b5f29aac35 --- /dev/null +++ b/docs/docs/language_concepts/01_functions.md @@ -0,0 +1,105 @@ +--- +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] +--- + +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() {} +``` + +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 : pub 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 : pub Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## 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); +``` + +## 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](./08_lambdas.md) for more details. diff --git a/docs/docs/language_concepts/02_control_flow.md b/docs/docs/language_concepts/02_control_flow.md new file mode 100644 index 00000000000..a7f85360197 --- /dev/null +++ b/docs/docs/language_concepts/02_control_flow.md @@ -0,0 +1,44 @@ +--- +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] +--- + +## 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`. + +## 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); +``` diff --git a/docs/docs/language_concepts/03_ops.md b/docs/docs/language_concepts/03_ops.md new file mode 100644 index 00000000000..da02b126059 --- /dev/null +++ b/docs/docs/language_concepts/03_ops.md @@ -0,0 +1,97 @@ +--- +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, + ] +--- + +# 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 indentically 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/docs/language_concepts/04_assert.md b/docs/docs/language_concepts/04_assert.md new file mode 100644 index 00000000000..7427ec6cc63 --- /dev/null +++ b/docs/docs/language_concepts/04_assert.md @@ -0,0 +1,26 @@ +--- +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] +--- + +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); +} +``` + +You can optionally provide a message to be logged when the assertion fails: + +```rust +assert(x == y, "x and y are not equal"); +``` + +> 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`. diff --git a/docs/docs/language_concepts/05_unconstrained.md b/docs/docs/language_concepts/05_unconstrained.md new file mode 100644 index 00000000000..6b621eda3eb --- /dev/null +++ b/docs/docs/language_concepts/05_unconstrained.md @@ -0,0 +1,96 @@ +--- +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] +--- + + + +Unconstrained functions are functions which do not constrain any of the included computation and allow for non-determinisitic 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 XOR 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. diff --git a/docs/docs/language_concepts/06_generics.md b/docs/docs/language_concepts/06_generics.md new file mode 100644 index 00000000000..b700bd5bc5b --- /dev/null +++ b/docs/docs/language_concepts/06_generics.md @@ -0,0 +1,113 @@ +--- +title: Generics +description: Learn how to use Generics in Noir +keywords: [Noir, Rust, generics, functions, structs] +--- + +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 new(value: T) -> Self { + Self { value, count: 1 } + } + + fn increment(mut repeated: Self) -> Self { + repeated.count += 1; + repeated + } + + fn print(self) { + for _i in 0 .. self.count { + dep::std::println(self.value); + } + } +} + +fn main() { + let mut repeated = RepeatedValue::new("Hello!"); + repeated = repeated.increment(); + 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 + +Unlike Rust, Noir does not have traits, so how can one translate the equivalent of a trait bound in +Rust into Noir? That is, how can we write a function that is generic over some type `T`, while also +requiring there is a function like `eq: fn(T, T) -> bool` that works on the type? + +The answer is that we can translate this by passing in the function manually. Here's an example of +implementing array equality in Noir: + +```rust +fn array_eq(array1: [T; N], array2: [T; N], elem_eq: fn(T, T) -> bool) -> bool { + if array1.len() != array2.len() { + false + } else { + let mut result = true; + for i in 0 .. array1.len() { + result &= elem_eq(array1[i], array2[i]); + } + result + } +} + +fn main() { + assert(array_eq([1, 2, 3], [1, 2, 3], |a, b| a == b)); + + // We can use array_eq even for arrays of structs, as long as we have + // an equality function for these structs we can pass in + let array = [MyStruct::new(), MyStruct::new()]; + assert(array_eq(array, array, MyStruct::eq)); +} +``` + +You can see an example of generics in the tests +[here](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/generics/src/main.nr). diff --git a/docs/docs/language_concepts/07_mutability.md b/docs/docs/language_concepts/07_mutability.md new file mode 100644 index 00000000000..4641521b1d9 --- /dev/null +++ b/docs/docs/language_concepts/07_mutability.md @@ -0,0 +1,92 @@ +--- +title: Mutability +description: + Learn about mutable variables, constants, and globals in Noir programming language. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +--- + +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() -> Field { + let x = 3; + helper(x); + x // x is still 3 +} + +fn helper(mut x: i32) { + x = 4; +} +``` + +## Comptime Values + +:::warning + +The 'comptime' keyword was removed in version 0.10. The comptime keyword and syntax are currently still kept and parsed for backwards compatibility, but are now deprecated and will issue a warning when used. `comptime` has been removed because it is no longer needed for accessing arrays. + +::: + +## Globals + +Noir also supports global variables. However, they must be known at compile-time. The global type can also be inferred by the compiler entirely. Globals can also be used to specify array +annotations for function parameters and can be imported from submodules. + +```rust +global N: Field = 5; // Same as `global N: Field = 5` + +fn main(x : Field, y : [Field; N]) { + let res = x * N; + + assert(res == y[0]); + + let res2 = x * mysubmodule::N; + assert(res != res2); +} + +mod mysubmodule { + use dep::std; + + global N: Field = 10; + + fn my_helper() -> Field { + let x = N; + x + } +} +``` + +## Why only local mutability? + +Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting +without applying additional overhead to the user. Modeling a mutable reference is not as +straightforward as on conventional architectures and would incur some possibly unexpected overhead. diff --git a/docs/docs/language_concepts/08_lambdas.md b/docs/docs/language_concepts/08_lambdas.md new file mode 100644 index 00000000000..ae1e6aecab1 --- /dev/null +++ b/docs/docs/language_concepts/08_lambdas.md @@ -0,0 +1,80 @@ +--- +title: Lambdas +description: Learn how to use anonymous functions in Noir programming language. +keywords: [Noir programming language, lambda, closure, function, anonymous function] +--- + +## 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/docs/language_concepts/09_comments.md b/docs/docs/language_concepts/09_comments.md new file mode 100644 index 00000000000..3bb4d2f25a4 --- /dev/null +++ b/docs/docs/language_concepts/09_comments.md @@ -0,0 +1,32 @@ +--- +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] +--- + +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/docs/language_concepts/10_distinct.md b/docs/docs/language_concepts/10_distinct.md new file mode 100644 index 00000000000..e7ff7f5017a --- /dev/null +++ b/docs/docs/language_concepts/10_distinct.md @@ -0,0 +1,63 @@ +--- +title: Distinct Witnesses +--- + +The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures +that the witnesses being returned as public inputs are all unique. + +The `distinct` keyword is only used for return values on program entry points (usually the `main()` +function). + +When using `distinct` and `pub` simultaneously, `distinct` comes first. See the example below. + +You can read more about the problem this solves +[here](https://github.com/noir-lang/noir/issues/1183). + +## Example + +Without the `distinct` keyword, the following program + +```rust +fn main(x : pub Field, y : pub Field) -> pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + "return_witnesses": [3, 2, 4, 4] + } +} +``` + +Whereas (with the `distinct` keyword) + +```rust +fn main(x : pub Field, y : pub Field) -> distinct pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + //... + "return_witnesses": [3, 4, 5, 6] + } +} +``` diff --git a/docs/docs/language_concepts/11_shadowing.md b/docs/docs/language_concepts/11_shadowing.md new file mode 100644 index 00000000000..efd743e764f --- /dev/null +++ b/docs/docs/language_concepts/11_shadowing.md @@ -0,0 +1,43 @@ +--- +title: Shadowing +--- + +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/docs/language_concepts/data_types.md b/docs/docs/language_concepts/data_types.md new file mode 100644 index 00000000000..d546cc463a8 --- /dev/null +++ b/docs/docs/language_concepts/data_types.md @@ -0,0 +1,96 @@ +--- +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](./06_generics.md): + +```rust +type Id = Size; + +fn main() { + let id: Id = 1; + let zero: u32 = 0; + assert(zero + 1 == id); +} +``` + +### BigInt + +You can acheive BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. diff --git a/docs/docs/language_concepts/data_types/00_fields.md b/docs/docs/language_concepts/data_types/00_fields.md new file mode 100644 index 00000000000..658a0441ffb --- /dev/null +++ b/docs/docs/language_concepts/data_types/00_fields.md @@ -0,0 +1,165 @@ +--- +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, + ] +--- + +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; N] +``` + +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; N] +``` + +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); +} +``` + +### 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 +``` diff --git a/docs/docs/language_concepts/data_types/01_integers.md b/docs/docs/language_concepts/data_types/01_integers.md new file mode 100644 index 00000000000..d9c5e20e795 --- /dev/null +++ b/docs/docs/language_concepts/data_types/01_integers.md @@ -0,0 +1,33 @@ +--- +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, + ] +--- + +An integer type is a range constrained field type. The Noir frontend currently supports unsigned, +arbitrary-sized integer types. + +An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by +its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of +$\\([0,2^{32}-1]\\)$: + +```rust +fn main(x : Field, y : u32) { + let z = x as u32 + y; +} +``` + +`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` +are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created +will be rejected by the verifier. + +> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) +> sized integer types. diff --git a/docs/docs/language_concepts/data_types/02_booleans.md b/docs/docs/language_concepts/data_types/02_booleans.md new file mode 100644 index 00000000000..885db167d83 --- /dev/null +++ b/docs/docs/language_concepts/data_types/02_booleans.md @@ -0,0 +1,30 @@ +--- +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, + ] +--- + + +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/docs/language_concepts/data_types/03_strings.md b/docs/docs/language_concepts/data_types/03_strings.md new file mode 100644 index 00000000000..c42f34ec3ad --- /dev/null +++ b/docs/docs/language_concepts/data_types/03_strings.md @@ -0,0 +1,63 @@ +--- +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, + ] +--- + + +The string type is a fixed length value defined with `str`. + +You can use strings in `assert()` functions or print them with +`std::println()`. See more about [Logging](../../standard_library/logging). + +```rust +use dep::std; + +fn main(message : pub str<11>, hex_as_string : str<4>) { + std::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" +``` diff --git a/docs/docs/language_concepts/data_types/04_arrays.md b/docs/docs/language_concepts/data_types/04_arrays.md new file mode 100644 index 00000000000..bdbd1798bef --- /dev/null +++ b/docs/docs/language_concepts/data_types/04_arrays.md @@ -0,0 +1,244 @@ +--- +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, + ] +--- + +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]; +``` + +## 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: + +### len + +Returns the length of an array + +```rust +fn len(_array: [T; N]) -> comptime 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(_array: [T; N]) -> [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(mut a: [T; N], 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(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(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(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(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(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/docs/language_concepts/data_types/05_slices.mdx b/docs/docs/language_concepts/data_types/05_slices.mdx new file mode 100644 index 00000000000..7fd07225a4e --- /dev/null +++ b/docs/docs/language_concepts/data_types/05_slices.mdx @@ -0,0 +1,146 @@ +--- +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] +--- + +import Experimental from '../../../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() +} +``` + +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); +``` diff --git a/docs/docs/language_concepts/data_types/06_vectors.mdx b/docs/docs/language_concepts/data_types/06_vectors.mdx new file mode 100644 index 00000000000..4d3406f20c0 --- /dev/null +++ b/docs/docs/language_concepts/data_types/06_vectors.mdx @@ -0,0 +1,172 @@ +--- +title: Vectors +description: Delve into the Vector 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] +--- + +import Experimental from '../../../src/components/Notes/_experimental.mdx'; + + + +A vector is a collection type similar to Rust's Vector type. It's convenient way to use slices as mutable arrays. + +Example: + +```rust +use dep::std::collections::vec::Vec; + +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 { + Self { slice: [] } +} +``` + +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 { + Self { slice } +} +``` + +Example: + +```rust +let arr: [Field] = [1, 2, 3]; +let vector_from_slice = Vec::from_slice(arr); +assert(vector_from_slice.len() == 3); +``` + +### 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 { + self.slice[index] +} +``` + +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) { + self.slice = self.slice.push_back(elem); +} +``` + +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 { + let (popped_slice, last_elem) = self.slice.pop_back(); + self.slice = popped_slice; + last_elem +} +``` + +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) { + self.slice = self.slice.insert(index, elem); +} +``` + +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 { + let (new_slice, elem) = self.slice.remove(index); + self.slice = new_slice; + elem +} +``` + +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); +``` + +### len + +Returns the number of elements in the vector. + +```rust +pub fn len(self) -> Field { + self.slice.len() +} +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` diff --git a/docs/docs/language_concepts/data_types/07_tuples.md b/docs/docs/language_concepts/data_types/07_tuples.md new file mode 100644 index 00000000000..5f6cab974a8 --- /dev/null +++ b/docs/docs/language_concepts/data_types/07_tuples.md @@ -0,0 +1,47 @@ +--- +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, + ] +--- + +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/language_concepts/data_types/08_structs.md b/docs/docs/language_concepts/data_types/08_structs.md new file mode 100644 index 00000000000..85649dfb389 --- /dev/null +++ b/docs/docs/language_concepts/data_types/08_structs.md @@ -0,0 +1,73 @@ +--- +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, + ] +--- + +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. + +:::note +You can use Structs as inputs to the `main` function, but you can't output them +::: diff --git a/docs/docs/language_concepts/data_types/09_references.md b/docs/docs/language_concepts/data_types/09_references.md new file mode 100644 index 00000000000..b0c35ce2cb9 --- /dev/null +++ b/docs/docs/language_concepts/data_types/09_references.md @@ -0,0 +1,22 @@ +--- +title: References +--- + +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/docs/language_concepts/data_types/10_function_types.md b/docs/docs/language_concepts/data_types/10_function_types.md new file mode 100644 index 00000000000..1ec92efd594 --- /dev/null +++ b/docs/docs/language_concepts/data_types/10_function_types.md @@ -0,0 +1,25 @@ +--- +title: Function types +--- + +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](../08_lambdas.md) for more details. diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md new file mode 100644 index 00000000000..48a8abcf22e --- /dev/null +++ b/docs/docs/migration_notes.md @@ -0,0 +1,83 @@ +--- +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. + +## β‰₯0.14 + +The index of the [for loops](./language_concepts/02_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 you 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 filed is running this bash script: , 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/docs/modules_packages_crates/crates_and_packages.md b/docs/docs/modules_packages_crates/crates_and_packages.md new file mode 100644 index 00000000000..fb83a33d94e --- /dev/null +++ b/docs/docs/modules_packages_crates/crates_and_packages.md @@ -0,0 +1,42 @@ +--- +title: Crates and Packages +description: Learn how to use Crates and Packages in your Noir project +keywords: [Nargo, dependencies, package management, crates, package] +--- + +## 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/yarn-project/noir-contracts/src/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/docs/modules_packages_crates/dependencies.md b/docs/docs/modules_packages_crates/dependencies.md new file mode 100644 index 00000000000..75f95aaa305 --- /dev/null +++ b/docs/docs/modules_packages_crates/dependencies.md @@ -0,0 +1,123 @@ +--- +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] +--- + +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 = "yarn-project/noir-contracts/src/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 +└── liba + β”œβ”€β”€ Nargo.toml + └── src + └── lib.nr +``` + +Inside of the binary crate, you can specify: + +```toml +# Nargo.toml + +[dependencies] +libA = { path = "../liba" } +``` + +## 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 liba referenced above: + +```rust +use dep::ecrecover; +use dep::libA; +``` + +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/docs/modules_packages_crates/modules.md b/docs/docs/modules_packages_crates/modules.md new file mode 100644 index 00000000000..147c9b284e8 --- /dev/null +++ b/docs/docs/modules_packages_crates/modules.md @@ -0,0 +1,104 @@ +--- +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] +--- + +Noir's module system follows the same convention as the _newer_ version of Rust's module system. + +## Purpose of Modules + +Modules are used to organise 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/docs/modules_packages_crates/workspaces.md b/docs/docs/modules_packages_crates/workspaces.md new file mode 100644 index 00000000000..eaa09506698 --- /dev/null +++ b/docs/docs/modules_packages_crates/workspaces.md @@ -0,0 +1,39 @@ +--- +title: Workspaces +--- + +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 +β”‚Β Β  β”‚Β Β  └── src +β”‚Β Β  β”‚Β Β  └── main.nr +β”‚Β Β  └── b +β”‚Β Β  β”œβ”€β”€ Nargo.toml +β”‚Β Β  └── src +β”‚Β Β  └── main.nr +β”œβ”€β”€ Nargo.toml +└── Prover.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. We just don't have a way to consume libraries from inside a workspace as external dependencies right now. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. diff --git a/docs/docs/nargo/01_commands.md b/docs/docs/nargo/01_commands.md new file mode 100644 index 00000000000..14c23290ce0 --- /dev/null +++ b/docs/docs/nargo/01_commands.md @@ -0,0 +1,237 @@ +--- +title: Commands +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, + ] +--- + +## General options + +``` +Options: + --show-ssa Emit debug information for the intermediate SSA IR + --deny-warnings Quit execution when warnings are emitted + -h, --help Print help +``` + +## `nargo help [subcommand]` + +Prints the list of available commands or specific information of a subcommand. + +_Arguments_ + +- `` - The subcommand whose help message to display + +## `nargo backend` + +Installs and selects custom backends used to generate and verify proofs. + +### Commands + +``` + 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 + help Print this message or the help of the given subcommand(s) +``` + +### Options + +``` +-h, --help Print help +``` + +## `nargo check` + +Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output +values of the Noir program respectively. + +### Options + +``` + --package The name of the package to check + --workspace Check all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +### `nargo codegen-verifier` + +Generate a Solidity verifier smart contract for the program. + +### Options + +``` + --package The name of the package to codegen + --workspace Codegen all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo compile` + +Compile the program into a JSON build artifact file containing the ACIR representation and the ABI +of the circuit. This build artifact can then be used to generate and verify proofs. + +You can also use "build" as an alias for compile (e.g. `nargo build`). + +### Options + +``` + --include-keys Include Proving and Verification keys in the build artifacts + --package The name of the package to compile + --workspace Compile all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo new ` + +Creates a new Noir project in a new folder. + +**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 +-h, --help Print help +``` + +## `nargo init` + +Creates a new Noir project in the current directory. + +### 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 +-h, --help Print help +``` + +## `nargo execute [WITNESS_NAME]` + +Runs the Noir program and prints its return value. + +**Arguments** + +``` +[WITNESS_NAME] 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: Prover] + --package The name of the package to execute + --workspace Execute all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +_Usage_ + +The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which +must be filled in. + +To save the witness to file, run the command with a value for the `WITNESS_NAME` argument. A +`.tr` file will then be saved in the `./target` folder. + +## `nargo prove` + +Creates a proof for the program. + +### Options + +``` +-p, --prover-name The name of the toml file which contains the inputs for the prover [default: Prover] +-v, --verifier-name The name of the toml file which contains the inputs for the verifier [default: Verifier] + --verify Verify proof after proving + --package The name of the package to prove + --workspace Prove all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo verify` + +Given a proof and a program, verify whether the proof is valid. + +### Options + +``` +-v, --verifier-name The name of the toml file which contains the inputs for the verifier [default: Verifier] + --package The name of the package verify + --workspace Verify all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo test [TEST_NAME]` + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. To print `println` statements in tests, use the `--show-output` flag. + +Takes an optional `--exact` flag which allows you to select tests based on an exact name. + +See an example on the [testing page](./testing). + +### 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 + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo info` + +Prints a table containing the information of the package. + +Currently the table provide + +1. The number of ACIR opcodes +2. The final number gates in the circuit used by a backend + +If the file contains a contract the table will provide the +above information about each function of the contract. + +## `nargo lsp` + +Start a long-running Language Server process that communicates over stdin/stdout. +Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). diff --git a/docs/docs/nargo/02_testing.md b/docs/docs/nargo/02_testing.md new file mode 100644 index 00000000000..da767274efd --- /dev/null +++ b/docs/docs/nargo/02_testing.md @@ -0,0 +1,61 @@ +--- +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] +--- + +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 the all +the contraints 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/docs/nargo/03_solidity_verifier.md b/docs/docs/nargo/03_solidity_verifier.md new file mode 100644 index 00000000000..9ac60cb0ba7 --- /dev/null +++ b/docs/docs/nargo/03_solidity_verifier.md @@ -0,0 +1,129 @@ +--- +title: 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, + ] +--- + +For certain applications, it may be desirable to run the verifier as a smart contract instead of on +a local machine. + +Compile a Solidity verifier contract for your Noir program by running: + +```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 on any EVM blockchain acting as a verifier smart contract. + +> **Note:** It is possible to compile 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 compilation of verifier contracts in +> Solidity only for the time being. + +## Verify + +To verify a proof using the Solidity verifier contract, call the `verify` function with the +following signature: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +You can see an example of how the `verify` function is called 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"); +``` + +### Public Inputs + +:::tip + +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. + +::: + +The verifier contract uses the output (return) value of a Noir program as a public input. So if you +have the following function + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +then `verify` in `plonk_vk.sol` will expect 3 public inputs. Passing two inputs will result in an +error like `Reason: PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case the 3 inputs to `verify` would be ordered as `[pubkey_x, pubkey_y, return]`. + +#### Struct inputs + +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) { + //... +} +``` + +Structs will be flattened so that the array of inputs is 1-dimensional array. The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +## Noir for EVM chains + +You can currently deploy the Solidity verifier contracts to most EVM compatible chains. EVM chains that have been tested and are known to work include: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +Other EVM chains should work, but have not been tested directly by our team. 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. + +### Unsupported chains + +Unfortunately not all "EVM" chains are supported. + +**zkSync** and the **Polygon zkEVM** do _not_ currently support proof verification via Solidity verifier contracts. They are missing the bn256 precompile contract that the verifier contract requires. Once these chains support this precompile, they may work. diff --git a/docs/docs/nargo/04_language_server.md b/docs/docs/nargo/04_language_server.md new file mode 100644 index 00000000000..8a81d7232d8 --- /dev/null +++ b/docs/docs/nargo/04_language_server.md @@ -0,0 +1,40 @@ +--- +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] +--- + +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). + +When you language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, execution, and tests: + +![Compile and Execute](./../../static/img/codelens_compile_execute.png) +![Run test](../../static/img/codelens_run_test.png) + +You should also see your tests in the `testing` panel: + +![Testing panel](./../../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/docs/noir_js/getting_started/01_tiny_noir_app.md b/docs/docs/noir_js/getting_started/01_tiny_noir_app.md new file mode 100644 index 00000000000..629a88fd2f1 --- /dev/null +++ b/docs/docs/noir_js/getting_started/01_tiny_noir_app.md @@ -0,0 +1,250 @@ +--- +title: Full Stack Noir App +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] +--- + +Noir JS works both on the browser and on the server, and works for both ESM and CJS module systems. In this page, we will learn how can we write a simple test and a simple web app to verify the standard Noir example. + +## Before we start + +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 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 +``` + +Your folder structure should look like: + +```tree +. +└── circuit + β”œβ”€β”€ Nargo.toml + β”œβ”€β”€ src + β”‚ └── main.nr + └── target + └── circuit.json +``` + +## Starting a new project + +Go back to the previous folder and start a new project by running run `npm init`. You can configure your project or just leave the defaults, and see a `package.json` appear in your root folder. + +## Installing dependencies + +We'll need two `npm` packages. These packages will provide us the methods we need to run and verify proofs. Let's install them: + +```bash +npm i @noir-lang/backend_barretenberg @noir-lang/noir_js +``` + +To serve our page, we can use a build tool such as `vite`. Because we're gonna use some `wasm` files, we need to install a plugin as well. Run: + +```bash +npm i --save-dev vite rollup-plugin-copy +``` + +Since we're on the dependency world, we may as well define a nice starting script. Vite makes it easy. Just open `package.json`, find the block "scripts" and add this just below the line with `"test" : "echo......."`: + +```json + "start": "vite --open" +``` + +If you want do build a static website, you can also add some build and preview scripts: + +```json + "build": "vite build", + "preview": "vite preview" +``` + +## Vite plugins + +Vite is great, but support from `wasm` doesn't work out-of-the-box. We're gonna write a quick plugin and use another one. Just copy and paste this into a file named `vite.config.js`. You don't need to understand it, just trust me bro. + +```js +import { defineConfig } from 'vite'; +import copy from 'rollup-plugin-copy'; +import fs from 'fs'; +import path from 'path'; + +const wasmContentTypePlugin = { + name: 'wasm-content-type-plugin', + configureServer(server) { + server.middlewares.use(async (req, res, next) => { + if (req.url.endsWith('.wasm')) { + res.setHeader('Content-Type', 'application/wasm'); + const newPath = req.url.replace('deps', 'dist'); + const targetPath = path.join(__dirname, newPath); + const wasmContent = fs.readFileSync(targetPath); + return res.end(wasmContent); + } + next(); + }); + }, +}; + +export default defineConfig(({ command }) => { + if (command === 'serve') { + return { + plugins: [ + copy({ + targets: [{ src: 'node_modules/**/*.wasm', dest: 'node_modules/.vite/dist' }], + copySync: true, + hook: 'buildStart', + }), + command === 'serve' ? wasmContentTypePlugin : [], + ], + }; + } + + return {}; +}); +``` + +## HTML + +Here's the simplest HTML with some terrible UI. Create a file called `index.html` and paste this: + +```html + + + + + + +

Very basic Noir app

+
+

Logs

+

Proof

+
+ + +``` + +## Some good old vanilla Javascript + +Create a new file `app.js`, which is where our javascript code will live. Let's start with this code inside: + +```js +document.addEventListener('DOMContentLoaded', async () => { + // here's where the magic happens +}); + +function display(container, msg) { + const c = document.getElementById(container); + const p = document.createElement('p'); + p.textContent = msg; + c.appendChild(p); +} +``` + +We can manipulate our website with this little function, so we can see our website working. + +## Adding Noir + +If you come from the previous page, your folder structure should look like this: + +```tree +β”œβ”€β”€ app.js +β”œβ”€β”€ circuit +β”‚ β”œβ”€β”€ Nargo.toml +β”‚ β”œβ”€β”€ src +β”‚ β”‚ └── main.nr +β”‚ └── target +β”‚ └── circuit.json +β”œβ”€β”€ index.html +β”œβ”€β”€ package.json +└── vite.config.js +``` + +You'll see other files and folders showing up (like `package-lock.json`, `yarn.lock`, `node_modules`) but you shouldn't have to care about those. + +## Importing our dependencies + +We're starting with the good stuff now. At the top of a new the typescript file, import the packages: + +```ts +import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { Noir } from '@noir-lang/noir_js'; +``` + +We also need to import the `circuit` JSON file we created. If you have the suggested folder structure, you can add this line: + +```ts +import circuit from './circuit/target/circuit.json'; +``` + +## Write code + +:::note + +We're gonna be adding code inside the `document.addEventListener...etc` block: + +```js +// forget stuff here +document.addEventListener('DOMContentLoaded', async () => { + // here's where the magic happens +}); +// forget stuff here +``` + +::: + +Our dependencies exported two classes: `BarretenbergBackend` and `Noir`. Let's `init` them and add some logs, just to flex: + +```ts +const backend = new BarretenbergBackend(circuit); +const noir = new Noir(circuit, backend); + +display('logs', 'Init... βŒ›'); +await noir.init(); +display('logs', 'Init... βœ…'); +``` + +You're probably eager to see stuff happening, so go and run your app now! + +From your terminal, run `npm start` (or `yarn start`). If it doesn't open a browser for you, just visit `localhost:5173`. You'll see your app with the two logs: + +![Getting Started 0](./../../../static/img/noir_getting_started_0.png) + +## Proving + +Now we're ready to prove stuff! Let's feed some inputs to our circuit and calculate the proof: + +```js +const input = { x: 1, y: 2 }; +display('logs', 'Generating proof... βŒ›'); +const proof = await noir.generateFinalProof(input); +display('logs', 'Generating proof... βœ…'); +display('results', proof); +``` + +Save your doc and vite should refresh your page automatically. On a modern laptop, proof will generate in less than 100ms, and you'll see this: + +![Getting Started 0](./../../../static/img/noir_getting_started_1.png) + +If you're human, you shouldn't be able to understand anything on the "proof" box. That's OK. We like you, human. + +In any case, this means your proof was generated! But you shouldn't trust me just yet. Add these lines to see it being verified: + +```js +display('logs', 'Verifying proof... βŒ›'); +const verification = await noir.verifyFinalProof(proof); +if (verification) display('logs', 'Verifying proof... βœ…'); +``` + +By saving, your app will refresh and here's our complete Tiny Noir App! diff --git a/docs/docs/noir_js/noir_js.md b/docs/docs/noir_js/noir_js.md new file mode 100644 index 00000000000..a4609215f92 --- /dev/null +++ b/docs/docs/noir_js/noir_js.md @@ -0,0 +1,22 @@ +--- +title: Noir JS +description: Learn how to use noir js to use Noir in a Typescript or Javascript environment +keywords: [Noir project, javascript, typescript, node.js, browser, react] +--- + +Noir JS are a set of typescript libraries that make it easy to use Noir on your dapp, webapp, node.js server, website, etc. + +It is composed of two major elements: + +- Noir +- Backend proving system + + + +Your only concern should be to write Noir. Noir.js will work out-of-the box and abstract all the components, such as the ACVM and others. + +## Barretenberg + +Since Noir is backend agnostic, you can instantiate `noir_js` with supported backends through their own `js` interface. + +Aztec Labs maintains the `barretenberg` backend. You can use it to instantiate your `Noir` class. diff --git a/docs/docs/noir_js/reference/01_bb_backend.md b/docs/docs/noir_js/reference/01_bb_backend.md new file mode 100644 index 00000000000..446bf9820ea --- /dev/null +++ b/docs/docs/noir_js/reference/01_bb_backend.md @@ -0,0 +1,272 @@ +--- +title: BarretenbergBackend +description: Reference documentation for the barretenberg_backend library and the BarretenbergBackend class +keywords: + [ + BarretenbergBackend, + Barretenberg, + javascript, + typescript, + node.js, + browser, + class, + reference, + noir_js, + ] +--- + +## Table of Contents + +- [constructor](#constructor) +- [generateFinalProof](#generatefinalproof) +- [generateIntermediateProof](#generateintermediateproof) +- [generateProof](#generateproof) +- [generateIntermediateProofArtifacts](#generateintermediateproofartifacts) +- [verifyFinalProof](#verifyfinalproof) +- [verifyIntermediateProof](#verifyintermediateproof) +- [verifyProof](#verifyproof) +- [destroy](#destroy) + +## `constructor` + +The `constructor` is a method used to create and initialize objects created within the `BarretenbergBackend` class. In this class, you should pass at least one argument for the `circuit`. + +### Syntax + +```js +constructor(acirCircuit, (numberOfThreads = 1)); +``` + +### Parameters + +| Parameter | Type | Description | +| ----------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `acirCircuit` | Object | A circuit represented in a `json` format, containing the ABI and bytecode Tipically obtained by running [`nargo compile`](../../nargo/01_commands.md). This is the same circuit expected to be passed to [the Noir class](02_noirjs.md) | +| `numberOfThreads` | Number (optional) | The number of threads to be used by the backend. Defaults to 1. | + +### Usage + +```js +const backend = new BarretenbergBackend(acirCircuit); +``` + +## `generateFinalProof` + +An async wrapper around the [generateProof](#generateproof) method that passes a `false` flag. Usually called by the Noir class. + +### Syntax + +```js +async generateFinalProof(decompressedWitness) +``` + +### Parameters + +| Parameter | Type | Description | +| --------------------- | ------ | -------------------------------------------------------- | +| `decompressedWitness` | Object | The decompressed witness for generating the final proof. | + +### Returns + +| Return value | Type | Description | +| ------------ | -------------------- | --------------------------------------------------------- | +| `proof` | Promise | An array with the byte representation of the final proof. | + +### Usage + +```js +const finalProof = await backend.generateFinalProof(decompressedWitness); +``` + +## `generateIntermediateProof` + +An async wrapper around the [generateProof](#generateproof) method that passes a `true` flag. It's not currently being used by the Noir class, but developers can call this method directly to use Noir's recursive features. + +### Syntax + +```js +async generateIntermediateProof(witness) +``` + +### Parameters + +| Parameter | Type | Description | +| --------- | ------ | -------------------------------------------------- | +| `witness` | Object | The witness for generating the intermediate proof. | + +### Returns + +| Return value | Type | Description | +| ------------ | -------------------- | --------------------------------------------------------------- | +| `proof` | Promise | An array with the byte representation of the intermediate proof | + +### Usage + +```js +const intermediateProof = await backend.generateIntermediateProof(witness); +``` + +## `generateProof` + +This async method generates a proof. Takes the witness generated by ACVM, and a boolean that evaluates to `true` when the proof _is_ meant to be verified in another circuit. Not currently used by the Noir class. + +### Syntax + +```js +async generateProof(decompressedWitness, makeEasyToVerifyInCircuit) +``` + +### Parameters + +| Parameter | Type | Description | +| --------------------------- | ------- | ---------------------------------------------------------------------------------------------- | +| `decompressedWitness` | Object | The decompressed witness for generating the proof. | +| `makeEasyToVerifyInCircuit` | Boolean | A flag indicating whether to generate proof components for easy verification within a circuit. | + +### Returns + +| Return value | Type | Description | +| ------------ | -------------------- | -------------------------------------------------- | +| `proof` | Promise | An array with the byte representation of the proof | + +### Usage + +```js +const proof = await backend.generateProof(decompressedWitness, makeEasyToVerifyInCircuit); +``` + +## `generateIntermediateProofArtifacts` + +This async method returns the artifacts needed to verify the intermediate proof in another circuit. It's not currently being used by the Noir class, but developers can call this method directly to use Noir's recursive features. + +### Syntax + +```js +async generateIntermediateProofArtifacts(proof, numOfPublicInputs = 0) +``` + +### Parameters + +| Parameter | Type | Description | +| ------------------- | ----------------- | ---------------------------------------------------------------- | +| `proof` | Object | The proof object. | +| `numOfPublicInputs` | Number (optional) | The number of public inputs in the inner proof, defaulting to 0. | + +### Returns + +| Return value | Type | Description | +| --------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `proofAsFields` | string[] | An array of strings with the hexadecimal representation of the [Fields](../../language_concepts/data_types/00_fields.md) that make up a proof | +| `vkAsFields` | string[] | An array of strings with the hexadecimal representation of the [Fields](../../language_concepts/data_types/00_fields.md) that make up the verification key | +| `vkHash` | string | A pedersen hash of the verification key | + +### Usage + +```js +const artifacts = await backend.generateIntermediateProofArtifacts(proof, numOfPublicInputs); +``` + +## `verifyFinalProof` + +An async wrapper around [verifyProof](#verifyproof) that sets the `false` flag. Usually called by the Noir class. + +### Syntax + +```js +async verifyFinalProof(proof) +``` + +### Parameters + +| Parameter | Type | Description | +| --------- | ------ | --------------------------- | +| `proof` | Object | The proof object to verify. | + +### Returns + +| Return value | Type | Description | +| ------------ | ------------------ | -------------------------------------------- | +| `verified` | Promise | A boolean for whether the proof was verified | + +### Usage + +```js +const isValidFinal = await backend.verifyFinalProof(proof); +``` + +## `verifyIntermediateProof` + +An async wrapper around [verifyProof](#verifyproof) that sets the `true` flag. It's not currently being used by the Noir class, but developers can call this method directly to use Noir's recursive features. + +### Syntax + +```js +async verifyIntermediateProof(proof) +``` + +### Parameters + +| Parameter | Type | Description | +| --------- | ------ | ---------------------------------------- | +| `proof` | Object | The intermediate proof object to verify. | + +### Returns + +| Return value | Type | Description | +| ------------ | ------------------ | -------------------------------------------- | +| `verified` | Promise | A boolean for whether the proof was verified | + +### Usage + +```js +const isValidIntermediate = await backend.verifyIntermediateProof(proof); +``` + +## `verifyProof` + +This async method verifies a proof. Takes the proof, and a boolean that evaluates to `true` when the proof is intermediate. + +### Syntax + +```js +async verifyProof(proof, makeEasyToVerifyInCircuit) +``` + +### Parameters + +| Parameter | Type | Description | +| --------------------------- | ------- | ------------------------------------------------------------ | +| `proof` | Object | The proof object to verify | +| `makeEasyToVerifyInCircuit` | Boolean | A flag indicating whether the proof is intermediate or final | + +### Returns + +| Parameter | Type | Description | +| ---------- | ------------------ | -------------------------------------------- | +| `verified` | Promise\ | A boolean for whether the proof was verified | + +### Usage + +```js +const isValid = await backend.verifyProof(proof, makeEasyToVerifyInCircuit); +``` + +## `destroy` + +This method destroys the resources allocated in the [instantiate](#instantiate) method. Noir doesn't currently call this method, but it's highly recommended that developers do so in order to save resources. + +### Syntax + +```js +async destroy() +``` + +### Parameters + +This method takes no parameters. + +### Usage + +```js +await backend.destroy(); +``` diff --git a/docs/docs/noir_js/reference/02_noirjs.md b/docs/docs/noir_js/reference/02_noirjs.md new file mode 100644 index 00000000000..07baf1e0bbe --- /dev/null +++ b/docs/docs/noir_js/reference/02_noirjs.md @@ -0,0 +1,114 @@ +--- +title: Noir +description: Reference to noir_js library and the Noir class +keywords: [Noir project, javascript, typescript, node.js, browser, react, class, reference] +--- + +## Table of Contents + +- [constructor](#constructor) +- [init](#init) +- [generateFinalProof](#generatefinalproof) +- [verifyFinalProof](#verifyfinalproof) + +## `constructor` + +The `constructor` is a method used to create and initialize objects created within the `Noir` class. In the `Noir` class constructor, you need to pass two parameters: `circuit` and `backend`. + +### Syntax + +```js +constructor(circuit, backend); +``` + +### Parameters + +| Parameter | Type | Description | +| --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `circuit` | Object | A circuit represented in a `json` format, containing the ABI and bytecode. Typically obtained by running [`nargo compile`](../../nargo/01_commands.md) | +| `backend` | Object | A backend instance, before initialization. | + +### Usage + +```js +const noir = new Noir(circuit, backend); +``` + +## `init` + +This async method should be called after class instantiation. It will run processes on the ACVM, instantiate your backend, etc. + +### Syntax + +```js +async init() +``` + +### Parameters + +This method takes no parameters + +### Usage + +```js +await noirInstance.init(); +``` + +## `generateFinalProof` + +This async method generates a witness and a proof given an object as input. + +### Syntax + +```js +async generateFinalproof(input) +``` + +### Parameters + +| Parameter | Type | Description | +| --------- | ------ | ------------------------------------------------ | +| `input` | Object | An object containing the inputs to your circuit. | + +### Returns + +| Return value | Type | Description | +| ------------ | --------------------- | --------------------------------------------------- | +| `proof` | Promise | An array with the byte representation of the proof. | + +### Usage + +```js +// consider the Standard Noir Example given with nargo init +const input = { x: 1, y: 2 }; +noirInstance.generateProof(input); +``` + +## `verifyFinalProof` + +This async method instantiates the verification key and verifies your proof. + +### Syntax + +```js +async verifyFinalProof(proof) +``` + +### Parameters + +| Parameter | Type | Description | +| --------- | ---------- | --------------------------------------------------------------------------------------------- | +| `proof` | Uint8Array | The Uint8Array representation of your proof, usually obtained by calling `generateFinalProof` | + +### Returns + +| Return value | Type | Description | +| ------------ | ------------------ | -------------------------------------------- | +| `verified` | Promise | A boolean for whether the proof was verified | + +### Usage + +```js +const proof = noirInstance.generateProof(input); +noirInstance.verifyFinalProof(proof); +``` diff --git a/docs/docs/standard_library/black_box_fns.md b/docs/docs/standard_library/black_box_fns.md new file mode 100644 index 00000000000..c758846b688 --- /dev/null +++ b/docs/docs/standard_library/black_box_fns.md @@ -0,0 +1,45 @@ +--- +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. + +:::warning + +It is likely that not all backends will support a particular black box function. + +::: + +Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. + +Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: + +```rust +#[foreign(sha256)] +fn sha256(_input : [u8; N]) -> [u8; 32] {} +``` + +## Function list + +Here is a list of the current black box functions that are supported by UltraPlonk: + +- AES +- [SHA256](./cryptographic_primitives/hashes#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr) +- [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Pedersen](./cryptographic_primitives/hashes#pedersen) +- [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [Compute merkle root](./merkle_trees#compute_merkle_root) +- AND +- XOR +- RANGE +- [Keccak256](./cryptographic_primitives/hashes#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. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. + +You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/acvm/blob/acir-v0.12.0/acir/src/circuit/black_box_functions.rs). diff --git a/docs/docs/standard_library/cryptographic_primitives.md b/docs/docs/standard_library/cryptographic_primitives.md new file mode 100644 index 00000000000..2df4f929474 --- /dev/null +++ b/docs/docs/standard_library/cryptographic_primitives.md @@ -0,0 +1,14 @@ +--- +title: Cryptographic primitives in Noir +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/standard_library/cryptographic_primitives/00_hashes.mdx b/docs/docs/standard_library/cryptographic_primitives/00_hashes.mdx new file mode 100644 index 00000000000..bb2621b6499 --- /dev/null +++ b/docs/docs/standard_library/cryptographic_primitives/00_hashes.mdx @@ -0,0 +1,146 @@ +--- +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] +--- + +import BlackBoxInfo from '../../../src/components/Notes/_blackbox.mdx'; + +## sha256 + +Given an array of bytes, returns the resulting sha256 hash. + +```rust +fn sha256(_input : [u8]) -> [u8; 32] +``` + +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 +fn blake2s(_input : [u8]) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::blake2s(x); +} +``` + + + +## pedersen + +Given an array of Fields, returns the Pedersen hash. + +```rust +fn pedersen(_input : [Field]) -> [Field; 2] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::pedersen(x); +} +``` + + + +## 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 +fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let message_size = 4; + let hash = std::hash::keccak256(x, message_size); +} +``` + + + +## 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 +fn main() +{ + let hash1 = std::hash::poseidon::bn254::hash_2([1, 2]); + assert(hash1 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); +} +``` + +## 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_bn254(x); +} +``` + +## hash_to_field + +```rust +fn hash_to_field(_input : [Field; N]) -> 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/docs/standard_library/cryptographic_primitives/01_scalar.mdx b/docs/docs/standard_library/cryptographic_primitives/01_scalar.mdx new file mode 100644 index 00000000000..0d7990859b5 --- /dev/null +++ b/docs/docs/standard_library/cryptographic_primitives/01_scalar.mdx @@ -0,0 +1,27 @@ +--- +title: Scalar multiplication +description: See how you can perform scalar multiplications over a fixed base in Noir +keywords: [cryptographic primitives, Noir project, scalar multiplication] +--- + +import BlackBoxInfo from '../../../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 +fn fixed_base_embedded_curve(_input : Field) -> [Field; 2] +``` + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base_embedded_curve(x); + std::println(scal); +} +``` + + diff --git a/docs/docs/standard_library/cryptographic_primitives/02_schnorr.mdx b/docs/docs/standard_library/cryptographic_primitives/02_schnorr.mdx new file mode 100644 index 00000000000..73737eb54bb --- /dev/null +++ b/docs/docs/standard_library/cryptographic_primitives/02_schnorr.mdx @@ -0,0 +1,37 @@ +--- +title: Schnorr Signatures +description: Learn how you can verify Schnorr signatures using Noir +keywords: [cryptographic primitives, Noir project, schnorr, signatures] +--- + +import BlackBoxInfo from '../../../src/components/Notes/_blackbox.mdx'; + +## schnorr::verify_signature + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). + +```rust +fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool +``` + +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() +); + +... +``` + + diff --git a/docs/docs/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/docs/docs/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx new file mode 100644 index 00000000000..25185b062f7 --- /dev/null +++ b/docs/docs/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx @@ -0,0 +1,45 @@ +--- +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] +--- + +import BlackBoxInfo from '../../../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 + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + +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_secp256r1::verify_signature + +Verifier for ECDSA Secp256r1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + +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); +} +``` + + diff --git a/docs/docs/standard_library/cryptographic_primitives/04_ec_primitives.md b/docs/docs/standard_library/cryptographic_primitives/04_ec_primitives.md new file mode 100644 index 00000000000..6e6b19b6861 --- /dev/null +++ b/docs/docs/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -0,0 +1,101 @@ +--- +title: Elliptic Curve Primitives +keywords: [cryptographic primitives, Noir project] +--- + +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/crates/nargo_cli/tests/test_data/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/docs/standard_library/cryptographic_primitives/05_eddsa.mdx b/docs/docs/standard_library/cryptographic_primitives/05_eddsa.mdx new file mode 100644 index 00000000000..39dfb604669 --- /dev/null +++ b/docs/docs/standard_library/cryptographic_primitives/05_eddsa.mdx @@ -0,0 +1,17 @@ +--- +title: EdDSA Verification +description: Learn about the cryptographic primitives regarding EdDSA +keywords: [cryptographic primitives, Noir project, eddsa, signatures] +--- + +import BlackBoxInfo from '../../../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 +``` + + diff --git a/docs/docs/standard_library/logging.md b/docs/docs/standard_library/logging.md new file mode 100644 index 00000000000..7e2fd9b9aff --- /dev/null +++ b/docs/docs/standard_library/logging.md @@ -0,0 +1,62 @@ +--- +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, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +The standard library provides a familiar `println` statement you can use. Despite being a limited +implementation of rust's `println!` macro, this construct can be useful for debugging. + +You can print the output of println statements in your Noir code by using the `nargo execute` command or the `--show-output` flag when using `nargo test` (provided there are println statements in your tests). + +It is recommended to use `nargo execute` if you want to debug failing constrains with `println` 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). `println` will not work for failed constraints caught at compile time. + +The `println` statement is unconstrained, so it works for outputting integers, fields, strings, and even structs or expressions. For example: + +```rust +use dep::std; + +struct Person { + age : Field, + height : Field, +} + +fn main(age : Field, height : Field) { + let person = Person { age : age, height : height }; + std::println(person); + std::println(age + height); + std::println("Hello world!"); +} + +``` + +You can print multiple different types in the same statement and string as well as a new "fmtstr" type. A `fmtstr` can be specified in the same way as a normal string it just should be prepended with an "f" character: + +```rust + let fmt_str = f"i: {i}, j: {j}"; + std::println(fmt_str); + + let s = myStruct { y: x, x: y }; + std::println(s); + + std::println(f"i: {i}, s: {s}"); + + std::println(x); + std::println([x, y]); + + let foo = fooStruct { my_struct: s, foo: 15 }; + std::println(f"s: {s}, foo: {foo}"); +``` diff --git a/docs/docs/standard_library/merkle_trees.md b/docs/docs/standard_library/merkle_trees.md new file mode 100644 index 00000000000..9761105f4f2 --- /dev/null +++ b/docs/docs/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/00_hashes.mdx#pedersen). + +```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); + std::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/docs/standard_library/options.md b/docs/docs/standard_library/options.md new file mode 100644 index 00000000000..3d3139fb98b --- /dev/null +++ b/docs/docs/standard_library/options.md @@ -0,0 +1,99 @@ +--- +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), +} +``` + +You can import the Option type into your Noir program like so: + +```rust +use dep::std::option::Option; + +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. + +### 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/docs/standard_library/recursion.md b/docs/docs/standard_library/recursion.md new file mode 100644 index 00000000000..ff4c63acaa7 --- /dev/null +++ b/docs/docs/standard_library/recursion.md @@ -0,0 +1,96 @@ +--- +title: Recursive Proofs +description: Learn about how to write recursive proofs in Noir. +keywords: [recursion, recursive proofs, verification_key, aggregation object, 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. + +The `verify_proof` function takes a verification key, proof and public inputs for a zk program, as well as a key hash and an input aggregation object. The key hash is used to check the validity of the verification key and the input aggregation object is required by some proving systems. The `verify_proof` function returns an output aggregation object that can then be fed into future iterations of the proof verification if required. + +```rust +#[foreign(verify_proof)] +fn verify_proof(_verification_key : [Field], _proof : [Field], _public_input : Field, _key_hash : Field, _input_aggregation_object : [Field]) -> [Field] {} +``` + +:::info + +This is a black box function. Read [this section](./black_box_fns) to learn more about black box functions in Noir. + +::: + +## Aggregation Object + +The purpose of the input aggregation object is a little less clear though (and the output aggregation object that is returned from the `std::verify_proof` method). 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. In the case of PLONK the recursive aggregation object is two G1 points (expressed as 16 witness values). The final verifier (in our case this is most often the smart contract verifier) has to be aware of this aggregation object to execute a pairing and check the validity of these points (thus completing the recursive verification). + +So for example in this circuit: + +```rust +use dep::std; + +fn main( + verification_key : [Field; 114], + proof : [Field; 94], + public_inputs : [Field; 1], + key_hash : Field, + input_aggregation_object : [Field; 16], + proof_b : [Field; 94], +) -> pub [Field; 16] { + let output_aggregation_object_a = std::verify_proof( + verification_key, + proof, + public_inputs, + key_hash, + input_aggregation_object + ); + + let output_aggregation_object = std::verify_proof( + verification_key, + proof_b, + public_inputs, + key_hash, + output_aggregation_object_a + ); + + let mut output = [0; 16]; + for i in 0..16 { + output[i] = output_aggregation_object[i]; + } + output +} +``` + +In this example we have a circuit, that generates proofs A and B, that is being verified in circuit C. Assuming that the proof being passed in is not already a recursive proof, the `input_aggregation_object` will be all zeros. It will then generate an `output_aggregation_object`. This blob of data then becomes the `input_aggregation_object` of the next recursive aggregation we wish to compute. We can see here as the same public inputs, verification key, and key hash are used that we are verifying two proofs generated from the same circuit in this single circuit. `std::verify_proof` returns a `[Field]` because the size of an aggregation object is proof system dependent--in barretenberg, aggregation objects are two G1 points, while in Halo2, the aggregation object is a list of G1 points that is log the circuit size. So for the final step we convert the slice into an array of size 16 because we are generating proofs using UltraPlonk. + +## 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. They should be checked against in the circuit after construction of a new aggregation state. + +### `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. + +### `input_aggregation_object` + +An aggregation object is blob of data that the top-level verifier must run some proof system specific algorithm on to complete verification. The size is proof system specific and will be set by the backend integrating this opcode. The input aggregation object is only not `None` when we are verifying a previous recursive aggregation in the current circuit. If this is the first recursive aggregation there is no input aggregation object. It is left to the backend to determine how to handle when there is no input aggregation object. + +## Return value + +### `output_aggregation_object` + +This is the result of a recursive aggregation and is what will be fed into the next verifier. +The next verifier can either perform a final verification (returning true or false) or perform another recursive aggregation where this output aggregation object will be the input aggregation object of the next recursive aggregation. + +## Example + +You can see an example of how to do recursive proofs in [this example recursion demo repo](https://github.com/noir-lang/noir-examples/tree/master/recursion). diff --git a/docs/docs/standard_library/zeroed.md b/docs/docs/standard_library/zeroed.md new file mode 100644 index 00000000000..97dab02dac2 --- /dev/null +++ b/docs/docs/standard_library/zeroed.md @@ -0,0 +1,25 @@ +--- +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 +- String +- Tuple +- Function + +Using it on other types could result in unexpected behavior. diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js new file mode 100644 index 00000000000..1abf122c405 --- /dev/null +++ b/docs/docusaurus.config.js @@ -0,0 +1,155 @@ +// @ts-check +// Note: type annotations allow type checking and IDEs autocompletion + +const lightCodeTheme = require('prism-react-renderer/themes/github'); +const darkCodeTheme = require('prism-react-renderer/themes/dracula'); + +const math = require('remark-math'); +const katex = require('rehype-katex'); + +/** @type {import('@docusaurus/types').Config} */ +const config = { + title: 'Noir Documentation', + tagline: 'The Universal ZK Circuit Language', + favicon: 'img/favicon.ico', + url: 'https://noir-lang.org', + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: '/', + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'throw', + + // Even if you don't use internalization, you can use this field to set useful + // metadata like html lang. For example, if your site is Chinese, you may want + // to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + presets: [ + [ + '@docusaurus/preset-classic', + { + // gtag: { + // trackingID: 'G-SZQHEQZK3L', + // anonymizeIP: true, + // }, + docs: { + sidebarPath: require.resolve('./sidebars.js'), + routeBasePath: '/', + remarkPlugins: [math], + rehypePlugins: [katex], + versions: { + current: { + label: 'dev', + path: 'dev', + }, + "0.7.1": { + label: '0.7.1 / 0.8.0' + }, + }, + editUrl: ({ versionDocsDirPath, docPath }) => + `https://github.com/noir-lang/docs/edit/master/${versionDocsDirPath}/${docPath}`, + }, + blog: false, + theme: { + customCss: require.resolve('./src/css/custom.css'), + }, + }, + ], + ], + + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + ({ + // Replace with your project's social card + navbar: { + logo: { + alt: 'Noir Logo', + src: 'img/logo.svg', + srcDark: 'img/logoDark.svg', + href: '/', + }, + items: [ + { + href: 'https://github.com/noir-lang/docs', + label: 'GitHub', + position: 'right', + }, + { + type: 'docsVersionDropdown', + position: 'left', + dropdownActiveClassDisabled: true, + }, + ], + }, + metadata: [ + { + name: 'Noir', + content: + 'noir, programming, language, documentation, zk, zero-knowledge, l2, crypto, layer2, ethereum', + }, + ], + footer: { + style: 'dark', + links: [ + { + title: 'Community', + items: [ + { + label: 'Noir Forum', + href: 'https://discourse.aztec.network/c/noir/7', + }, + { + label: 'Twitter', + href: 'https://twitter.com/NoirLang', + }, + { + label: 'Discord', + href: 'https://discord.gg/JtqzkdeQ6G' + } + ], + }, + { + title: 'Code', + items: [ + { + label: 'Noir GitHub', + href: 'https://github.com/noir-lang', + }, + { + label: 'Docs GitHub', + href: 'https://github.com/noir-lang/docs', + }, + ], + }, + ], + copyright: `Noir will be dual licensed under MIT/Apache (Version 2.0).`, + }, + prism: { + theme: lightCodeTheme, + darkTheme: darkCodeTheme, + additionalLanguages: ['rust', 'powershell', 'solidity', 'toml'], + }, + stylesheets: [ + { + href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', + type: 'text/css', + integrity: 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', + crossorigin: 'anonymous', + }, + ], + algolia: { + // The application ID provided by Algolia + appId: '97APAVUL6H', + + // Public API key: it is safe to commit it + apiKey: 'b9b94d2f1c58f7d509f0bc1f13b381fb', + + indexName: 'noir-lang', + }, + }), +}; + +module.exports = config; diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 00000000000..edf4bba0686 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,42 @@ +{ + "name": "docs", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "docusaurus start", + "build": "docusaurus build" + }, + "dependencies": { + "@docusaurus/core": "^2.4.0", + "@docusaurus/plugin-google-gtag": "^2.4.0", + "@docusaurus/preset-classic": "^2.4.0", + "@easyops-cn/docusaurus-search-local": "^0.35.0", + "@mdx-js/react": "^1.6.22", + "axios": "^1.4.0", + "clsx": "^1.2.1", + "hast-util-is-element": "^1.1.0", + "prism-react-renderer": "^1.3.5", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "rehype-katex": "^5.0.0", + "remark-math": "^3.0.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^2.4.0" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "engines": { + "node": ">=16.14" + } +} diff --git a/docs/sidebars.js b/docs/sidebars.js new file mode 100644 index 00000000000..205ecb76038 --- /dev/null +++ b/docs/sidebars.js @@ -0,0 +1,137 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +// @ts-check + +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const sidebars = { + sidebar: [ + { + type: 'doc', + id: 'index', + label: 'Noir', + }, + { + type: 'category', + label: 'Getting Started', + items: [{ type: 'autogenerated', dirName: 'getting_started' }], + }, + { + type: 'category', + label: 'Examples', + items: [{ type: 'autogenerated', dirName: 'examples' }], + }, + { + type: 'category', + label: 'Nargo', + items: [{ type: 'autogenerated', dirName: 'nargo' }], + }, + { + type: 'category', + label: 'Language Concepts', + items: [ + { + type: 'category', + label: 'Data Types', + link: { + type: 'doc', + id: 'language_concepts/data_types', + }, + items: [ + { + type: 'autogenerated', + dirName: 'language_concepts/data_types', + }, + ], + }, + 'language_concepts/functions', + 'language_concepts/control_flow', + 'language_concepts/ops', + 'language_concepts/assert', + 'language_concepts/unconstrained', + 'language_concepts/generics', + 'language_concepts/mutability', + 'language_concepts/lambdas', + 'language_concepts/comments', + 'language_concepts/distinct', + 'language_concepts/shadowing', + ], + }, + { + type: 'category', + label: 'Noir Standard Library', + items: [ + { + type: 'category', + label: 'Cryptographic Primitives', + link: { + type: 'doc', + id: 'standard_library/cryptographic_primitives', + }, + items: [ + { + type: 'autogenerated', + dirName: 'standard_library/cryptographic_primitives', + }, + ], + }, + 'standard_library/recursion', + 'standard_library/logging', + 'standard_library/merkle_trees', + 'standard_library/zeroed', + 'standard_library/black_box_fns', + 'standard_library/options', + ], + }, + { + type: 'category', + label: 'Modules, Packages and Crates', + items: [{ type: 'autogenerated', dirName: 'modules_packages_crates' }], + }, + { + type: 'category', + label: 'Noir JS', + link: { + type: 'doc', + id: 'noir_js/noir_js', + }, + items: [ + { + type: 'category', + label: 'Reference', + items: [ + { + type: 'autogenerated', + dirName: 'noir_js/reference', + }, + ], + }, + { + type: 'category', + label: 'Guides', + items: [ + { + type: 'autogenerated', + dirName: 'noir_js/getting_started', + }, + ], + }, + ], + }, + { + type: 'doc', + id: 'migration_notes', + label: 'Migration notes', + }, + ], +}; + +module.exports = sidebars; diff --git a/docs/src/components/GithubCode/index.js b/docs/src/components/GithubCode/index.js new file mode 100644 index 00000000000..69ba17ef791 --- /dev/null +++ b/docs/src/components/GithubCode/index.js @@ -0,0 +1,63 @@ +import React, { useEffect, useState } from 'react'; +import axios from 'axios'; +import Highlight, { defaultProps } from "prism-react-renderer"; +import github from 'prism-react-renderer/themes/github'; +//import vsDark from 'prism-react-renderer/themes/vsDark'; + +const GitHubCode = ({ owner, repo, branch = 'master', filePath, language, startLine = 1, endLine = Infinity }) => { + const [code, setCode] = useState(''); + const [response, setResponse] = useState(''); + + useEffect(() => { + const fetchCode = async () => { + const url = `https://api.github.com/repos/${owner}/${repo}/contents/${filePath}?ref=${branch}` + try { + const response = await axios.get(url); + const content = response.data.content; + const decodedContent = atob(content); // Decode Base64 content + + const lines = decodedContent.split('\n'); + const desiredLines = lines.slice(startLine - 1, endLine).join('\n').trimEnd(); + + setResponse(response); + setCode(desiredLines); + } catch (error) { + console.error('Failed to fetch GitHub code:', error); + } + }; + + fetchCode(); + }, [owner, repo, branch, filePath, startLine, endLine]); + + const highlightedCode = ( + + {({ className, style, tokens, getLineProps, getTokenProps }) => ( +
+
+                        {tokens.map((line, i) => (
+                            
+ {/* uncomment for line numbers */} + {/* {i + 1} */} + {line.map((token, key) => ( + + ))} +
+ ))} +
+ { + response.data?.html_url ? Link to source code. : '' + } +
+ )} +
+ ) + + return highlightedCode; +}; + +export default GitHubCode; \ No newline at end of file diff --git a/docs/src/components/HomepageFeatures/index.js b/docs/src/components/HomepageFeatures/index.js new file mode 100644 index 00000000000..78f410ba688 --- /dev/null +++ b/docs/src/components/HomepageFeatures/index.js @@ -0,0 +1,64 @@ +import React from 'react'; +import clsx from 'clsx'; +import styles from './styles.module.css'; + +const FeatureList = [ + { + title: 'Easy to Use', + Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, + description: ( + <> + Docusaurus was designed from the ground up to be easily installed and + used to get your website up and running quickly. + + ), + }, + { + title: 'Focus on What Matters', + Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, + description: ( + <> + Docusaurus lets you focus on your docs, and we'll do the chores. Go + ahead and move your docs into the docs directory. + + ), + }, + { + title: 'Powered by React', + Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, + description: ( + <> + Extend or customize your website layout by reusing React. Docusaurus can + be extended while reusing the same header and footer. + + ), + }, +]; + +function Feature({Svg, title, description}) { + return ( +
+
+ +
+
+

{title}

+

{description}

+
+
+ ); +} + +export default function HomepageFeatures() { + return ( +
+
+
+ {FeatureList.map((props, idx) => ( + + ))} +
+
+
+ ); +} diff --git a/docs/src/components/HomepageFeatures/styles.module.css b/docs/src/components/HomepageFeatures/styles.module.css new file mode 100644 index 00000000000..b248eb2e5de --- /dev/null +++ b/docs/src/components/HomepageFeatures/styles.module.css @@ -0,0 +1,11 @@ +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureSvg { + height: 200px; + width: 200px; +} diff --git a/docs/src/components/Notes/_blackbox.mdx b/docs/src/components/Notes/_blackbox.mdx new file mode 100644 index 00000000000..9fe9b48fbff --- /dev/null +++ b/docs/src/components/Notes/_blackbox.mdx @@ -0,0 +1,5 @@ +:::info + +This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. + +::: \ No newline at end of file diff --git a/docs/src/components/Notes/_experimental.mdx b/docs/src/components/Notes/_experimental.mdx new file mode 100644 index 00000000000..da1b0826aa1 --- /dev/null +++ b/docs/src/components/Notes/_experimental.mdx @@ -0,0 +1,6 @@ +:::caution + +This feature is experimental. You should expect it to change in future versions, +cause unexpected behavior, or simply not work at all. + +::: diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css new file mode 100644 index 00000000000..c1faa9d3139 --- /dev/null +++ b/docs/src/css/custom.css @@ -0,0 +1,70 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #9f3fff; + --ifm-color-primary-dark: #2f1f49; + --ifm-color-primary-darker: #2f1f49; + --ifm-color-primary-darkest: #2f1f49; + --ifm-color-primary-light: #9f3fff; + --ifm-color-primary-lighter: #9f3fff; + --ifm-color-primary-lightest: #9f3fff; + --search-local-highlight-color: #2f1f49; + --ifm-menu-color-background-active: #f6f8fa; + --ifm-code-font-size: 95%; + --ifm-breadcrumb-color-active: white; + --ifm-breadcrumb-item-background-active: #2f1f49; + --ifm-heading-color: #2f1f49; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #f5bda9; + --ifm-color-primary-dark: #f5bda9; + --ifm-color-primary-darker: #f5bda9; + --ifm-color-primary-darkest: #f5bda9; + --ifm-color-primary-light: #f5bda9; + --ifm-color-primary-lighter: #f5bda9; + --ifm-color-primary-lightest: #f5bda9; + + --ifm-heading-color: white; + --ifm-menu-color-background-active: #282a36; + --ifm-breadcrumb-color-active: #2f1f49; + --ifm-breadcrumb-item-background-active: #f5bda9; + + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} + +html[data-theme='dark'] { + --search-local-highlight-color: #f5bda9; + --search-local-muted-color: white; + --search-local-hit-active-color: #1b1b1d; + --search-local-hit-color: white; +} + +[data-theme='dark'] .footer { + --ifm-footer-background-color: #282a36 + --ifm-footer-color: var(--ifm-footer-link-color); + --ifm-footer-link-color: var(--ifm-color-secondary); + --ifm-footer-title-color: var(--ifm-color-white); +} + +[data-theme='light'] .navbar { + background-color: #f6fbfc; +} + +[data-theme='light'] .footer { + --ifm-footer-background-color: #f6fbfc; + --ifm-footer-color: #2f1f49; + --ifm-footer-link-color: #2f1f49; + --ifm-footer-title-color: #2f1f49; +} + +.katex-html { + display: none; +} diff --git a/docs/static/.nojekyll b/docs/static/.nojekyll new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docs/static/img/codelens_compile_execute.png b/docs/static/img/codelens_compile_execute.png new file mode 100644 index 0000000000000000000000000000000000000000..347490f529fa9b877f5a2463e11d7dbbe31ba6c4 GIT binary patch literal 5630 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�?fB0fLzpn4fEz0fH*IQjL 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 F{{uZDeU1PC literal 0 HcmV?d00001 diff --git a/docs/static/img/codelens_testing_panel.png b/docs/static/img/codelens_testing_panel.png new file mode 100644 index 0000000000000000000000000000000000000000..cec1708d405082b11b9f6eab681f88895452a46e GIT binary patch literal 18339 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 literal 0 HcmV?d00001 diff --git a/docs/static/img/favicon.ico b/docs/static/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..1c85cef482e601f1fe5e291df4e97a3aef958676 GIT binary patch literal 4286 zcmcJRv2KGf5QdEy7&=g?Qb*#kQ<4XWRK_Ig17!$p1Hj$6IXcY0Os7Ar&J z%yag+Ws^k_r?_#M-5c9%UC6S@R*$ivC6tCK>`)p8*eCL99>hI?4eM(k#@MJ{C=FBC zp)^R?zBRb8eQA)eciHlb`s@pASjyqllTvo4*Jo>RW&6-Dmpw-Vv2(DikA8Cu z^uuy)E3Wvr5`~{C6m+4|1HBSaVqz)1=1Ki7{1dOc5Cq73Mdt zjz3BLeo31}lO57}vq`E$78gw#MRiidRa_+n&!U>=JmYh`hSzco$8rwN#W~yD%wQHX GiTwx67ZB?J literal 0 HcmV?d00001 diff --git a/docs/static/img/logo.svg b/docs/static/img/logo.svg new file mode 100644 index 00000000000..8095d6a169d --- /dev/null +++ b/docs/static/img/logo.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/docs/static/img/logoDark.svg b/docs/static/img/logoDark.svg new file mode 100644 index 00000000000..dee9f27a6a9 --- /dev/null +++ b/docs/static/img/logoDark.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/docs/static/img/noir_getting_started_0.png b/docs/static/img/noir_getting_started_0.png new file mode 100644 index 0000000000000000000000000000000000000000..9e1f569ceec694e3c242af6919fe9102eb0ae099 GIT binary patch literal 72108 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� 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

YRJ67x8+n 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 nF-?w|r*iH1)+)D>$E4W#aeY=%1>@ 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 Dpw;^&|GL&Mlb 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 AR{#J2 literal 0 HcmV?d00001 diff --git a/docs/versioned_docs/version-0.10.5/examples/merkle-proof.mdx b/docs/versioned_docs/version-0.10.5/examples/merkle-proof.mdx new file mode 100644 index 00000000000..6430780817c --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/examples/merkle-proof.mdx @@ -0,0 +1,48 @@ +--- +title: Merkle Proof 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] +--- + +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); + 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` +instead. + +```rust +let leaf = std::hash::hash_to_field(message); +``` + +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-0.10.5/getting_started/00_nargo_installation.md b/docs/versioned_docs/version-0.10.5/getting_started/00_nargo_installation.md new file mode 100644 index 00000000000..de30869732d --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/getting_started/00_nargo_installation.md @@ -0,0 +1,285 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, + verifying and more). Learn how to install and use Nargo for your projects with this comprehensive + guide. +keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] +--- + +`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, +verifying and more). + +Alternatively, the interactions can also be performed in [TypeScript](../typescript). + +### UltraPlonk + +Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. + +## Installation + +There are four approaches for installing Nargo: + +- [Option 1: Noirup](#option-1-noirup) +- [Option 2: Binaries](#option-2-binaries) +- [Option 3: Install via Nix](#option-3-install-via-nix) +- [Option 4: Compile from Source](#option-4-compile-from-source) + +Optionally you can also install [Noir VS Code extension] for syntax highlighting. + +### Option 1: Noirup + +If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a +terminal and run: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done, 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. + +#### GitHub Actions + +You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as +installing `noirup` and running tests in your GitHub Action `yml` file. + +See the +[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in +this repo containing hash functions in Noir for an example. + +#### Nightly versions + +To install the nightly version of Noir (updated daily) run: + +```bash +noirup -n +``` + +### Option 2: Binaries + +See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous +platform specific binaries. + +#### Step 1 + +Paste and run the following in the terminal to extract and install the binary: + +> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend +> `sudo` and re-run it. + +##### macOS (Apple Silicon) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### macOS (Intel) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### Windows (PowerShell) + +Open PowerShell as Administrator and run: + +```powershell +mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` +Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` +Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` +$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` +$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` +$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` +Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +``` + +##### Linux (Bash) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ +echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ +source ~/.bashrc +``` + +#### Step 2 + +Check if the installation was successful by running `nargo --help`. + +> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from +> Finder. Close the new terminal popped up and `nargo` should now be accessible. + +For a successful installation, you should see something similar to the following after running the +command: + +```sh +$ nargo --help + +Noir's package manager + +Usage: nargo + +Commands: + check Checks the constraint system for errors + 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 new binary project + 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 + gates Counts the occurrences of different gates in circuit + help Print this message or the help of the given subcommand(s) +``` + +### Option 3: Install via Nix + +Due to the large number of native dependencies, Noir projects can be installed via [Nix](https://nixos.org/). + +#### Installing Nix + +For the best experience, please follow these instructions to setup Nix: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +#### Install Nargo into your Nix profile + +1. Use `nix profile` to install Nargo + +```sh +nix profile install github:noir-lang/noir +``` + +### Option 4: Compile from Source + +Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. + +#### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +3. Install direnv into your Nix profile by running: + +```sh +nix profile install nixpkgs#direnv +``` + +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). + 1. For bash or zshell, add `eval "$(direnv hook bash)"` or `eval "$(direnv hook zsh)"` to your ~/.bashrc or ~/.zshrc file, respectively. +5. Restart your shell. + +#### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: + +```sh +git clone git@github.com:noir-lang/noir +``` + +> Replacing `noir` with whichever repository you want to work on. + +2. Navigate to the directory: + +```sh +cd noir +``` + +> Replacing `noir` with whichever repository you cloned. + +3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: + +```sh +direnv allow +``` + +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. + +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): + +```sh +code . +``` + +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +#### Building and testing + +Assuming you are using `direnv` to populate your environment, building and testing the project can be done +with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. + +If you want to build the entire project in an isolated sandbox, you can use Nix commands: + +1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. +2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. + +#### Without `direnv` + +If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. + +Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! + +## Uninstalling Nargo + +### Noirup + +If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` + +### Nix + +If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. + +```bash +rm ~/.nix-profile/bin/nargo +``` + +[git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git +[rust]: https://www.rust-lang.org/tools/install +[noir vs code extension]: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir +[homebrew]: https://brew.sh/ +[cmake]: https://cmake.org/install/ +[llvm]: https://llvm.org/docs/GettingStarted.html +[openmp]: https://openmp.llvm.org/ +[barretenberg]: https://github.com/AztecProtocol/barretenberg diff --git a/docs/versioned_docs/version-0.10.5/getting_started/01_hello_world.md b/docs/versioned_docs/version-0.10.5/getting_started/01_hello_world.md new file mode 100644 index 00000000000..8b4416beba1 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/getting_started/01_hello_world.md @@ -0,0 +1,147 @@ +--- +title: Create 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, + ] +--- + +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 +``` + +For Windows CMD, run: + +```sh +> mkdir "%USERPROFILE%\projects" +> cd /d "%USERPROFILE%\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_ that contains 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](../language_concepts/data_types) 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](../language_concepts/comments) 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 on 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](breakdown), we will go into more detail on each step performed. diff --git a/docs/versioned_docs/version-0.10.5/getting_started/02_breakdown.md b/docs/versioned_docs/version-0.10.5/getting_started/02_breakdown.md new file mode 100644 index 00000000000..3fa3a35766b --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/getting_started/02_breakdown.md @@ -0,0 +1,200 @@ +--- +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] +--- + +This section breaks down our hello world program in section _1.2_. We elaborate on the project +structure and what the `prove` and `verify` commands did in the previous section. + +## 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 = "noirstarter" +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](../modules_packages_crates/workspaces) will look a bit different. For example: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +#### Package section + +The package section requires 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` (optional) - specifies the version of the compiler to use. This is not currently enforced by the compiler, but will be in future versions. +- `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](../modules_packages_crates/dependencies) 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 the satisfaction of the condition (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 not equal 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 from usually external sources and +verifies the validity of the proof against it. + +Take a private asset transfer as an example: + +A user on browser as the prover would retrieve private inputs (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. + +In the [next section](language_server), we will explain how to utilize the Noir Language Server. diff --git a/docs/versioned_docs/version-0.10.5/getting_started/03_language_server.md b/docs/versioned_docs/version-0.10.5/getting_started/03_language_server.md new file mode 100644 index 00000000000..f2de55cfb7c --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/getting_started/03_language_server.md @@ -0,0 +1,36 @@ +--- +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] +--- + +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). + +When you language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, execution, and tests: + +![Compile and Execute](./../../../static/img/codelens_compile_execute.png) +![Run test](../../../static/img/codelens_run_test.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-0.10.5/index.md b/docs/versioned_docs/version-0.10.5/index.md new file mode 100644 index 00000000000..e56b24bccd8 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/index.md @@ -0,0 +1,103 @@ +--- +title: Introducing Noir +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, + ] +slug: / +--- + +This version of the book is being released with the public alpha. There will be a lot of features +that are missing in this version, however the syntax and the feel of the language will mostly be +completed. + +## What is Noir? + +Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. + +It's design choices are influenced heavily by Rust and focuses on a simple, familiar syntax. + +## Who is Noir for? + +Noir can be used for a variety of purposes. + +### Solidity Developers + +Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will +be modularised in the future; however, as of the alpha, you can use the [`nargo codegen-verifier`](./nargo/commands#nargo-codegen-verifier) command to create +a verifier contract. + +### Protocol Developers + +As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for +your stack, or maybe you simply want to use a different proving system. Since Noir does not compile +to a specific proof system, it is possible for protocol developers to replace the PLONK-based +proving system with a different proving system altogether. + +### Blockchain developers + +As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the +proving system and smart contract language has been pre-defined). In order for you to use Noir in +your blockchain, a proving system backend and a smart contract interface +must be implemented for it. + +## What's new about Noir? + +Noir is simple and flexible in its design, as it does not compile immediately to a fixed +NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled +to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). + +This in itself brings up a few challenges within the design process, but allows one to decouple the programming language completely from the backend. This is similar in theory to LLVM. + +## Current Features + +Compiler: + +- Module System +- For expressions +- Arrays +- Bit Operations +- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Unsigned integers +- If statements +- Structures and Tuples +- Generics + +ACIR Supported OPCODES: + +- Sha256 +- Blake2s +- Schnorr signature verification +- MerkleMembership +- Pedersen +- HashToField + +## 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 + +See the section on [dependencies](./modules_packages_crates/dependencies) for more information. diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/01_functions.md b/docs/versioned_docs/version-0.10.5/language_concepts/01_functions.md new file mode 100644 index 00000000000..7cb43c4c5f2 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/01_functions.md @@ -0,0 +1,99 @@ +--- +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] +--- + +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() {} +``` + +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 : pub 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 : pub Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## 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); +``` + +## 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](./08_lambdas.md) for more details. diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/02_control_flow.md b/docs/versioned_docs/version-0.10.5/language_concepts/02_control_flow.md new file mode 100644 index 00000000000..691c514d9a8 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/02_control_flow.md @@ -0,0 +1,42 @@ +--- +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] +--- + +## 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 +}; +``` + +## 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); +``` diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/03_ops.md b/docs/versioned_docs/version-0.10.5/language_concepts/03_ops.md new file mode 100644 index 00000000000..da02b126059 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/03_ops.md @@ -0,0 +1,97 @@ +--- +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, + ] +--- + +# 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 indentically 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-0.10.5/language_concepts/04_assert.md b/docs/versioned_docs/version-0.10.5/language_concepts/04_assert.md new file mode 100644 index 00000000000..a25a946123d --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/04_assert.md @@ -0,0 +1,34 @@ +--- +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] +--- + +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); +} +``` + +The above snippet compiles because `==` is a predicate operation. Conversely, the following will not +compile: + +```rust +// INCORRECT + +fn main(x : Field, y : Field) { + assert(x + y); +} +``` + +> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should +> equate to `x + y == 0` or if it should check the truthiness of the result. diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/05_unconstrained.md b/docs/versioned_docs/version-0.10.5/language_concepts/05_unconstrained.md new file mode 100644 index 00000000000..6b621eda3eb --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/05_unconstrained.md @@ -0,0 +1,96 @@ +--- +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] +--- + + + +Unconstrained functions are functions which do not constrain any of the included computation and allow for non-determinisitic 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 XOR 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. diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/06_generics.md b/docs/versioned_docs/version-0.10.5/language_concepts/06_generics.md new file mode 100644 index 00000000000..b700bd5bc5b --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/06_generics.md @@ -0,0 +1,113 @@ +--- +title: Generics +description: Learn how to use Generics in Noir +keywords: [Noir, Rust, generics, functions, structs] +--- + +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 new(value: T) -> Self { + Self { value, count: 1 } + } + + fn increment(mut repeated: Self) -> Self { + repeated.count += 1; + repeated + } + + fn print(self) { + for _i in 0 .. self.count { + dep::std::println(self.value); + } + } +} + +fn main() { + let mut repeated = RepeatedValue::new("Hello!"); + repeated = repeated.increment(); + 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 + +Unlike Rust, Noir does not have traits, so how can one translate the equivalent of a trait bound in +Rust into Noir? That is, how can we write a function that is generic over some type `T`, while also +requiring there is a function like `eq: fn(T, T) -> bool` that works on the type? + +The answer is that we can translate this by passing in the function manually. Here's an example of +implementing array equality in Noir: + +```rust +fn array_eq(array1: [T; N], array2: [T; N], elem_eq: fn(T, T) -> bool) -> bool { + if array1.len() != array2.len() { + false + } else { + let mut result = true; + for i in 0 .. array1.len() { + result &= elem_eq(array1[i], array2[i]); + } + result + } +} + +fn main() { + assert(array_eq([1, 2, 3], [1, 2, 3], |a, b| a == b)); + + // We can use array_eq even for arrays of structs, as long as we have + // an equality function for these structs we can pass in + let array = [MyStruct::new(), MyStruct::new()]; + assert(array_eq(array, array, MyStruct::eq)); +} +``` + +You can see an example of generics in the tests +[here](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/generics/src/main.nr). diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/07_mutability.md b/docs/versioned_docs/version-0.10.5/language_concepts/07_mutability.md new file mode 100644 index 00000000000..4641521b1d9 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/07_mutability.md @@ -0,0 +1,92 @@ +--- +title: Mutability +description: + Learn about mutable variables, constants, and globals in Noir programming language. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +--- + +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() -> Field { + let x = 3; + helper(x); + x // x is still 3 +} + +fn helper(mut x: i32) { + x = 4; +} +``` + +## Comptime Values + +:::warning + +The 'comptime' keyword was removed in version 0.10. The comptime keyword and syntax are currently still kept and parsed for backwards compatibility, but are now deprecated and will issue a warning when used. `comptime` has been removed because it is no longer needed for accessing arrays. + +::: + +## Globals + +Noir also supports global variables. However, they must be known at compile-time. The global type can also be inferred by the compiler entirely. Globals can also be used to specify array +annotations for function parameters and can be imported from submodules. + +```rust +global N: Field = 5; // Same as `global N: Field = 5` + +fn main(x : Field, y : [Field; N]) { + let res = x * N; + + assert(res == y[0]); + + let res2 = x * mysubmodule::N; + assert(res != res2); +} + +mod mysubmodule { + use dep::std; + + global N: Field = 10; + + fn my_helper() -> Field { + let x = N; + x + } +} +``` + +## Why only local mutability? + +Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting +without applying additional overhead to the user. Modeling a mutable reference is not as +straightforward as on conventional architectures and would incur some possibly unexpected overhead. diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/08_lambdas.md b/docs/versioned_docs/version-0.10.5/language_concepts/08_lambdas.md new file mode 100644 index 00000000000..ae1e6aecab1 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/08_lambdas.md @@ -0,0 +1,80 @@ +--- +title: Lambdas +description: Learn how to use anonymous functions in Noir programming language. +keywords: [Noir programming language, lambda, closure, function, anonymous function] +--- + +## 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-0.10.5/language_concepts/09_comments.md b/docs/versioned_docs/version-0.10.5/language_concepts/09_comments.md new file mode 100644 index 00000000000..3bb4d2f25a4 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/09_comments.md @@ -0,0 +1,32 @@ +--- +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] +--- + +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-0.10.5/language_concepts/10_distinct.md b/docs/versioned_docs/version-0.10.5/language_concepts/10_distinct.md new file mode 100644 index 00000000000..e7ff7f5017a --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/10_distinct.md @@ -0,0 +1,63 @@ +--- +title: Distinct Witnesses +--- + +The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures +that the witnesses being returned as public inputs are all unique. + +The `distinct` keyword is only used for return values on program entry points (usually the `main()` +function). + +When using `distinct` and `pub` simultaneously, `distinct` comes first. See the example below. + +You can read more about the problem this solves +[here](https://github.com/noir-lang/noir/issues/1183). + +## Example + +Without the `distinct` keyword, the following program + +```rust +fn main(x : pub Field, y : pub Field) -> pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + "return_witnesses": [3, 2, 4, 4] + } +} +``` + +Whereas (with the `distinct` keyword) + +```rust +fn main(x : pub Field, y : pub Field) -> distinct pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + //... + "return_witnesses": [3, 4, 5, 6] + } +} +``` diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/11_shadowing.md b/docs/versioned_docs/version-0.10.5/language_concepts/11_shadowing.md new file mode 100644 index 00000000000..efd743e764f --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/11_shadowing.md @@ -0,0 +1,43 @@ +--- +title: Shadowing +--- + +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-0.10.5/language_concepts/data_types.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types.md new file mode 100644 index 00000000000..d546cc463a8 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types.md @@ -0,0 +1,96 @@ +--- +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](./06_generics.md): + +```rust +type Id = Size; + +fn main() { + let id: Id = 1; + let zero: u32 = 0; + assert(zero + 1 == id); +} +``` + +### BigInt + +You can acheive BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/data_types/00_fields.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/00_fields.md new file mode 100644 index 00000000000..658a0441ffb --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/00_fields.md @@ -0,0 +1,165 @@ +--- +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, + ] +--- + +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; N] +``` + +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; N] +``` + +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); +} +``` + +### 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 +``` diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/data_types/01_integers.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/01_integers.md new file mode 100644 index 00000000000..d9c5e20e795 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/01_integers.md @@ -0,0 +1,33 @@ +--- +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, + ] +--- + +An integer type is a range constrained field type. The Noir frontend currently supports unsigned, +arbitrary-sized integer types. + +An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by +its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of +$\\([0,2^{32}-1]\\)$: + +```rust +fn main(x : Field, y : u32) { + let z = x as u32 + y; +} +``` + +`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` +are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created +will be rejected by the verifier. + +> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) +> sized integer types. diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/data_types/02_booleans.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/02_booleans.md new file mode 100644 index 00000000000..885db167d83 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/02_booleans.md @@ -0,0 +1,30 @@ +--- +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, + ] +--- + + +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-0.10.5/language_concepts/data_types/03_strings.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/03_strings.md new file mode 100644 index 00000000000..ee69853bfba --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/03_strings.md @@ -0,0 +1,43 @@ +--- +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, + ] +--- + + +The string type is a fixed length value defined with `str`. + +You can use strings in `assert()` functions or print them with +`std::println()`. See more about [Logging](../../standard_library/logging). + +```rust +use dep::std; + +fn main(message : pub str<11>, hex_as_string : str<4>) { + std::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)); +} +``` diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/data_types/04_arrays.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/04_arrays.md new file mode 100644 index 00000000000..f826b39bf39 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/04_arrays.md @@ -0,0 +1,237 @@ +--- +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, + ] +--- + +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() +``` + +## 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: + +### len + +Returns the length of an array + +```rust +fn len(_array: [T; N]) -> comptime 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(_array: [T; N]) -> [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(mut a: [T; N], 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(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(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(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(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(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-0.10.5/language_concepts/data_types/05_slices.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/05_slices.md new file mode 100644 index 00000000000..bc7f5c531e7 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/05_slices.md @@ -0,0 +1,157 @@ +--- +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, + ] +--- + +:::caution + +This feature is experimental. You should expect it to change in future versions, +cause unexpected behavior, or simply not work at all. + +::: + +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() +} +``` + +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); +``` diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/data_types/06_vectors.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/06_vectors.md new file mode 100644 index 00000000000..c5b74c877f8 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/06_vectors.md @@ -0,0 +1,34 @@ +--- +title: Vectors +description: + Delve into the Vector 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, + ] +--- + +:::caution + +This feature is experimental. You should expect it to change in future versions, +cause unexpected behavior, or simply not work at all. + +::: + +A vector is a collection type similar to Rust's Vector type. It's convenient way to use slices as mutable arrays. + +Example: + +```rust +use dep::std::collections::vec::Vec; + +let mut vector: Vec = Vec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +``` diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/data_types/07_tuples.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/07_tuples.md new file mode 100644 index 00000000000..5f6cab974a8 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/07_tuples.md @@ -0,0 +1,47 @@ +--- +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, + ] +--- + +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-0.10.5/language_concepts/data_types/08_structs.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/08_structs.md new file mode 100644 index 00000000000..85649dfb389 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/08_structs.md @@ -0,0 +1,73 @@ +--- +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, + ] +--- + +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. + +:::note +You can use Structs as inputs to the `main` function, but you can't output them +::: diff --git a/docs/versioned_docs/version-0.10.5/language_concepts/data_types/09_references.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/09_references.md new file mode 100644 index 00000000000..b0c35ce2cb9 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/09_references.md @@ -0,0 +1,22 @@ +--- +title: References +--- + +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-0.10.5/language_concepts/data_types/10_function_types.md b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/10_function_types.md new file mode 100644 index 00000000000..1ec92efd594 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/language_concepts/data_types/10_function_types.md @@ -0,0 +1,25 @@ +--- +title: Function types +--- + +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](../08_lambdas.md) for more details. diff --git a/docs/versioned_docs/version-0.10.5/modules_packages_crates/crates_and_packages.md b/docs/versioned_docs/version-0.10.5/modules_packages_crates/crates_and_packages.md new file mode 100644 index 00000000000..fb83a33d94e --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/modules_packages_crates/crates_and_packages.md @@ -0,0 +1,42 @@ +--- +title: Crates and Packages +description: Learn how to use Crates and Packages in your Noir project +keywords: [Nargo, dependencies, package management, crates, package] +--- + +## 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/yarn-project/noir-contracts/src/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-0.10.5/modules_packages_crates/dependencies.md b/docs/versioned_docs/version-0.10.5/modules_packages_crates/dependencies.md new file mode 100644 index 00000000000..9e6463801b7 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/modules_packages_crates/dependencies.md @@ -0,0 +1,123 @@ +--- +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] +--- + +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 = "yarn-project/noir-contracts/src/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 +└── liba + β”œβ”€β”€ Nargo.toml + └── src + └── lib.nr +``` + +Inside of the binary crate, you can specify: + +```toml +# Nargo.toml + +[dependencies] +libA = { path = "../liba" } +``` + +## 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 liba referenced above: + +```rust +use dep::ecrecover; +use dep::libA; +``` + +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; +``` + +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-0.10.5/modules_packages_crates/modules.md b/docs/versioned_docs/version-0.10.5/modules_packages_crates/modules.md new file mode 100644 index 00000000000..147c9b284e8 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/modules_packages_crates/modules.md @@ -0,0 +1,104 @@ +--- +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] +--- + +Noir's module system follows the same convention as the _newer_ version of Rust's module system. + +## Purpose of Modules + +Modules are used to organise 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-0.10.5/modules_packages_crates/workspaces.md b/docs/versioned_docs/version-0.10.5/modules_packages_crates/workspaces.md new file mode 100644 index 00000000000..eaa09506698 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/modules_packages_crates/workspaces.md @@ -0,0 +1,39 @@ +--- +title: Workspaces +--- + +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 +β”‚Β Β  β”‚Β Β  └── src +β”‚Β Β  β”‚Β Β  └── main.nr +β”‚Β Β  └── b +β”‚Β Β  β”œβ”€β”€ Nargo.toml +β”‚Β Β  └── src +β”‚Β Β  └── main.nr +β”œβ”€β”€ Nargo.toml +└── Prover.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. We just don't have a way to consume libraries from inside a workspace as external dependencies right now. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. diff --git a/docs/versioned_docs/version-0.10.5/nargo/01_commands.md b/docs/versioned_docs/version-0.10.5/nargo/01_commands.md new file mode 100644 index 00000000000..425a73a34c8 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/nargo/01_commands.md @@ -0,0 +1,223 @@ +--- +title: Commands +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, + ] +--- + +## General options + +``` +Options: + --show-ssa Emit debug information for the intermediate SSA IR + --deny-warnings Quit execution when warnings are emitted + -h, --help Print help +``` + +## `nargo help [subcommand]` + +Prints the list of available commands or specific information of a subcommand. + +_Arguments_ + +- `` - The subcommand whose help message to display + +## `nargo check` + +Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output +values of the Noir program respectively. + +**Options** + +``` + --package The name of the package to check + --workspace Check all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo codegen-verifier` + +Generate a Solidity verifier smart contract for the program. + +**Options** + +``` + --package The name of the package to codegen + --workspace Codegen all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo compile` + +Compile the program into a JSON build artifact file containing the ACIR representation and the ABI +of the circuit. This build artifact can then be used to generate and verify proofs. + +You can also use "build" as an alias for compile (e.g. `nargo build`). + +**Options** + +``` + --include-keys Include Proving and Verification keys in the build artifacts + --package The name of the package to compile + --workspace Compile all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo new ` + +Creates a new Noir project in a new folder. + +**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 +-h, --help Print help +``` + +## `nargo init` + +Creates a new Noir project in the current directory. + +**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 +-h, --help Print help +``` + +## `nargo execute [WITNESS_NAME]` + +Runs the Noir program and prints its return value. + +**Arguments** + +``` +[WITNESS_NAME] 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: Prover] + --package The name of the package to execute + --workspace Execute all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +_Usage_ + +The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which +must be filled in. + +To save the witness to file, run the command with a value for the `WITNESS_NAME` argument. A +`.tr` file will then be saved in the `./target` folder. + +> **Info:** The `.tr` file is the witness file. The witness file can be considered as program inputs +> parsed for your program's ACIR. +> +> This file can be passed along with circuit's ACIR into a TypeScript project for proving and +> verification. See the [TypeScript](../typescript#proving-and-verifying-externally-compiled-files) +> section to learn more. + +## `nargo prove` + +Creates a proof for the program. + +**Options** + +``` +-p, --prover-name The name of the toml file which contains the inputs for the prover [default: Prover] +-v, --verifier-name The name of the toml file which contains the inputs for the verifier [default: Verifier] + --verify Verify proof after proving + --package The name of the package to prove + --workspace Prove all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo verify` + +Given a proof and a program, verify whether the proof is valid. + +**Options** + +``` +-v, --verifier-name The name of the toml file which contains the inputs for the verifier [default: Verifier] + --package The name of the package verify + --workspace Verify all packages in the workspace + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo test [TEST_NAME]` + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. To print `println` statements in tests, use the `--show-output` flag. + +Takes an optional `--exact` flag which allows you to select tests based on an exact name. + +See an example on the [testing page](./testing). + +**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 + --print-acir Display the ACIR for compiled circuit + --deny-warnings Treat all warnings as errors +-h, --help Print help +``` + +## `nargo info` + +Prints a table containing the information of the package. + +Currently the table provide + +1. The number of ACIR opcodes +2. The final number gates in the circuit used by a backend + +If the file contains a contract the table will provide the +above information about each function of the contract. + +## `nargo lsp` + +Start a long-running Language Server process that communicates over stdin/stdout. +Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). diff --git a/docs/versioned_docs/version-0.10.5/nargo/02_testing.md b/docs/versioned_docs/version-0.10.5/nargo/02_testing.md new file mode 100644 index 00000000000..106952c44c0 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/nargo/02_testing.md @@ -0,0 +1,42 @@ +--- +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] +--- + +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 the all +the contraints 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); +} +``` diff --git a/docs/versioned_docs/version-0.10.5/nargo/03_solidity_verifier.md b/docs/versioned_docs/version-0.10.5/nargo/03_solidity_verifier.md new file mode 100644 index 00000000000..9ac60cb0ba7 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/nargo/03_solidity_verifier.md @@ -0,0 +1,129 @@ +--- +title: 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, + ] +--- + +For certain applications, it may be desirable to run the verifier as a smart contract instead of on +a local machine. + +Compile a Solidity verifier contract for your Noir program by running: + +```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 on any EVM blockchain acting as a verifier smart contract. + +> **Note:** It is possible to compile 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 compilation of verifier contracts in +> Solidity only for the time being. + +## Verify + +To verify a proof using the Solidity verifier contract, call the `verify` function with the +following signature: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +You can see an example of how the `verify` function is called 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"); +``` + +### Public Inputs + +:::tip + +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. + +::: + +The verifier contract uses the output (return) value of a Noir program as a public input. So if you +have the following function + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +then `verify` in `plonk_vk.sol` will expect 3 public inputs. Passing two inputs will result in an +error like `Reason: PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case the 3 inputs to `verify` would be ordered as `[pubkey_x, pubkey_y, return]`. + +#### Struct inputs + +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) { + //... +} +``` + +Structs will be flattened so that the array of inputs is 1-dimensional array. The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +## Noir for EVM chains + +You can currently deploy the Solidity verifier contracts to most EVM compatible chains. EVM chains that have been tested and are known to work include: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +Other EVM chains should work, but have not been tested directly by our team. 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. + +### Unsupported chains + +Unfortunately not all "EVM" chains are supported. + +**zkSync** and the **Polygon zkEVM** do _not_ currently support proof verification via Solidity verifier contracts. They are missing the bn256 precompile contract that the verifier contract requires. Once these chains support this precompile, they may work. diff --git a/docs/versioned_docs/version-0.10.5/standard_library/black_box_fns.md b/docs/versioned_docs/version-0.10.5/standard_library/black_box_fns.md new file mode 100644 index 00000000000..c758846b688 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/black_box_fns.md @@ -0,0 +1,45 @@ +--- +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. + +:::warning + +It is likely that not all backends will support a particular black box function. + +::: + +Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. + +Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: + +```rust +#[foreign(sha256)] +fn sha256(_input : [u8; N]) -> [u8; 32] {} +``` + +## Function list + +Here is a list of the current black box functions that are supported by UltraPlonk: + +- AES +- [SHA256](./cryptographic_primitives/hashes#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr) +- [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Pedersen](./cryptographic_primitives/hashes#pedersen) +- [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [Compute merkle root](./merkle_trees#compute_merkle_root) +- AND +- XOR +- RANGE +- [Keccak256](./cryptographic_primitives/hashes#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. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. + +You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/acvm/blob/acir-v0.12.0/acir/src/circuit/black_box_functions.rs). diff --git a/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives.md b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives.md new file mode 100644 index 00000000000..2df4f929474 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives.md @@ -0,0 +1,14 @@ +--- +title: Cryptographic primitives in Noir +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-0.10.5/standard_library/cryptographic_primitives/00_hashes.mdx b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/00_hashes.mdx new file mode 100644 index 00000000000..1d9b1c7f09c --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/00_hashes.mdx @@ -0,0 +1,146 @@ +--- +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] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +## sha256 + +Given an array of bytes, returns the resulting sha256 hash. + +```rust +fn sha256(_input : [u8]) -> [u8; 32] +``` + +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 +fn blake2s(_input : [u8]) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::blake2s(x); +} +``` + + + +## pedersen + +Given an array of Fields, returns the Pedersen hash. + +```rust +fn pedersen(_input : [Field]) -> [Field; 2] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::pedersen(x); +} +``` + + + +## 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 +fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let message_size = 4; + let hash = std::hash::keccak256(x, message_size); +} +``` + + + +## 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 +fn main() +{ + let hash1 = std::hash::poseidon::bn254::hash_2([1, 2]); + assert(hash1 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); +} +``` + +## 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_bn254(x); +} +``` + +## hash_to_field + +```rust +fn hash_to_field(_input : [Field; N]) -> 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-0.10.5/standard_library/cryptographic_primitives/01_scalar.mdx b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/01_scalar.mdx new file mode 100644 index 00000000000..62265cddb1e --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/01_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, + ] +--- + +import BlackBoxInfo from './common/\_blackbox.mdx'; + +## scalar_mul::fixed_base + +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 +fn fixed_base(_input : Field) -> [Field; 2] +``` + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base(x); + std::println(scal); +} +``` + + diff --git a/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/02_schnorr.mdx b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/02_schnorr.mdx new file mode 100644 index 00000000000..0e219c0e5ff --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/02_schnorr.mdx @@ -0,0 +1,37 @@ +--- +title: Schnorr Signatures +description: Learn how you can verify Schnorr signatures using Noir +keywords: [cryptographic primitives, Noir project, schnorr, signatures] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +## schnorr::verify_signature + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). + +```rust +fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool +``` + +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() +); + +... +``` + + diff --git a/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx new file mode 100644 index 00000000000..3934a0338d0 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx @@ -0,0 +1,45 @@ +--- +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] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 curves. + +## ecdsa_secp256k1::verify_signature + +Verifier for ECDSA Secp256k1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + +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_secp256r1::verify_signature + +Verifier for ECDSA Secp256r1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + +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); +} +``` + + diff --git a/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/04_ec_primitives.md b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/04_ec_primitives.md new file mode 100644 index 00000000000..6e6b19b6861 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -0,0 +1,101 @@ +--- +title: Elliptic Curve Primitives +keywords: [cryptographic primitives, Noir project] +--- + +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/crates/nargo_cli/tests/test_data/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-0.10.5/standard_library/cryptographic_primitives/05_eddsa.mdx b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/05_eddsa.mdx new file mode 100644 index 00000000000..8f060ed3316 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/05_eddsa.mdx @@ -0,0 +1,17 @@ +--- +title: EdDSA Verification +description: Learn about the cryptographic primitives regarding EdDSA +keywords: [cryptographic primitives, Noir project, eddsa, signatures] +--- + +import BlackBoxInfo from './common/_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 +``` + + diff --git a/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/common/_blackbox.mdx b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/common/_blackbox.mdx new file mode 100644 index 00000000000..9fe9b48fbff --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/cryptographic_primitives/common/_blackbox.mdx @@ -0,0 +1,5 @@ +:::info + +This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. + +::: \ No newline at end of file diff --git a/docs/versioned_docs/version-0.10.5/standard_library/logging.md b/docs/versioned_docs/version-0.10.5/standard_library/logging.md new file mode 100644 index 00000000000..7e2fd9b9aff --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/logging.md @@ -0,0 +1,62 @@ +--- +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, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +The standard library provides a familiar `println` statement you can use. Despite being a limited +implementation of rust's `println!` macro, this construct can be useful for debugging. + +You can print the output of println statements in your Noir code by using the `nargo execute` command or the `--show-output` flag when using `nargo test` (provided there are println statements in your tests). + +It is recommended to use `nargo execute` if you want to debug failing constrains with `println` 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). `println` will not work for failed constraints caught at compile time. + +The `println` statement is unconstrained, so it works for outputting integers, fields, strings, and even structs or expressions. For example: + +```rust +use dep::std; + +struct Person { + age : Field, + height : Field, +} + +fn main(age : Field, height : Field) { + let person = Person { age : age, height : height }; + std::println(person); + std::println(age + height); + std::println("Hello world!"); +} + +``` + +You can print multiple different types in the same statement and string as well as a new "fmtstr" type. A `fmtstr` can be specified in the same way as a normal string it just should be prepended with an "f" character: + +```rust + let fmt_str = f"i: {i}, j: {j}"; + std::println(fmt_str); + + let s = myStruct { y: x, x: y }; + std::println(s); + + std::println(f"i: {i}, s: {s}"); + + std::println(x); + std::println([x, y]); + + let foo = fooStruct { my_struct: s, foo: 15 }; + std::println(f"s: {s}, foo: {foo}"); +``` diff --git a/docs/versioned_docs/version-0.10.5/standard_library/merkle_trees.md b/docs/versioned_docs/version-0.10.5/standard_library/merkle_trees.md new file mode 100644 index 00000000000..57d8c4a9e4f --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/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/00_hashes.mdx#pedersen). + +```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(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); + std::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-0.10.5/standard_library/options.md b/docs/versioned_docs/version-0.10.5/standard_library/options.md new file mode 100644 index 00000000000..3d3139fb98b --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/options.md @@ -0,0 +1,99 @@ +--- +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), +} +``` + +You can import the Option type into your Noir program like so: + +```rust +use dep::std::option::Option; + +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. + +### 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-0.10.5/standard_library/recursion.md b/docs/versioned_docs/version-0.10.5/standard_library/recursion.md new file mode 100644 index 00000000000..4705ae6c575 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/recursion.md @@ -0,0 +1,96 @@ +--- +title: Recursive Proofs +description: Learn about how to write recursive proofs in Noir. +keywords: [recursion, recursive proofs, verification_key, aggregation object, 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. + +The `verify_proof` function takes a verification key, proof and public inputs for a zk program, as well as a key hash and an input aggregation object. The key hash is used to check the validity of the verification key and the input aggregation object is required by some proving systems. The `verify_proof` function returns an output aggregation object that can then be fed into future iterations of the proof verification if required. + +```rust +#[foreign(verify_proof)] +fn verify_proof(_verification_key : [Field], _proof : [Field], _public_input : Field, _key_hash : Field, _input_aggregation_object : [Field]) -> [Field] {} +``` + +:::info + +This is a black box function. Read [this section](./black_box_fns) to learn more about black box functions in Noir. + +::: + +## Aggregation Object + +The purpose of the input aggregation object is a little less clear though (and the output aggregation object that is returned from the `std::verify_proof` method). 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. In the case of PLONK the recursive aggregation object is two G1 points (expressed as 16 witness values). The final verifier (in our case this is most often the smart contract verifier) has to be aware of this aggregation object to execute a pairing and check the validity of these points (thus completing the recursive verification). + +So for example in this circuit: + +```rust +use dep::std; + +fn main( + verification_key : [Field; 114], + proof : [Field; 94], + public_inputs : [Field; 1], + key_hash : Field, + input_aggregation_object : [Field; 16], + proof_b : [Field; 94], +) -> pub [Field; 16] { + let output_aggregation_object_a = std::verify_proof( + verification_key, + proof, + public_inputs, + key_hash, + input_aggregation_object + ); + + let output_aggregation_object = std::verify_proof( + verification_key, + proof_b, + public_inputs, + key_hash, + output_aggregation_object_a + ); + + let mut output = [0; 16]; + for i in 0..16 { + output[i] = output_aggregation_object[i]; + } + output +} +``` + +In this example we have a circuit, that generates proofs A and B, that is being verified in circuit C. Assuming that the proof being passed in is not already a recursive proof, the `input_aggregation_object` will be all zeros. It will then generate an `output_aggregation_object`. This blob of data then becomes the `input_aggregation_object` of the next recursive aggregation we wish to compute. We can see here as the same public inputs, verification key, and key hash are used that we are verifying two proofs generated from the same circuit in this single circuit. `std::verify_proof` returns a `[Field]` because the size of an aggregation object is proof system dependent--in barretenberg, aggregation objects are two G1 points, while in Halo2, the aggregation object is a list of G1 points that is log the circuit size. So for the final step we convert the slice into an array of size 16 because we are generating proofs using UltraPlonk. + +## 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. They should be checked against in the circuit after construction of a new aggregation state. + +### `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. + +### `input_aggregation_object` + +An aggregation object is blob of data that the top-level verifier must run some proof system specific algorithm on to complete verification. The size is proof system specific and will be set by the backend integrating this opcode. The input aggregation object is only not `None` when we are verifying a previous recursive aggregation in the current circuit. If this is the first recursive aggregation there is no input aggregation object. It is left to the backend to determine how to handle when there is no input aggregation object. + +## Return value + +### `output_aggregation_object` + +This is the result of a recursive aggregation and is what will be fed into the next verifier. +The next verifier can either perform a final verification (returning true or false) or perform another recursive aggregation where this output aggregation object will be the input aggregation object of the next recursive aggregation. + +## Example + +You can see an example of how to do recursive proofs in [this example recursion demo repo](https://github.com/Savio-Sou/recursion-demo/tree/main). diff --git a/docs/versioned_docs/version-0.10.5/standard_library/zeroed.md b/docs/versioned_docs/version-0.10.5/standard_library/zeroed.md new file mode 100644 index 00000000000..97dab02dac2 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/standard_library/zeroed.md @@ -0,0 +1,25 @@ +--- +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 +- String +- Tuple +- Function + +Using it on other types could result in unexpected behavior. diff --git a/docs/versioned_docs/version-0.10.5/typescript.md b/docs/versioned_docs/version-0.10.5/typescript.md new file mode 100644 index 00000000000..258a2160e92 --- /dev/null +++ b/docs/versioned_docs/version-0.10.5/typescript.md @@ -0,0 +1,237 @@ +--- +title: Working with TypeScript +description: + Learn how to interact with Noir programs using TypeScript. Follow this tutorial to compile your + program, specify inputs, initialize a prover & verifier, and prove and verify your program. +keywords: [TypeScript, Noir, tutorial, compile, inputs, prover, verifier, proof] +--- + +Interactions with Noir programs can also be performed in TypeScript, which can come in handy when +writing tests or when working in TypeScript-based projects like [Hardhat](https://hardhat.org/). + +You can check the complete code for this tutorial here: [browser with next.js](https://github.com/signorecello/noir-min-browser-example) and [node.js](https://github.com/signorecello/noir-min-nodejs-example). If you want just a browser boilerplate to start with, check out the [noir-starter](https://github.com/noir-lang/noir-starter) for an example implementation. + +:::note + +You may find unexpected errors working with some frameworks such as `vite`. This is due to the +nature of `wasm` files and the way Noir uses web workers. As we figure it out, we suggest using +[Create React App](https://create-react-app.dev/), or [Next.js](https://nextjs.org/) for a quick +start. + +::: + +## Setup + +Make sure you are using Noir version >= 0.10.1. + +You can check your current version by running `nargo --version`. + +See the [Installation page](./getting_started/nargo_installation) for more info. + +We're assuming you're using ES6 and ESM for both browser (for example with React), or nodejs. Install [Node.js](https://nodejs.org/en). Init a new project with `npm init` and add `"type": "module"` to your `package.json`, to let `node` know we're using the new ESM sytem: + +```json +{ + "type": "module" + // the rest of your package.json +} +``` + +Install Noir dependencies in your project by running: + +```bash +npm i @aztec/bb.js@0.3.6 https://git@github.com/noir-lang/acvm-simulator-wasm.git#b9d9ca9dfc5140839f23998d9466307215607c42 fflate ethers@5.7.2 +``` + +This will install the `acvm-simulator` that will generate our witness, and the proving backend barretenberg `bb.js`. + +We're also installing `ethers` because we're too lazy to write a function that pads public inputs with 32bytes, and `fflate` to help us decompress our circuit bytecode. + +Since we're with typescript and using `nodejs` types, we also recommend to install the `@types/node` package, otherwise your IDE will scream at you. + +```bash +npm i --save-dev @types/node +``` + +:::note + +While Noir is in rapid development, some packages could interfere with others. For that reason, you +should use these specified versions. Let us know if for some reason you need to use other ones. + +::: + +As for the circuit, run `nargo init` to create a new Noir project. + +We will use a Standard Noir Example and place it in the `src` folder. This program simply multiplies input `x` with input `y` and returns the result `z`. The verifier doesn't know the value of `x`: we're proving that we know it without making it public. + +```rust +// src/main.nr +fn main(x: u32, y: pub u32) -> pub u32 { + let z = x * y; + z +} +``` + +One valid scenario for proving could be `x = 3`, `y = 4` and `return = 12` + +## Compiling + +In order to start proving, we need to compile our circuit into the intermediate representation used by our backend. As of today, you have to do that with `nargo`. Just hop to your circuits folder and run `nargo compile`. + +:::info + +At this time, you need to use a nightly version of nargo. Using [noirup](./getting_started/00_nargo_installation.md#option-1-noirup) you can do this simply by running `noirup -n`. + +::: + +You should have a `json` file in `target/` with your circuit's bytecode. The json file is name based on the project name specified in Nargo.toml, so for a project named "test", it will be at `target/test.json`. You can then import that file normally. + +```ts +import circuit from '../target/test.json' assert { type: 'json' }; +``` + +## Decompressing the circuit + +The compiled circuit comes compressed. We need to decompress it, that's where `fflate` comes in. + +```ts +import { decompressSync } from 'fflate'; + +const acirBuffer = Buffer.from(circuit.bytecode, 'base64'); +const acirBufferUncompressed = decompressSync(acirBuffer); +``` + +From here, it's highly recommended you store `acirBuffer` and `acirBufferUncompressed` close by, as they will be used for witness generation and proving. + +## Initializing ACVM and BB.JS + +:::note + +This step will eventually be abstracted away as Noir tooling matures. For now, you should be fine just literally copy-pasting most of this into your own code. + +::: + +Before proving, `bb.js` needs to be initialized. We need to import some functions and use them + +```ts +import { Crs, newBarretenbergApiAsync, RawBuffer } from '@aztec/bb.js/dest/node/index.js'; + +const api = await newBarretenbergApiAsync(4); + +const [exact, circuitSize, subgroup] = await api.acirGetCircuitSizes(acirBufferUncompressed); +const subgroupSize = Math.pow(2, Math.ceil(Math.log2(circuitSize))); +const crs = await Crs.new(subgroupSize + 1); +await api.commonInitSlabAllocator(subgroupSize); +await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); + +const acirComposer = await api.acirNewAcirComposer(subgroupSize); +``` + +We should take two very useful objects from here: `api` and `acirComposer`. Make sure to keep these close by! + +:::info + +On the browser, you also need to init the ACVM. You can do that by importing it and calling it like: + +```ts +import initACVM, { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; + +await initACVM(); +// the rest of your code +``` + +::: + +## Generating witnesses + +Witness generation is what allows us to prove with arbitrary inputs (like user inputs on a form, game, etc). In this example, our input is a simple object with our circuit inputs `x`, `y`, and return `z` (fun fact: the return value in Noir is actually a public input!). We're wrapping it in a function, so it can be conveniently called later on. + +```ts +import { ethers } from 'ethers'; // I'm lazy so I'm using ethers to pad my input +import { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; + +async function generateWitness(input: any, acirBuffer: Buffer): Promise { + const initialWitness = new Map(); + initialWitness.set(1, ethers.utils.hexZeroPad(`0x${input.x.toString(16)}`, 32)); + initialWitness.set(2, ethers.utils.hexZeroPad(`0x${input.y.toString(16)}`, 32)); + + const witnessMap = await executeCircuit(acirBuffer, initialWitness, () => { + throw Error('unexpected oracle'); + }); + + const witnessBuff = compressWitness(witnessMap); + return witnessBuff; +} +``` + +## Proving + +Finally, we're ready to prove with our backend. Just like with the witness generation, could be useful to wrap it in its own function: + +```ts +async function generateProof(witness: Uint8Array) { + const proof = await api.acirCreateProof( + acirComposer, + acirBufferUncompressed, + decompressSync(witness), + false, + ); + return proof; +} +``` + +## Verifying + +Our backend should also be ready to verify our proof: + +```ts +async function verifyProof(proof: Uint8Array) { + await api.acirInitProvingKey(acirComposer, acirBufferUncompressed); + const verified = await api.acirVerifyProof(acirComposer, proof, false); + return verified; +} +``` + +## Now for the fun part + +Let's call our functions, and destroy our API! + +```ts +const input = { x: 3, y: 4 }; +const witness = await generateWitness(input, acirBuffer); +console.log('Witness generated!'); +const proof = await generateProof(witness); +console.log('Proof generated!'); +await verifyProof(proof); +console.log('Proof verified!'); +api.destroy(); +``` + +You can use [this](https://gist.github.com/critesjosh/6f3ba19fdc9298b24e90ba4f736247dc) tsconfig.json. You can see the script [here](https://gist.github.com/critesjosh/4aa36e87a0cc3f09feaf1febb4d11348). + +## Verifying with Smart Contract + +Alternatively, a verifier smart contract can be generated and used for verifying Noir proofs in +TypeScript as well. + +This could be useful if the Noir program is designed to be decentrally verified and/or make use of +decentralized states and logics that is handled at the smart contract level. + +This assumes you've already ran `nargo codegen-verifier`, got your smart contract, and deployed it with Hardhat, Foundry, or your tool of choice. You can then verify a Noir proof by simply calling it. + +Currently, `bb.js` appends the public inputs to the proof. However, these inputs need to be fed separately to the verifier contract. A simple solution is to just slice them from the resulting proof, like this: + +```ts +import { ethers } from 'ethers'; // example using ethers v5 +import artifacts from '../artifacts/circuits/contract/plonk_vk.sol/UltraVerifier.json'; // I compiled using Hardhat, so I'm getting my abi from here + +const verifierAddress = '0x123455'; // your verifier address +const provider = new ethers.providers.Web3Provider(window.ethereum); +const signer = this.provider.getSigner(); + +const contract = new ethers.Contract(verifierAddress, artifacts.abi, signer); + +const publicInputs = proof.slice(0, 32); +const slicedProof = proof.slice(32); +await contract.verify(slicedProof, [publicInputs]); +``` diff --git a/docs/versioned_docs/version-0.6.0/examples/merkle-proof.md b/docs/versioned_docs/version-0.6.0/examples/merkle-proof.md new file mode 100644 index 00000000000..4696b4a1426 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/examples/merkle-proof.md @@ -0,0 +1,48 @@ +--- +title: Merkle Proof 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] +--- + +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); + 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` +instead. + +```rust +let leaf = std::hash::hash_to_field(message); +``` + +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-0.6.0/getting_started/00_nargo_installation.md b/docs/versioned_docs/version-0.6.0/getting_started/00_nargo_installation.md new file mode 100644 index 00000000000..432884b709e --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/getting_started/00_nargo_installation.md @@ -0,0 +1,283 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, + verifying and more). Learn how to install and use Nargo for your projects with this comprehensive + guide. +keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] +--- + +`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, +verifying and more). + +Alternatively, the interactions can also be performed in [TypeScript](../typescript). + +### UltraPlonk + +Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. + +## Installation + +There are four approaches for installing Nargo: + +- [Option 1: Noirup](#option-1-noirup) +- [Option 2: Binaries](#option-2-binaries) +- [Option 3: Install via Nix](#option-3-install-via-nix) +- [Option 4: Compile from Source](#option-4-compile-from-source) + +Optionally you can also install [Noir VS Code extension] for syntax highlighting. + +### Option 1: Noirup + +If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a +terminal and run: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup -v 0.6.0 +``` + +Done, 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. + +#### GitHub Actions + +You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as +installing `noirup` and running tests in your GitHub Action `yml` file. + +See the +[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in +this repo containing hash functions in Noir for an example. + +#### Nightly versions + +To install the nightly version of Noir (updated daily) run: + +```bash +noirup -n +``` + +### Option 2: Binaries + +See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous +platform specific binaries. + +#### Step 1 + +Paste and run the following in the terminal to extract and install the binary: + +> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend +> `sudo` and re-run it. + +##### macOS (Apple Silicon) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### macOS (Intel) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### Windows (PowerShell) + +Open PowerShell as Administrator and run: + +```powershell +mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` +Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` +Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` +$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` +$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` +$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` +Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +``` + +##### Linux (Bash) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ +echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ +source ~/.bashrc +``` + +#### Step 2 + +Check if the installation was successful by running `nargo --help`. + +> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from +> Finder. Close the new terminal popped up and `nargo` should now be accessible. + +For a successful installation, you should see something similar to the following after running the +command: + +```sh +$ nargo --help + +Noir's package manager + +Usage: nargo + +Commands: + check Checks the constraint system for errors + 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 new binary project + 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 + gates Counts the occurrences of different gates in circuit + help Print this message or the help of the given subcommand(s) +``` + +### Option 3: Install via Nix + +Due to the large number of native dependencies, Noir projects can be installed via [Nix](https://nixos.org/). + +#### Installing Nix + +For the best experience, please follow these instructions to setup Nix: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +#### Install Nargo into your Nix profile + +1. Use `nix profile` to install Nargo + +```sh +nix profile install github:noir-lang/noir +``` + +### Option 4: Compile from Source + +Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. + +#### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +3. Install direnv into your Nix profile by running: + +```sh +nix profile install nixpkgs#direnv +``` + +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). +5. Restart your shell. + +#### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: + +```sh +git clone git@github.com:noir-lang/noir +``` +> Replacing `noir` with whichever repository you want to work on. + +2. Navigate to the directory: + +```sh +cd noir +``` +> Replacing `noir` with whichever repository you cloned. + +3. You should see a __direnv error__ because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: + +```sh +direnv allow +``` + +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. + +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): + +```sh +code . +``` + +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +#### Building and testing + +Assuming you are using `direnv` to populate your environment, building and testing the project can be done +with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. + +If you want to build the entire project in an isolated sandbox, you can use Nix commands: + +1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. +2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. + +#### Without `direnv` + +If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. + +Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! + +## Uninstalling Nargo + +### Noirup + +If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` + +### Nix + +If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. + +```bash +rm ~/.nix-profile/bin/nargo +``` + +[git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git +[rust]: https://www.rust-lang.org/tools/install +[noir vs code extension]: + https://marketplace.visualstudio.com/items?itemName=noir-lang.noir-programming-language-syntax-highlighter +[homebrew]: https://brew.sh/ +[cmake]: https://cmake.org/install/ +[llvm]: https://llvm.org/docs/GettingStarted.html +[openmp]: https://openmp.llvm.org/ +[barretenberg]: https://github.com/AztecProtocol/barretenberg diff --git a/docs/versioned_docs/version-0.6.0/getting_started/01_hello_world.md b/docs/versioned_docs/version-0.6.0/getting_started/01_hello_world.md new file mode 100644 index 00000000000..0f21ad45569 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/getting_started/01_hello_world.md @@ -0,0 +1,147 @@ +--- +title: Create 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, + ] +--- + +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 +``` + +For Windows CMD, run: + +```sh +> mkdir "%USERPROFILE%\projects" +> cd /d "%USERPROFILE%\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_ that contains 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](../language_concepts/data_types) 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](../language_concepts/comments) 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 on 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 with your preferred proof name, for example `p`: + +```sh +nargo prove p +``` + +A new folder _proofs_ would then be generated in your project directory, containing the proof file +`p.proof`. + +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 of name `p` by running: + +```sh +nargo verify p +``` + +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](breakdown), we will go into more detail on each step performed. diff --git a/docs/versioned_docs/version-0.6.0/getting_started/02_breakdown.md b/docs/versioned_docs/version-0.6.0/getting_started/02_breakdown.md new file mode 100644 index 00000000000..5f4f00a3f36 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/getting_started/02_breakdown.md @@ -0,0 +1,103 @@ +--- +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] +--- + +This section breaks down our hello world program in section _1.2_. We elaborate on the project +structure and what the `prove` and `verify` commands did in the previous section. + +## 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_ is used for specifying the input values for executing and proving the program. +Optionally you may specify expected output values for prove-time checking as well. + +_Verifier.toml_ contains public in/output values computed when executing the Noir program. + +_Nargo.toml_ contains the environmental options of your project. + +_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) { + constrain 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, `constrain` ensures the satisfaction of the condition (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 my_proof` 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 not equal constraint is due to the line `constrain x != y`. + +2. Noir creates and stores the proof of this statement in the _proofs_ directory and names the proof + file _my_proof_. Opening this file will display the proof in hex format. + +## Verifying a Proof + +When the command `nargo verify my_proof` is executed, two processes happen: + +1. Noir checks in the _proofs_ directory for a file called _my_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 from usually external sources and +verifies the validity of the proof against it. + +Take a private asset transfer as an example: + +A user on browser as the prover would retrieve private inputs (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). diff --git a/docs/versioned_docs/version-0.6.0/index.md b/docs/versioned_docs/version-0.6.0/index.md new file mode 100644 index 00000000000..f4706182ffa --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/index.md @@ -0,0 +1,65 @@ +--- +title: Introducing Noir +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, + ] +slug: / +--- + +This version of the book is being released with the public alpha. There will be a lot of features +that are missing in this version, however the syntax and the feel of the language will mostly be +completed. + +## What is Noir? + +Noir is a domain specific language for creating and verifying proofs. It's design choices are +influenced heavily by Rust. + +## What's new about Noir? + +Noir is simple and flexible in its design, as it does not compile immediately to a fixed +NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled +to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). + +This in itself brings up a few challenges +within the design process, but allows one to decouple the programming language completely from the +backend. This is similar in theory to LLVM. + +## Who is Noir for? + +Noir can be used for a variety of purposes. + +### Ethereum Developers + +Noir currently includes a command to publish a contract which verifies your Noir program. This will +be modularised in the future; however, as of the alpha, you can use the `contract` command to create +a verifier contract. + +### Protocol Developers + +As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for +your stack, or maybe you simply want to use a different proving system. Since Noir does not compile +to a specific proof system, it is possible for protocol developers to replace the PLONK-based +proving system with a different proving system altogether. + +### Blockchain developers + +As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the +proving system and smart contract language has been pre-defined). In order for you to use Noir in +your blockchain, a proving system backend and a smart contract interface +must be implemented for it. diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/00_data_types.md b/docs/versioned_docs/version-0.6.0/language_concepts/00_data_types.md new file mode 100644 index 00000000000..3a711fc8922 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/00_data_types.md @@ -0,0 +1,301 @@ +--- +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, + field type, + integer types, + boolean type, + array type, + tuple type, + struct type, + ] +--- + +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`. + +## Primitive Types + +A primitive type represents a single value. They can be private or public. + +### Fields + +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. + +### Integers + +An integer type is a range constrained field type. The Noir frontend currently supports unsigned, +arbitrary-sized integer types. + +An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by +its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of +$\\([0,2^{32}-1]\\)$: + +```rust +fn main(x : Field, y : u32) { + let z = x as u32 + y; +} +``` + +`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` +are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created +will be rejected by the verifier. + +> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) +> sized integer types. + +### Booleans + +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 `constrain` +statements. More about conditionals is covered in the [Control Flow](./control_flow) and +[Constrain Statement](./constrain) sections. + +### Strings + +The string type is a fixed length value defined with `str`. + +You can use strings in `constrain` statements, `assert()` functions or print them with +`std::println()`. + +```rust +fn main(message : pub str<11>, hex_as_string : str<4>) { + std::println(message); + assert(message == "hello world"); + assert(hex_as_string == "0x41"); +} +``` + +## Compound Types + +A compound type groups together multiple values into one type. Elements within a compound type can +be private or public. + +### Arrays + +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); +} +``` + +#### 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. + +### Tuples + +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; +} +``` + +### Structs + +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. + +:::note +You can use Structs as inputs to the `main` function, but you can't output them +::: diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/01_functions.md b/docs/versioned_docs/version-0.6.0/language_concepts/01_functions.md new file mode 100644 index 00000000000..c4bc0545a1c --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/01_functions.md @@ -0,0 +1,88 @@ +--- +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] +--- + +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() {} +``` + +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 : pub 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 : pub Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## 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); + constrain s.sum() == 42; +} +``` + +Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as +follows: + +```rust +constrain MyStruct::sum(s) == 42 +``` diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/02_control_flow.md b/docs/versioned_docs/version-0.6.0/language_concepts/02_control_flow.md new file mode 100644 index 00000000000..29108dd2634 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/02_control_flow.md @@ -0,0 +1,42 @@ +--- +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] +--- + +## 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 +}; +``` + +## If Expressions + +Noir supports `if-else` statements. The syntax is most similar to Rust's where it is not required +for the statement's conditonal 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; + constrain x == 5; +} +constrain x == 2; +``` diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/03_ops.md b/docs/versioned_docs/version-0.6.0/language_concepts/03_ops.md new file mode 100644 index 00000000000..d08df2094a5 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/03_ops.md @@ -0,0 +1,96 @@ +--- +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, + ] +--- + +# 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 | +| << | 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 indentically 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; +} +constrain flag == 1; + +if (my_val != 10) & (my_val < 50) { + flag = 0; +} +constrain 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-0.6.0/language_concepts/04_assert.md b/docs/versioned_docs/version-0.6.0/language_concepts/04_assert.md new file mode 100644 index 00000000000..a25a946123d --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/04_assert.md @@ -0,0 +1,34 @@ +--- +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] +--- + +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); +} +``` + +The above snippet compiles because `==` is a predicate operation. Conversely, the following will not +compile: + +```rust +// INCORRECT + +fn main(x : Field, y : Field) { + assert(x + y); +} +``` + +> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should +> equate to `x + y == 0` or if it should check the truthiness of the result. diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/05_constrain.md b/docs/versioned_docs/version-0.6.0/language_concepts/05_constrain.md new file mode 100644 index 00000000000..9ba1e260e8c --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/05_constrain.md @@ -0,0 +1,40 @@ +--- +title: Constrain Statements +description: + Learn about the constrain keyword 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, constrain statement, predicate expression, comparison expression] +--- + +:::danger + +In versions >=0.5.0 use the [`assert`](./04_assert.md) syntax. The `constrain` statement will be +maintained for some time for backwards compatibility but will be deprecated in the future. + +::: + +Noir includes a special keyword `constrain` 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. + +### Constrain statement example + +```rust +fn main(x : Field, y : Field) { + constrain x == y; +} +``` + +The above snippet compiles because `==` is a predicate operation. Conversely, the following will not +compile: + +```rust +fn main(x : Field, y : Field) { + constrain x + y; +} +``` + +> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should +> equate to `x + y == 0` or if it should check the truthiness of the result. diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/06_generics.md b/docs/versioned_docs/version-0.6.0/language_concepts/06_generics.md new file mode 100644 index 00000000000..6976666b23e --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/06_generics.md @@ -0,0 +1,116 @@ +--- +title: Generics +description: + Learn how to use Generics in Noir +keywords: [Noir, Rust, generics, functions, structs] +--- + +# Generics + +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: comptime Field, +} + +impl RepeatedValue { + fn new(value: T) -> Self { + Self { value, count: 1 } + } + + fn increment(mut repeated: Self) -> Self { + repeated.count += 1; + repeated + } + + fn print(self) { + for _i in 0 .. self.count { + dep::std::println(self.value); + } + } +} + +fn main() { + let mut repeated = RepeatedValue::new("Hello!"); + repeated = repeated.increment(); + 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 { + constrain first.limbs != second.limbs; + first + + fn second(first: BigInt, second: Self) -> Self { + constrain first.limbs != second.limbs; + second + } +} +``` + +## Calling functions on generic parameters + +Unlike Rust, Noir does not have traits, so how can one translate the equivalent of a trait bound in +Rust into Noir? That is, how can we write a function that is generic over some type `T`, while also +requiring there is a function like `eq: fn(T, T) -> bool` that works on the type? + +The answer is that we can translate this by passing in the function manually. Here's an example of +implementing array equality in Noir: + +```rust +fn array_eq(array1: [T; N], array2: [T; N], elem_eq: fn(T, T) -> bool) -> bool { + if array1.len() != array2.len() { + false + } else { + let mut result = true; + for i in 0 .. array1.len() { + result &= elem_eq(array1[i], array2[i]); + } + result + } +} + +fn main() { + constrain array_eq([1, 2, 3], [1, 2, 3], |a, b| a == b); + + // We can use array_eq even for arrays of structs, as long as we have + // an equality function for these structs we can pass in + let array = [MyStruct::new(), MyStruct::new()]; + constrain array_eq(array, array, MyStruct::eq); +} +``` + +You can see an example of generics in the tests +[here](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/generics/src/main.nr). diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/07_mutability.md b/docs/versioned_docs/version-0.6.0/language_concepts/07_mutability.md new file mode 100644 index 00000000000..c8ccb4f8b9f --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/07_mutability.md @@ -0,0 +1,118 @@ +--- +title: Mutability +description: + Learn about mutable variables, constants, and globals in Noir programming language. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +--- + +# Mutability + +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() -> Field { + let x = 3; + helper(x); + x // x is still 3 +} + +fn helper(mut x: i32) { + x = 4; +} +``` + +## Comptime values + +Comptime value are values that are known at compile-time. This is different to a witness +which changes per proof. If a comptime value that is being used in your program is changed, then your +circuit will also change. + +Below we show how to declare a comptime value: + +```rust +fn main() { + let a: comptime Field = 5; + + // `comptime Field` can also be inferred: + let a = 5; +} +``` + +Note that variables declared as mutable may not be comptime: + +```rust +fn main() { + // error: Cannot mark a comptime type as mutable + let mut a: comptime Field = 5; + + // a inferred as a private Field here + let mut a = 5; +} +``` + +## Globals + +Noir also supports global variables. However, they must be compile-time variables. If `comptime` is +not explicitly written in the type annotation the compiler will implicitly specify the declaration +as compile-time. They can then be used like any other compile-time variable inside functions. The +global type can also be inferred by the compiler entirely. Globals can also be used to specify array +annotations for function parameters and can be imported from submodules. + +```rust +global N: Field = 5; // Same as `global N: comptime Field = 5` + +fn main(x : Field, y : [Field; N]) { + let res = x * N; + + constrain res == y[0]; + + let res2 = x * mysubmodule::N; + constrain res != res2; +} + +mod mysubmodule { + use dep::std; + + global N: Field = 10; + + fn my_helper() -> comptime Field { + let x = N; + x + } +} +``` + +## Why only local mutability? + +Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting +without applying additional overhead to the user. Modeling a mutable reference is not as +straightforward as on conventional architectures and would incur some possibly unexpected overhead. diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/08_comments.md b/docs/versioned_docs/version-0.6.0/language_concepts/08_comments.md new file mode 100644 index 00000000000..5b1d9fa38f2 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/08_comments.md @@ -0,0 +1,27 @@ +--- +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] +--- + +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 doesn't have multi-line comments, but you can emulate them via using `//` on each line + +```rust +// This is a multi line +// comment, that is ignored by +// the compiler +``` diff --git a/docs/versioned_docs/version-0.6.0/language_concepts/09_distinct.md b/docs/versioned_docs/version-0.6.0/language_concepts/09_distinct.md new file mode 100644 index 00000000000..03759d4bb4a --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/language_concepts/09_distinct.md @@ -0,0 +1,63 @@ +--- +title: Distinct Witnesses +--- + +The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures +that the witnesses being returned as public inputs are all unique. + +The `distinct` keyword is only used for return values on program entry points (usually the `main()` +function). + +When using `disctinct` and `pub` simultaneously, `distinct` comes first. See the example below. + +You can read more about the problem this solves +[here](https://github.com/noir-lang/noir/issues/1183). + +## Example + +Without the `distinct` keyword, the following program + +```rust +fn main(x : pub Field, y : pub Field) -> pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + "return_witnesses": [3, 2, 4, 4] + } +} +``` + +Whereas (with the `distinct` keyword) + +```rust +fn main(x : pub Field, y : pub Field) -> distinct pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + //... + "return_witnesses": [3, 4, 5, 6] + } +} +``` diff --git a/docs/versioned_docs/version-0.6.0/modules_packages_crates/crates_and_packages.md b/docs/versioned_docs/version-0.6.0/modules_packages_crates/crates_and_packages.md new file mode 100644 index 00000000000..34f28a71148 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/modules_packages_crates/crates_and_packages.md @@ -0,0 +1,35 @@ +--- +title: Crates and Packages +description: + Learn how to use Crates and Packages in your Noir project +keywords: [Nargo, dependencies, package management, crates, package] +--- + +## 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 one of two forms: a binary crate or a library crate. + +_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. + +_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. + +### 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-0.6.0/modules_packages_crates/dependencies.md b/docs/versioned_docs/version-0.6.0/modules_packages_crates/dependencies.md new file mode 100644 index 00000000000..f3b40eb849b --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/modules_packages_crates/dependencies.md @@ -0,0 +1,85 @@ +--- +title: Managing 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] +--- + +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.2.0", git = "https://github.com/colinnielsen/ecrecover-noir"} +``` + +## 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 + +``` +β”œβ”€β”€ binary_crate +β”‚Β Β  β”œβ”€β”€ Nargo.toml +β”‚Β Β  └── src +β”‚Β Β  └── main.nr +└── liba + β”œβ”€β”€ Nargo.toml + └── src + └── lib.nr +``` + +Inside of the binary crate, you can specify: + +```toml +# Nargo.toml + +[dependencies] +libA = { path = "../liba" } +``` + +## 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 liba referenced above: + +```rust +use dep::ecrecover; +use dep::libA; +``` + +You can also import only the specific parts of dependency that you want to use. For example, +demonstrated in the +[elliptic curve example](../standard_library/cryptographic_primitives/ec_primitives#examples), you +can import just the `Point` and the `Curve` that you want to use. + +```rust +use dep::std::ec::tecurve::affine::Curve; +use dep::std::ec::tecurve::affine::Point; +``` + +## 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: + +- BigInt +- "`ecrecover`" +- sparse merkle tree verifier diff --git a/docs/versioned_docs/version-0.6.0/modules_packages_crates/modules.md b/docs/versioned_docs/version-0.6.0/modules_packages_crates/modules.md new file mode 100644 index 00000000000..e429b336511 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/modules_packages_crates/modules.md @@ -0,0 +1,104 @@ +--- +title: Understanding 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] +--- + +# Modules + +Noir's module system follows the same convention as the _newer_ version of Rust's module system. + +## Purpose of Modules + +Modules are used to organise 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-0.6.0/nargo/01_commands.md b/docs/versioned_docs/version-0.6.0/nargo/01_commands.md new file mode 100644 index 00000000000..f9d9ddb77ff --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/nargo/01_commands.md @@ -0,0 +1,130 @@ +--- +title: Commands +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, + ] +--- + +## General options + +``` +Options: + -s, --show-ssa Emit debug information for the intermediate SSA IR + -d, --deny-warnings Quit execution when warnings are emitted + --show-output Display output of `println` statements during tests + -h, --help Print help +``` + +## `nargo help [subcommand]` + +Prints the list of available commands or specific information of a subcommand. + +_Arguments_ + +- `` - The subcommand whose help message to display + +## `nargo check` + +Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output +values of the Noir program respectively. + +## `nargo codegen-verifier` + +Generate a Solidity verifier smart contract for the program. + +## `nargo compile ` + +Compile the program into a JSON build artifact file containing the ACIR representation and the ABI +of the circuit. This build artifact can then be used to generate and verify proofs. + +_Arguments_ + +- `` - The name of the circuit file + +_Options_ + +- `-c, --contracts` - Compile each contract function used within the program + +## `nargo new [path]` + +Creates a new Noir project. + +_Arguments_ + +- `` - Name of the package +- `[path]` - The path to save the new project + +## `nargo execute [witness_name]` + +Runs the Noir program and prints its return value. + +_Arguments_ + +- `[witness_name]` - The name of the witness + +_Usage_ + +The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which +must be filled in. + +To save the witness to file, run the command with a value for the `witness-name` argument. A +`.tr` file will then be saved in the `build` folder. + +> **Info:** The `.tr` file is the witness file. The witness file can be considered as program inputs +> parsed for your program's ACIR. +> +> This file can be passed along with circuit's ACIR into a TypeScript project for proving and +> verification. See the [TypeScript](../typescript#proving-and-verifying-externally-compiled-files) +> section to learn more. + +## `nargo prove ` + +Creates a proof for the program. + +_Arguments_ + +- `` - The name of the proof + +_Options_ + +- `-v, --verify` - Verify proof after proving + +## `nargo verify ` + +Given a proof and a program, verify whether the proof is valid. + +_Arguments_ + +- `` - The proof to verify + +## `nargo test ` + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. + +See an example on the [testing page](./testing). + +_Arguments_ + +- `` - a pattern to indicate to only run tests with names containing the pattern + +## `nargo gates` + +Counts the occurrences of different gates in circuit + +## `nargo print-acir` + +Print a compiled circuit to stdout such that the ACIR can be inspected. diff --git a/docs/versioned_docs/version-0.6.0/nargo/02_testing.md b/docs/versioned_docs/version-0.6.0/nargo/02_testing.md new file mode 100644 index 00000000000..73f91c72bfd --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/nargo/02_testing.md @@ -0,0 +1,32 @@ +--- +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] +--- + +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() { + constrain add(2,2) == 4; + constrain add(0,1) == 1; + constrain add(1,0) == 1; +} +``` + +Running `nargo test` will test that the `test_add` function can be executed while satisfying the all +the contraints which allows you to test that add returns the expected values. Test functions can't +have any arguments currently. + +This is much faster compared to testing in Typescript but the only downside is that you can't +explicitly test that a certain set of inputs are invalid. i.e. you can't say that you want +add(2^64-1, 2^64-1) to fail. diff --git a/docs/versioned_docs/version-0.6.0/nargo/03_solidity_verifier.md b/docs/versioned_docs/version-0.6.0/nargo/03_solidity_verifier.md new file mode 100644 index 00000000000..69a5607f1b2 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/nargo/03_solidity_verifier.md @@ -0,0 +1,116 @@ +--- +title: 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, + ] +--- + +For certain applications, it may be desirable to run the verifier as a smart contract instead of on +a local machine. + +Compile a Solidity verifier contract for your Noir program by running: + +```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 on any EVM blockchain acting as a verifier smart contract. + +> **Note:** It is possible to compile 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 compilation of verifier contracts in +> Solidity only for the time being. + +## Verify + +To verify a proof using the Solidity verifier contract, call the `verify` function with the +following signature: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +### Public Inputs + +:::tip + +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. + +::: + +The verifier contract uses the output (return) value of a Noir program as a public input. So if you +have the following function + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +then `verify` in `plonk_vk.sol` will expect 3 public inputs. Passing two inputs will result in an +error like `Reason: PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case the 3 inputs to `verify` would be ordered as `[pubkey_x, pubkey_y, return]`. + +#### Struct inputs + +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) { + //... +} +``` + +Structs will be flattened so that the array of inputs is 1-dimensional array. The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +## Noir for EVM chains + +You can currently deploy the Solidity verifier contracts to most EVM compatible chains. EVM chains that have been tested and are known to work include: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +Other EVM chains should work, but have not been tested directly by our team. 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. + +### Unsupported chains + +Unfortunately not all "EVM" chains are supported. + +**zkSync** and the **Polygon zkEVM** do *not* currently support proof verification via Solidity verifier contracts. They are missing the bn256 precompile contract that the verifier contract requires. Once these chains support this precompile, they may work. diff --git a/docs/versioned_docs/version-0.6.0/standard_library/array_methods.md b/docs/versioned_docs/version-0.6.0/standard_library/array_methods.md new file mode 100644 index 00000000000..701590ccf54 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/array_methods.md @@ -0,0 +1,180 @@ +--- +title: Array Methods +description: + Learn about the commonly used methods available for arrays in Noir, including len, sort, fold, + reduce, all, and any. +keywords: [rust, array, methods, len, sort, fold, reduce, all, any] +--- + +# Array + +For convenience, the STD provides some ready-to-use, common methods for arrays[^migrationnote]: + +## len + +Returns the length of an array + +```rust +fn len(_array: [T; N]) -> comptime Field +``` + +example + +```rust +fn main() { + let array = [42, 42]; + constrain 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(_array: [T; N]) -> [T; N] +``` + +example + +```rust +fn main() { + let arr = [42, 32] + let sorted = arr.sort(); + constrain sorted == [32, 42]; +} +``` + +## sort_via + +Sorts the array with a custom comparison function + +```rust +fn sort_via(mut a: [T; N], 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); + constrain sorted_ascending == [32, 42]; // verifies + + let sorted_descending = arr.sort_via(|a, b| a > b); + constrain 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(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(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); + constrain folded == 10; +} + +``` + +## reduce + +Same as fold, but uses the first element as starting element. + +```rust +fn reduce(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); + constrain reduced == 10; +} +``` + +## all + +Returns true if all the elements satisfy the given predicate + +```rust +fn all(predicate: fn(T) -> bool) -> bool +``` + +example: + +```rust +fn main() { + let arr = [2,2,2,2,2] + let all = arr.all(|a| a == 2); + constrain all; +} +``` + +## any + +Returns true if any of the elements satisfy the given predicate + +```rust +fn any(predicate: fn(T) -> bool) -> bool +``` + +example: + +```rust +fn main() { + let arr = [2,2,2,2,5] + let any = arr.any(|a| a == 5); + constrain any; +} + +``` + +[^migrationnote]: + Migration Note: These methods were previously free functions, called via `std::array::len()`. + For the sake of ease of use and readability, these functions are now methods and the old syntax + for them is now deprecated. diff --git a/docs/versioned_docs/version-0.6.0/standard_library/black_box_fns.md b/docs/versioned_docs/version-0.6.0/standard_library/black_box_fns.md new file mode 100644 index 00000000000..3063e71c147 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/black_box_fns.md @@ -0,0 +1,44 @@ +--- +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. + +:::warning + +It is likely that not all backends will support a particular black box function. + +::: + +Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. + +Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: + +```rust +#[foreign(sha256)] +fn sha256(_input : [u8; N]) -> [u8; 32] {} +``` + +## Function list + +Here is a list of the current black box functions that are supported by UltraPlonk: + +- AES +- [SHA256](./cryptographic_primitives/hashes#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr) +- [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Pedersen](./cryptographic_primitives/hashes#pedersen) +- [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_secp256k1) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [Compute merkle root](./merkle_trees#compute_merkle_root) +- AND +- XOR +- RANGE +- [Keccak256](./cryptographic_primitives/hashes#keccak256) + +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. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. + +You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/acvm/blob/acir-v0.12.0/acir/src/circuit/black_box_functions.rs). diff --git a/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives.md b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives.md new file mode 100644 index 00000000000..2df4f929474 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives.md @@ -0,0 +1,14 @@ +--- +title: Cryptographic primitives in Noir +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-0.6.0/standard_library/cryptographic_primitives/00_hashes.mdx b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/00_hashes.mdx new file mode 100644 index 00000000000..c373f10ca6a --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/00_hashes.mdx @@ -0,0 +1,149 @@ +--- +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 + ] +--- + +import BlackBoxInfo from './common/\_blackbox.mdx'; + +## sha256 + +Given an array of bytes, returns the resulting sha256 hash. + +```rust +fn sha256(_input : [u8]) -> [u8; 32] +``` + +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 +fn blake2s(_input : [u8]) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let hash = std::hash::blake2s(x); +} +``` + + + +## pedersen + +Given an array of Fields, returns the Pedersen hash. + +```rust +fn pedersen(_input : [Field]) -> [Field; 2] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let hash = std::hash::pedersen(x); +} +``` + + + +## keccak256 + +Given an array of bytes (`u8`), returns the resulting keccak hash as an array of 32 bytes (`[u8; 32]`). + +```rust +fn keccak256(_input : [u8; N]) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let hash = std::hash::keccak256(x); +} +``` + + + +## 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 +fn main() +{ + let hash1 = std::hash::poseidon::bn254::hash_2([1, 2]); + constrain hash1 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a; +} +``` + +## 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_bn254(x); +} +``` + +## hash_to_field + +```rust +fn hash_to_field(_input : [Field; N]) -> 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-0.6.0/standard_library/cryptographic_primitives/01_scalar.mdx b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/01_scalar.mdx new file mode 100644 index 00000000000..62265cddb1e --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/01_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, + ] +--- + +import BlackBoxInfo from './common/\_blackbox.mdx'; + +## scalar_mul::fixed_base + +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 +fn fixed_base(_input : Field) -> [Field; 2] +``` + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base(x); + std::println(scal); +} +``` + + diff --git a/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/02_schnorr.mdx b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/02_schnorr.mdx new file mode 100644 index 00000000000..c2c6f3ae19a --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/02_schnorr.mdx @@ -0,0 +1,37 @@ +--- +title: Schnorr Signatures +description: Learn how you can verify Schnorr signatures using Noir +keywords: [cryptographic primitives, Noir project, schnorr, signatures] +--- + +import BlackBoxInfo from './common/\_blackbox.mdx'; + +## schnorr::verify_signature + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). + +```rust +fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> Field +``` + +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() +); + +... +``` + + diff --git a/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx new file mode 100644 index 00000000000..88892712fb6 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx @@ -0,0 +1,25 @@ +--- +title: ECDSA Verification +description: + Learn about the cryptographic primitives regarding ECDSA over the secp256k1 curve +keywords: + [ + cryptographic primitives, + Noir project, + ecdsa, + secp256k1, + signatures, + ] +--- + +import BlackBoxInfo from './common/\_blackbox.mdx'; + +## ecdsa_secp256k1::verify_signature + +Verifier for ECDSA Secp256k1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> Field +``` + + diff --git a/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/04_ec_primitives.md b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/04_ec_primitives.md new file mode 100644 index 00000000000..2d4ed0f8fae --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -0,0 +1,102 @@ +--- +title: Elliptic Curve Primitives +keywords: [cryptographic primitives, Noir project] +--- + +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 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/crates/nargo_cli/tests/test_data/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; +use dep::std::ec::tecurve::affine::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-0.6.0/standard_library/cryptographic_primitives/common/_blackbox.mdx b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/common/_blackbox.mdx new file mode 100644 index 00000000000..9fe9b48fbff --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/cryptographic_primitives/common/_blackbox.mdx @@ -0,0 +1,5 @@ +:::info + +This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. + +::: \ No newline at end of file diff --git a/docs/versioned_docs/version-0.6.0/standard_library/field_methods.md b/docs/versioned_docs/version-0.6.0/standard_library/field_methods.md new file mode 100644 index 00000000000..7cea9846102 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/field_methods.md @@ -0,0 +1,149 @@ +--- +title: Field Methods +description: + Learn about common methods on Noir Field, including to_le_bits, to_le_bytes, to_le_radix, + to_be_radix, pow_32, etc, and see code examples. +keywords: + [ + Noir Field, + to_le_bits, + to_le_bytes, + to_le_radix, + to_be_radix, + pow_32, + Little Endian, + Big Endian, + Vector, + Exponent, + ] +--- + +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; N] +``` + +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; N] +``` + +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); + constrain pow == 16; +} +``` + +## 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 +``` diff --git a/docs/versioned_docs/version-0.6.0/standard_library/logging.md b/docs/versioned_docs/version-0.6.0/standard_library/logging.md new file mode 100644 index 00000000000..649d35a3f0b --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/logging.md @@ -0,0 +1,55 @@ +--- +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, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +# Logging + +The standard library provides a familiar `println` statement you can use. Despite being a limited +implementation of rust's `println!` macro, this construct can be useful for debugging. + +The `println` statement only works for fields, integers and arrays (including strings). + +```rust +use dep::std; + +fn main(string: pub str<5>) { + let x = 5; + std::println(x) +} + +``` + +To view the output of the `println` statement you need to set the `--show-output` flag. + +``` +$ nargo prove --help +Create proof for this program. The proof is returned as a hex encoded string + +Usage: nargo prove [OPTIONS] [PROOF_NAME] [CIRCUIT_NAME] + +Arguments: + [PROOF_NAME] The name of the proof + [CIRCUIT_NAME] The name of the circuit build files (ACIR, proving and verification keys) + +Options: + -v, --verify Verify proof after proving + -s, --show-ssa Emit debug information for the intermediate SSA IR + -d, --deny-warnings Quit execution when warnings are emitted + --show-output Display output of `println` statements during tests + -h, --help Print help +``` diff --git a/docs/versioned_docs/version-0.6.0/standard_library/merkle_trees.md b/docs/versioned_docs/version-0.6.0/standard_library/merkle_trees.md new file mode 100644 index 00000000000..fc8909a4795 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/merkle_trees.md @@ -0,0 +1,59 @@ +--- +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/00_hashes.mdx#pedersen). + +```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(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); + std::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). \ No newline at end of file diff --git a/docs/versioned_docs/version-0.6.0/standard_library/zeroed.md b/docs/versioned_docs/version-0.6.0/standard_library/zeroed.md new file mode 100644 index 00000000000..97dab02dac2 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/standard_library/zeroed.md @@ -0,0 +1,25 @@ +--- +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 +- String +- Tuple +- Function + +Using it on other types could result in unexpected behavior. diff --git a/docs/versioned_docs/version-0.6.0/typescript.md b/docs/versioned_docs/version-0.6.0/typescript.md new file mode 100644 index 00000000000..fae002dfd28 --- /dev/null +++ b/docs/versioned_docs/version-0.6.0/typescript.md @@ -0,0 +1,262 @@ +--- +title: Working with TypeScript +description: + Learn how to interact with Noir programs using TypeScript. Follow this tutorial to compile your + program, specify inputs, initialize a prover & verifier, and prove and verify your program. +keywords: [TypeScript, Noir, tutorial, compile, inputs, prover, verifier, proof] +--- + +Interactions with Noir programs can also be performed in TypeScript, which can come in handy when +writing tests or when working in TypeScript-based projects like [Hardhat](https://hardhat.org/). + +This guide is based on the [noir-starter](https://github.com/signorecello/noir-starter) example. +Please refer to it for an example implementation. + +:::note + +You may find unexpected errors working with some frameworks such as `vite`. This is due to the +nature of `wasm` files and the way Noir uses web workers. As we figure it out, we suggest using +[Create React App](https://create-react-app.dev/), or [Next.js](https://nextjs.org/) for a quick +start. + +::: + +## Setup + +We're assuming you're using ES6 for both browser (for example with React), or nodejs. + +Install [Yarn](https://yarnpkg.com/) or [Node.js](https://nodejs.org/en). Init a new project with +`npm init`. Install Noir dependencies in your project by running: + +```bash +npm i @noir-lang/noir_wasm@0.3.2-fa0e9cff github:noir-lang/barretenberg#39a1547875f941ef6640217a42d8f34972425c97 @noir-lang/aztec_backend@0.1.0-0c3b2f2 +``` + +:::note + +While Noir is in rapid development, some packages could interfere with others. For that reason, you +should use these specified versions. Let us know if for some reason you need to use other ones. + +::: + +As for the circuit, we will use the _Standard Noir Example_ and place it in the `src` folder. Feel +free to use any other, as long as you refactor the below examples accordingly. + +This standard example is a program that multiplies input `x` with input `y` and returns the result: + +```rust +// src/main.nr +fn main(x: u32, y: pub u32) -> pub u32 { + let z = x * y; + z +} +``` + +One valid scenario for proving could be `x = 3`, `y = 4` and `return = 12` + +## Imports + +We need some imports, for both the `noir_wasm` library (which will compile the circuit into `wasm` +executables) and `aztec_backend` which is the actual proving backend we will be using. + +We also need to tell the compiler where to find the `.nr` files, so we need to import +`initialiseResolver`. + +```ts +import initNoirWasm, { acir_read_bytes, compile } from '@noir-lang/noir_wasm'; +import initialiseAztecBackend from '@noir-lang/aztec_backend'; +import { initialiseResolver } from '@noir-lang/noir-source-resolver'; +``` + +## Compiling + +We'll go over the code line-by-line later: + +```ts +export const compileCircuit = async () => { + await initNoirWasm(); + + return await fetch(new URL('../src/main.nr', import.meta.url)) + .then(r => r.text()) + .then(code => { + initialiseResolver((id: any) => { + return code; + }); + }) + .then(() => { + try { + const compiled_noir = compile({}); + return compiled_noir; + } catch (e) { + console.log('Error while compiling:', e); + } + }); +}; +``` + +1. First we're calling `initNoirWasm`. This is required on the browser only. +2. We then pass an URL that points to our `main.nr` file, and call `.then` on it so we can get the + actual text of the source code +3. We call `initialiseResolver` returning the source code +4. Finally, we can call the `compile` function + +This function should return us the compiled circuit. + +:::note + +You can use as many files as you need, +[importing them as you would do with Nargo](./modules_packages_crates/dependencies), and you don't +need to set them up in the `src` folder. Just mind the following particularities about +`initialiseResolver`: + +1. The `compile` function expects a `main.nr` file as an entry point. If you need another one, just + pass it as a `entry_point` parameter to `compile`. Check the + [noir starter](https://github.com/signorecello/noir-starter) for an example on multiple files and + a non-default entry point. +2. `initialiseResolver` needs to be synchronous +3. Different frameworks use different ways of fetching files. It's beyond the scope of this guide to + explain why and how, but for reference, + [noir starter](https://github.com/signorecello/noir-starter) uses both Next.js and node.js for + testing. + +Quick tip: an easy way to deal with `initialiseResolver` is just to prepare a +`{fileName: "literally_the_code"}` object beforehand + +::: + +## ACIR + +Noir compiles to two properties: + +1. The ACIR, which is the intermediate language used by backends such as Barretenberg +2. The ABI, which tells you which inputs are to be read + +Let's write a little function that gets us both, initializes the backend, and returns the ACIR as +bytes: + +```ts +export const getAcir = async () => { + const { circuit, abi } = await compileCircuit(); + await initialiseAztecBackend(); + + let acir_bytes = new Uint8Array(Buffer.from(circuit, 'hex')); + return acir_read_bytes(acir_bytes); +}; +``` + +Calling `getAcir()` now should return us the ACIR of the circuit, ready to be used in proofs. + +## Initializing Prover & Verifier + +Prior to proving and verifying, the prover and verifier have to first be initialized by calling +`barretenberg`'s `setup_generic_prover_and_verifier` with your Noir program's ACIR: + +```ts +let [prover, verifier] = await setup_generic_prover_and_verifier(acir); +``` + +This is probably a good time to store this prover and verifier into your state like React Context, +Redux, or others. + +## Proving + +The Noir program can then be executed and proved by calling `barretenberg`'s `create_proof` +function: + +```ts +const proof = await create_proof(prover, acir, abi); +``` + +On the browser, this proof can fail as it requires heavy loads to be run on worker threads. Here's a +quick example of a worker: + +```ts +// worker.ts +onmessage = async event => { + try { + await initializeAztecBackend(); + const { acir, input } = event.data; + const [prover, verifier] = await setup_generic_prover_and_verifier(acir); + const proof = await create_proof(prover, acir, input); + postMessage(proof); + } catch (er) { + postMessage(er); + } finally { + close(); + } +}; +``` + +Which would be called like this, for example: + +```ts +// index.ts +const worker = new Worker(new URL('./worker.ts', import.meta.url)); +worker.onmessage = e => { + if (e.data instanceof Error) { + // oh no! + } else { + // yey! + } +}; +worker.postMessage({ acir, input: { x: 3, y: 4 } }); +``` + +## Verifying + +The `proof` obtained can be verified by calling `barretenberg`'s `verify_proof` function: + +```ts +// 1_mul.ts +const verified = await verify_proof(verifier, proof); +``` + +The function should return `true` if the entire process is working as intended, which can be +asserted if you are writing a test script: + +```ts +expect(verified).eq(true); +``` + +## Verifying with Smart Contract + +Alternatively, a verifier smart contract can be generated and used for verifying Noir proofs in +TypeScript as well. + +This could be useful if the Noir program is designed to be decentrally verified and/or make use of +decentralized states and logics that is handled at the smart contract level. + +To generate the verifier smart contract using typescript: + +```ts +// generator.ts +import { writeFileSync } from 'fs'; + +const sc = verifier.SmartContract(); +syncWriteFile('../contracts/plonk_vk.sol', sc); + +function syncWriteFile(filename: string, data: any) { + writeFileSync(join(__dirname, filename), data, { + flag: 'w', + }); +} +``` + +You can then verify a Noir proof using the verifier contract, for example using Hardhat: + +```ts +// verifier.ts +import { ethers } from 'hardhat'; +import { Contract, ContractFactory, utils } from 'ethers'; + +let Verifier: ContractFactory; +let verifierContract: Contract; + +before(async () => { + Verifier = await ethers.getContractFactory('TurboVerifier'); + verifierContract = await Verifier.deploy(); +}); + +// Verify proof +const sc_verified = await verifierContract.verify(proof); +``` diff --git a/docs/versioned_docs/version-0.7.1/examples/merkle-proof.md b/docs/versioned_docs/version-0.7.1/examples/merkle-proof.md new file mode 100644 index 00000000000..4696b4a1426 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/examples/merkle-proof.md @@ -0,0 +1,48 @@ +--- +title: Merkle Proof 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] +--- + +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); + 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` +instead. + +```rust +let leaf = std::hash::hash_to_field(message); +``` + +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-0.7.1/getting_started/00_nargo_installation.md b/docs/versioned_docs/version-0.7.1/getting_started/00_nargo_installation.md new file mode 100644 index 00000000000..fb86a966e75 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/getting_started/00_nargo_installation.md @@ -0,0 +1,284 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, + verifying and more). Learn how to install and use Nargo for your projects with this comprehensive + guide. +keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] +--- + +`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, +verifying and more). + +Alternatively, the interactions can also be performed in [TypeScript](../typescript). + +### UltraPlonk + +Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. + +## Installation + +There are four approaches for installing Nargo: + +- [Option 1: Noirup](#option-1-noirup) +- [Option 2: Binaries](#option-2-binaries) +- [Option 3: Install via Nix](#option-3-install-via-nix) +- [Option 4: Compile from Source](#option-4-compile-from-source) + +Optionally you can also install [Noir VS Code extension] for syntax highlighting. + +### Option 1: Noirup + +If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a +terminal and run: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done, 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. + +#### GitHub Actions + +You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as +installing `noirup` and running tests in your GitHub Action `yml` file. + +See the +[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in +this repo containing hash functions in Noir for an example. + +#### Nightly versions + +To install the nightly version of Noir (updated daily) run: + +```bash +noirup -n +``` + +### Option 2: Binaries + +See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous +platform specific binaries. + +#### Step 1 + +Paste and run the following in the terminal to extract and install the binary: + +> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend +> `sudo` and re-run it. + +##### macOS (Apple Silicon) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### macOS (Intel) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### Windows (PowerShell) + +Open PowerShell as Administrator and run: + +```powershell +mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` +Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` +Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` +$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` +$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` +$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` +Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +``` + +##### Linux (Bash) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ +echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ +source ~/.bashrc +``` + +#### Step 2 + +Check if the installation was successful by running `nargo --help`. + +> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from +> Finder. Close the new terminal popped up and `nargo` should now be accessible. + +For a successful installation, you should see something similar to the following after running the +command: + +```sh +$ nargo --help + +Noir's package manager + +Usage: nargo + +Commands: + check Checks the constraint system for errors + 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 new binary project + 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 + gates Counts the occurrences of different gates in circuit + help Print this message or the help of the given subcommand(s) +``` + +### Option 3: Install via Nix + +Due to the large number of native dependencies, Noir projects can be installed via [Nix](https://nixos.org/). + +#### Installing Nix + +For the best experience, please follow these instructions to setup Nix: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +#### Install Nargo into your Nix profile + +1. Use `nix profile` to install Nargo + +```sh +nix profile install github:noir-lang/noir +``` + +### Option 4: Compile from Source + +Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. + +#### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +3. Install direnv into your Nix profile by running: + +```sh +nix profile install nixpkgs#direnv +``` + +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). +5. Restart your shell. + +#### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: + +```sh +git clone git@github.com:noir-lang/noir +``` + +> Replacing `noir` with whichever repository you want to work on. + +2. Navigate to the directory: + +```sh +cd noir +``` + +> Replacing `noir` with whichever repository you cloned. + +3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: + +```sh +direnv allow +``` + +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. + +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): + +```sh +code . +``` + +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +#### Building and testing + +Assuming you are using `direnv` to populate your environment, building and testing the project can be done +with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. + +If you want to build the entire project in an isolated sandbox, you can use Nix commands: + +1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. +2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. + +#### Without `direnv` + +If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. + +Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! + +## Uninstalling Nargo + +### Noirup + +If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` + +### Nix + +If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. + +```bash +rm ~/.nix-profile/bin/nargo +``` + +[git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git +[rust]: https://www.rust-lang.org/tools/install +[noir vs code extension]: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir +[homebrew]: https://brew.sh/ +[cmake]: https://cmake.org/install/ +[llvm]: https://llvm.org/docs/GettingStarted.html +[openmp]: https://openmp.llvm.org/ +[barretenberg]: https://github.com/AztecProtocol/barretenberg diff --git a/docs/versioned_docs/version-0.7.1/getting_started/01_hello_world.md b/docs/versioned_docs/version-0.7.1/getting_started/01_hello_world.md new file mode 100644 index 00000000000..0f21ad45569 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/getting_started/01_hello_world.md @@ -0,0 +1,147 @@ +--- +title: Create 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, + ] +--- + +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 +``` + +For Windows CMD, run: + +```sh +> mkdir "%USERPROFILE%\projects" +> cd /d "%USERPROFILE%\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_ that contains 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](../language_concepts/data_types) 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](../language_concepts/comments) 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 on 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 with your preferred proof name, for example `p`: + +```sh +nargo prove p +``` + +A new folder _proofs_ would then be generated in your project directory, containing the proof file +`p.proof`. + +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 of name `p` by running: + +```sh +nargo verify p +``` + +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](breakdown), we will go into more detail on each step performed. diff --git a/docs/versioned_docs/version-0.7.1/getting_started/02_breakdown.md b/docs/versioned_docs/version-0.7.1/getting_started/02_breakdown.md new file mode 100644 index 00000000000..64d04c4e062 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/getting_started/02_breakdown.md @@ -0,0 +1,122 @@ +--- +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] +--- + +This section breaks down our hello world program in section _1.2_. We elaborate on the project +structure and what the `prove` and `verify` commands did in the previous section. + +## 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_ 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_ contains public in/output values computed when executing the Noir program. + +_Nargo.toml_ contains the environmental options of your project. + +_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 the satisfaction of the condition (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 my_proof` 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 not equal constraint is due to the line `assert(x != y)`. + +2. Noir creates and stores the proof of this statement in the _proofs_ directory and names the proof + file _my_proof_. Opening this file will display the proof in hex format. + +#### 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 proof `p`: + +```bash +nargo prove p +``` + +This command looks for proof inputs in the custom **OtherProver.toml** and generates proof `pp`: + +```bash +nargo prove -p OtherProver pp +``` + +## Verifying a Proof + +When the command `nargo verify my_proof` is executed, two processes happen: + +1. Noir checks in the _proofs_ directory for a file called _my_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 from usually external sources and +verifies the validity of the proof against it. + +Take a private asset transfer as an example: + +A user on browser as the prover would retrieve private inputs (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. + +In the [next section](language_server), we will explain how to utilize the Noir Language Server. diff --git a/docs/versioned_docs/version-0.7.1/getting_started/03_language_server.md b/docs/versioned_docs/version-0.7.1/getting_started/03_language_server.md new file mode 100644 index 00000000000..e6f5dfc2faa --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/getting_started/03_language_server.md @@ -0,0 +1,31 @@ +--- +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] +--- + +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). + +### 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-0.7.1/index.md b/docs/versioned_docs/version-0.7.1/index.md new file mode 100644 index 00000000000..e56b24bccd8 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/index.md @@ -0,0 +1,103 @@ +--- +title: Introducing Noir +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, + ] +slug: / +--- + +This version of the book is being released with the public alpha. There will be a lot of features +that are missing in this version, however the syntax and the feel of the language will mostly be +completed. + +## What is Noir? + +Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. + +It's design choices are influenced heavily by Rust and focuses on a simple, familiar syntax. + +## Who is Noir for? + +Noir can be used for a variety of purposes. + +### Solidity Developers + +Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will +be modularised in the future; however, as of the alpha, you can use the [`nargo codegen-verifier`](./nargo/commands#nargo-codegen-verifier) command to create +a verifier contract. + +### Protocol Developers + +As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for +your stack, or maybe you simply want to use a different proving system. Since Noir does not compile +to a specific proof system, it is possible for protocol developers to replace the PLONK-based +proving system with a different proving system altogether. + +### Blockchain developers + +As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the +proving system and smart contract language has been pre-defined). In order for you to use Noir in +your blockchain, a proving system backend and a smart contract interface +must be implemented for it. + +## What's new about Noir? + +Noir is simple and flexible in its design, as it does not compile immediately to a fixed +NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled +to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). + +This in itself brings up a few challenges within the design process, but allows one to decouple the programming language completely from the backend. This is similar in theory to LLVM. + +## Current Features + +Compiler: + +- Module System +- For expressions +- Arrays +- Bit Operations +- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Unsigned integers +- If statements +- Structures and Tuples +- Generics + +ACIR Supported OPCODES: + +- Sha256 +- Blake2s +- Schnorr signature verification +- MerkleMembership +- Pedersen +- HashToField + +## 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 + +See the section on [dependencies](./modules_packages_crates/dependencies) for more information. diff --git a/docs/versioned_docs/version-0.7.1/language_concepts/00_data_types.md b/docs/versioned_docs/version-0.7.1/language_concepts/00_data_types.md new file mode 100644 index 00000000000..6ac494ad404 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/00_data_types.md @@ -0,0 +1,305 @@ +--- +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, + field type, + integer types, + boolean type, + array type, + tuple type, + struct type, + ] +--- + +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`. + +## Primitive Types + +A primitive type represents a single value. They can be private or public. + +### Fields + +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. + +### Integers + +An integer type is a range constrained field type. The Noir frontend currently supports unsigned, +arbitrary-sized integer types. + +An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by +its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of +$\\([0,2^{32}-1]\\)$: + +```rust +fn main(x : Field, y : u32) { + let z = x as u32 + y; +} +``` + +`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` +are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created +will be rejected by the verifier. + +> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) +> sized integer types. + +### Booleans + +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. + +### Strings + +The string type is a fixed length value defined with `str`. + +You can use strings in `assert()` functions or print them with +`std::println()`. + +```rust +fn main(message : pub str<11>, hex_as_string : str<4>) { + std::println(message); + assert(message == "hello world"); + assert(hex_as_string == "0x41"); +} +``` + +## Compound Types + +A compound type groups together multiple values into one type. Elements within a compound type can +be private or public. + +### Arrays + +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); +} +``` + +#### 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. + +### Tuples + +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; +} +``` + +### Structs + +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. + +:::note +You can use Structs as inputs to the `main` function, but you can't output them +::: + +### BigInt + +You can acheive BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. diff --git a/docs/versioned_docs/version-0.7.1/language_concepts/01_functions.md b/docs/versioned_docs/version-0.7.1/language_concepts/01_functions.md new file mode 100644 index 00000000000..54c618599d2 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/01_functions.md @@ -0,0 +1,88 @@ +--- +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] +--- + +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() {} +``` + +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 : pub 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 : pub Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## 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); +``` diff --git a/docs/versioned_docs/version-0.7.1/language_concepts/02_control_flow.md b/docs/versioned_docs/version-0.7.1/language_concepts/02_control_flow.md new file mode 100644 index 00000000000..691c514d9a8 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/02_control_flow.md @@ -0,0 +1,42 @@ +--- +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] +--- + +## 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 +}; +``` + +## 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); +``` diff --git a/docs/versioned_docs/version-0.7.1/language_concepts/03_ops.md b/docs/versioned_docs/version-0.7.1/language_concepts/03_ops.md new file mode 100644 index 00000000000..da02b126059 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/03_ops.md @@ -0,0 +1,97 @@ +--- +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, + ] +--- + +# 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 indentically 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-0.7.1/language_concepts/04_assert.md b/docs/versioned_docs/version-0.7.1/language_concepts/04_assert.md new file mode 100644 index 00000000000..a25a946123d --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/04_assert.md @@ -0,0 +1,34 @@ +--- +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] +--- + +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); +} +``` + +The above snippet compiles because `==` is a predicate operation. Conversely, the following will not +compile: + +```rust +// INCORRECT + +fn main(x : Field, y : Field) { + assert(x + y); +} +``` + +> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should +> equate to `x + y == 0` or if it should check the truthiness of the result. diff --git a/docs/versioned_docs/version-0.7.1/language_concepts/06_generics.md b/docs/versioned_docs/version-0.7.1/language_concepts/06_generics.md new file mode 100644 index 00000000000..a4c207e09e4 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/06_generics.md @@ -0,0 +1,116 @@ +--- +title: Generics +description: + Learn how to use Generics in Noir +keywords: [Noir, Rust, generics, functions, structs] +--- + +# Generics + +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: comptime Field, +} + +impl RepeatedValue { + fn new(value: T) -> Self { + Self { value, count: 1 } + } + + fn increment(mut repeated: Self) -> Self { + repeated.count += 1; + repeated + } + + fn print(self) { + for _i in 0 .. self.count { + dep::std::println(self.value); + } + } +} + +fn main() { + let mut repeated = RepeatedValue::new("Hello!"); + repeated = repeated.increment(); + 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 + +Unlike Rust, Noir does not have traits, so how can one translate the equivalent of a trait bound in +Rust into Noir? That is, how can we write a function that is generic over some type `T`, while also +requiring there is a function like `eq: fn(T, T) -> bool` that works on the type? + +The answer is that we can translate this by passing in the function manually. Here's an example of +implementing array equality in Noir: + +```rust +fn array_eq(array1: [T; N], array2: [T; N], elem_eq: fn(T, T) -> bool) -> bool { + if array1.len() != array2.len() { + false + } else { + let mut result = true; + for i in 0 .. array1.len() { + result &= elem_eq(array1[i], array2[i]); + } + result + } +} + +fn main() { + assert(array_eq([1, 2, 3], [1, 2, 3], |a, b| a == b)); + + // We can use array_eq even for arrays of structs, as long as we have + // an equality function for these structs we can pass in + let array = [MyStruct::new(), MyStruct::new()]; + assert(array_eq(array, array, MyStruct::eq)); +} +``` + +You can see an example of generics in the tests +[here](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/generics/src/main.nr). diff --git a/docs/versioned_docs/version-0.7.1/language_concepts/07_mutability.md b/docs/versioned_docs/version-0.7.1/language_concepts/07_mutability.md new file mode 100644 index 00000000000..5631a322659 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/07_mutability.md @@ -0,0 +1,118 @@ +--- +title: Mutability +description: + Learn about mutable variables, constants, and globals in Noir programming language. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +--- + +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() -> Field { + let x = 3; + helper(x); + x // x is still 3 +} + +fn helper(mut x: i32) { + x = 4; +} +``` + +## Comptime Values + +Comptime values are values that are known at compile-time. This is different to a witness +which changes per proof. If a comptime value that is being used in your program is changed, then your +circuit will also change. + +Comptime is slightly different from Rust's `const`. Namely, it is a bit more flexible in that normal functions can accept comptime parameters. For example, this is used to verify an array index is known at compile-time. Note that the "known at compile-time" here means "known after function inlining is performed while optimizing the program" and not "known during type-checking." + +Below we show how to declare a comptime value: + +```rust +fn main() { + let a: comptime Field = 5; + + // `comptime Field` can also be inferred: + let a = 5; +} +``` + +Note that variables declared as mutable may not be comptime: + +```rust +fn main() { + // error: Cannot mark a comptime type as mutable + let mut a: comptime Field = 5; + + // a inferred as a private Field here + let mut a = 5; +} +``` + +## Globals + +Noir also supports global variables. However, they must be compile-time variables. If `comptime` is +not explicitly written in the type annotation the compiler will implicitly specify the declaration +as compile-time. They can then be used like any other compile-time variable inside functions. The +global type can also be inferred by the compiler entirely. Globals can also be used to specify array +annotations for function parameters and can be imported from submodules. + +```rust +global N: Field = 5; // Same as `global N: comptime Field = 5` + +fn main(x : Field, y : [Field; N]) { + let res = x * N; + + assert(res == y[0]); + + let res2 = x * mysubmodule::N; + assert(res != res2); +} + +mod mysubmodule { + use dep::std; + + global N: Field = 10; + + fn my_helper() -> comptime Field { + let x = N; + x + } +} +``` + +## Why only local mutability? + +Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting +without applying additional overhead to the user. Modeling a mutable reference is not as +straightforward as on conventional architectures and would incur some possibly unexpected overhead. diff --git a/docs/versioned_docs/version-0.7.1/language_concepts/08_comments.md b/docs/versioned_docs/version-0.7.1/language_concepts/08_comments.md new file mode 100644 index 00000000000..5b1d9fa38f2 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/08_comments.md @@ -0,0 +1,27 @@ +--- +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] +--- + +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 doesn't have multi-line comments, but you can emulate them via using `//` on each line + +```rust +// This is a multi line +// comment, that is ignored by +// the compiler +``` diff --git a/docs/versioned_docs/version-0.7.1/language_concepts/09_distinct.md b/docs/versioned_docs/version-0.7.1/language_concepts/09_distinct.md new file mode 100644 index 00000000000..03759d4bb4a --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/language_concepts/09_distinct.md @@ -0,0 +1,63 @@ +--- +title: Distinct Witnesses +--- + +The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures +that the witnesses being returned as public inputs are all unique. + +The `distinct` keyword is only used for return values on program entry points (usually the `main()` +function). + +When using `disctinct` and `pub` simultaneously, `distinct` comes first. See the example below. + +You can read more about the problem this solves +[here](https://github.com/noir-lang/noir/issues/1183). + +## Example + +Without the `distinct` keyword, the following program + +```rust +fn main(x : pub Field, y : pub Field) -> pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + "return_witnesses": [3, 2, 4, 4] + } +} +``` + +Whereas (with the `distinct` keyword) + +```rust +fn main(x : pub Field, y : pub Field) -> distinct pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + //... + "return_witnesses": [3, 4, 5, 6] + } +} +``` diff --git a/docs/versioned_docs/version-0.7.1/modules_packages_crates/crates_and_packages.md b/docs/versioned_docs/version-0.7.1/modules_packages_crates/crates_and_packages.md new file mode 100644 index 00000000000..34f28a71148 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/modules_packages_crates/crates_and_packages.md @@ -0,0 +1,35 @@ +--- +title: Crates and Packages +description: + Learn how to use Crates and Packages in your Noir project +keywords: [Nargo, dependencies, package management, crates, package] +--- + +## 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 one of two forms: a binary crate or a library crate. + +_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. + +_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. + +### 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-0.7.1/modules_packages_crates/dependencies.md b/docs/versioned_docs/version-0.7.1/modules_packages_crates/dependencies.md new file mode 100644 index 00000000000..2807ad52046 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/modules_packages_crates/dependencies.md @@ -0,0 +1,110 @@ +--- +title: Managing 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] +--- + +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"} +``` + +## 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 + +``` +β”œβ”€β”€ binary_crate +β”‚Β Β  β”œβ”€β”€ Nargo.toml +β”‚Β Β  └── src +β”‚Β Β  └── main.nr +└── liba + β”œβ”€β”€ Nargo.toml + └── src + └── lib.nr +``` + +Inside of the binary crate, you can specify: + +```toml +# Nargo.toml + +[dependencies] +libA = { path = "../liba" } +``` + +## 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 liba referenced above: + +```rust +use dep::ecrecover; +use dep::libA; +``` + +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; +``` + +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}; +``` + +## 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-0.7.1/modules_packages_crates/modules.md b/docs/versioned_docs/version-0.7.1/modules_packages_crates/modules.md new file mode 100644 index 00000000000..e429b336511 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/modules_packages_crates/modules.md @@ -0,0 +1,104 @@ +--- +title: Understanding 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] +--- + +# Modules + +Noir's module system follows the same convention as the _newer_ version of Rust's module system. + +## Purpose of Modules + +Modules are used to organise 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-0.7.1/nargo/01_commands.md b/docs/versioned_docs/version-0.7.1/nargo/01_commands.md new file mode 100644 index 00000000000..8efa286b5f0 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/nargo/01_commands.md @@ -0,0 +1,132 @@ +--- +title: Commands +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, + ] +--- + +## General options + +``` +Options: + -s, --show-ssa Emit debug information for the intermediate SSA IR + -d, --deny-warnings Quit execution when warnings are emitted + --show-output Display output of `println` statements during tests + -h, --help Print help +``` + +## `nargo help [subcommand]` + +Prints the list of available commands or specific information of a subcommand. + +_Arguments_ + +- `` - The subcommand whose help message to display + +## `nargo check` + +Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output +values of the Noir program respectively. + +## `nargo codegen-verifier` + +Generate a Solidity verifier smart contract for the program. + +## `nargo compile ` + +Compile the program into a JSON build artifact file containing the ACIR representation and the ABI +of the circuit. This build artifact can then be used to generate and verify proofs. + +_Arguments_ + +- `` - The name of the circuit file + +_Options_ + +- `-c, --contracts` - Compile each contract function used within the program +- `--print-acir` - Displays the ACIR for the compiled circuit + +## `nargo new [path]` + +Creates a new Noir project. + +_Arguments_ + +- `` - Name of the package +- `[path]` - The path to save the new project + +## `nargo execute [witness_name]` + +Runs the Noir program and prints its return value. + +_Arguments_ + +- `[witness_name]` - The name of the witness + +_Usage_ + +The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which +must be filled in. + +To save the witness to file, run the command with a value for the `witness-name` argument. A +`.tr` file will then be saved in the `build` folder. + +> **Info:** The `.tr` file is the witness file. The witness file can be considered as program inputs +> parsed for your program's ACIR. +> +> This file can be passed along with circuit's ACIR into a TypeScript project for proving and +> verification. See the [TypeScript](../typescript#proving-and-verifying-externally-compiled-files) +> section to learn more. + +## `nargo prove ` + +Creates a proof for the program. + +_Arguments_ + +- `` - The name of the proof + +_Options_ + +- `-v, --verify` - Verify proof after proving + +## `nargo verify ` + +Given a proof and a program, verify whether the proof is valid. + +_Arguments_ + +- `` - The proof to verify + +## `nargo test ` + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. + +See an example on the [testing page](./testing). + +_Arguments_ + +- `` - a pattern to indicate to only run tests with names containing the pattern + +## `nargo gates` + +Counts the occurrences of different gates in circuit + +## `nargo lsp` + +Start a long-running Language Server process that communicates over stdin/stdout. +Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). diff --git a/docs/versioned_docs/version-0.7.1/nargo/02_testing.md b/docs/versioned_docs/version-0.7.1/nargo/02_testing.md new file mode 100644 index 00000000000..ba0bebd658b --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/nargo/02_testing.md @@ -0,0 +1,32 @@ +--- +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] +--- + +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 the all +the contraints which allows you to test that add returns the expected values. Test functions can't +have any arguments currently. + +This is much faster compared to testing in Typescript but the only downside is that you can't +explicitly test that a certain set of inputs are invalid. i.e. you can't say that you want +add(2^64-1, 2^64-1) to fail. diff --git a/docs/versioned_docs/version-0.7.1/nargo/03_solidity_verifier.md b/docs/versioned_docs/version-0.7.1/nargo/03_solidity_verifier.md new file mode 100644 index 00000000000..9ac60cb0ba7 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/nargo/03_solidity_verifier.md @@ -0,0 +1,129 @@ +--- +title: 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, + ] +--- + +For certain applications, it may be desirable to run the verifier as a smart contract instead of on +a local machine. + +Compile a Solidity verifier contract for your Noir program by running: + +```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 on any EVM blockchain acting as a verifier smart contract. + +> **Note:** It is possible to compile 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 compilation of verifier contracts in +> Solidity only for the time being. + +## Verify + +To verify a proof using the Solidity verifier contract, call the `verify` function with the +following signature: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +You can see an example of how the `verify` function is called 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"); +``` + +### Public Inputs + +:::tip + +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. + +::: + +The verifier contract uses the output (return) value of a Noir program as a public input. So if you +have the following function + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +then `verify` in `plonk_vk.sol` will expect 3 public inputs. Passing two inputs will result in an +error like `Reason: PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case the 3 inputs to `verify` would be ordered as `[pubkey_x, pubkey_y, return]`. + +#### Struct inputs + +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) { + //... +} +``` + +Structs will be flattened so that the array of inputs is 1-dimensional array. The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +## Noir for EVM chains + +You can currently deploy the Solidity verifier contracts to most EVM compatible chains. EVM chains that have been tested and are known to work include: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +Other EVM chains should work, but have not been tested directly by our team. 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. + +### Unsupported chains + +Unfortunately not all "EVM" chains are supported. + +**zkSync** and the **Polygon zkEVM** do _not_ currently support proof verification via Solidity verifier contracts. They are missing the bn256 precompile contract that the verifier contract requires. Once these chains support this precompile, they may work. diff --git a/docs/versioned_docs/version-0.7.1/standard_library/array_methods.md b/docs/versioned_docs/version-0.7.1/standard_library/array_methods.md new file mode 100644 index 00000000000..8d8a9531243 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/array_methods.md @@ -0,0 +1,180 @@ +--- +title: Array Methods +description: + Learn about the commonly used methods available for arrays in Noir, including len, sort, fold, + reduce, all, and any. +keywords: [rust, array, methods, len, sort, fold, reduce, all, any] +--- + +# Array + +For convenience, the STD provides some ready-to-use, common methods for arrays[^migrationnote]: + +## len + +Returns the length of an array + +```rust +fn len(_array: [T; N]) -> comptime 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(_array: [T; N]) -> [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(mut a: [T; N], 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(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(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(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(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(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); +} + +``` + +[^migrationnote]: + Migration Note: These methods were previously free functions, called via `std::array::len()`. + For the sake of ease of use and readability, these functions are now methods and the old syntax + for them is now deprecated. diff --git a/docs/versioned_docs/version-0.7.1/standard_library/black_box_fns.md b/docs/versioned_docs/version-0.7.1/standard_library/black_box_fns.md new file mode 100644 index 00000000000..3063e71c147 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/black_box_fns.md @@ -0,0 +1,44 @@ +--- +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. + +:::warning + +It is likely that not all backends will support a particular black box function. + +::: + +Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. + +Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: + +```rust +#[foreign(sha256)] +fn sha256(_input : [u8; N]) -> [u8; 32] {} +``` + +## Function list + +Here is a list of the current black box functions that are supported by UltraPlonk: + +- AES +- [SHA256](./cryptographic_primitives/hashes#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr) +- [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Pedersen](./cryptographic_primitives/hashes#pedersen) +- [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_secp256k1) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [Compute merkle root](./merkle_trees#compute_merkle_root) +- AND +- XOR +- RANGE +- [Keccak256](./cryptographic_primitives/hashes#keccak256) + +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. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. + +You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/acvm/blob/acir-v0.12.0/acir/src/circuit/black_box_functions.rs). diff --git a/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives.md b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives.md new file mode 100644 index 00000000000..2df4f929474 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives.md @@ -0,0 +1,14 @@ +--- +title: Cryptographic primitives in Noir +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-0.7.1/standard_library/cryptographic_primitives/00_hashes.mdx b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/00_hashes.mdx new file mode 100644 index 00000000000..31a84cdb753 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/00_hashes.mdx @@ -0,0 +1,146 @@ +--- +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] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +## sha256 + +Given an array of bytes, returns the resulting sha256 hash. + +```rust +fn sha256(_input : [u8]) -> [u8; 32] +``` + +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 +fn blake2s(_input : [u8]) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let hash = std::hash::blake2s(x); +} +``` + + + +## pedersen + +Given an array of Fields, returns the Pedersen hash. + +```rust +fn pedersen(_input : [Field]) -> [Field; 2] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let hash = std::hash::pedersen(x); +} +``` + + + +## 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 +fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let message_size = 4; + let hash = std::hash::keccak256(x, message_size); +} +``` + + + +## 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 +fn main() +{ + let hash1 = std::hash::poseidon::bn254::hash_2([1, 2]); + assert(hash1 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); +} +``` + +## 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_bn254(x); +} +``` + +## hash_to_field + +```rust +fn hash_to_field(_input : [Field; N]) -> 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-0.7.1/standard_library/cryptographic_primitives/01_scalar.mdx b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/01_scalar.mdx new file mode 100644 index 00000000000..62265cddb1e --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/01_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, + ] +--- + +import BlackBoxInfo from './common/\_blackbox.mdx'; + +## scalar_mul::fixed_base + +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 +fn fixed_base(_input : Field) -> [Field; 2] +``` + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base(x); + std::println(scal); +} +``` + + diff --git a/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/02_schnorr.mdx b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/02_schnorr.mdx new file mode 100644 index 00000000000..0e219c0e5ff --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/02_schnorr.mdx @@ -0,0 +1,37 @@ +--- +title: Schnorr Signatures +description: Learn how you can verify Schnorr signatures using Noir +keywords: [cryptographic primitives, Noir project, schnorr, signatures] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +## schnorr::verify_signature + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). + +```rust +fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool +``` + +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() +); + +... +``` + + diff --git a/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx new file mode 100644 index 00000000000..0b800fdbc5f --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/03_ecdsa_secp256k1.mdx @@ -0,0 +1,17 @@ +--- +title: ECDSA Verification +description: Learn about the cryptographic primitives regarding ECDSA over the secp256k1 curve +keywords: [cryptographic primitives, Noir project, ecdsa, secp256k1, signatures] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +## ecdsa_secp256k1::verify_signature + +Verifier for ECDSA Secp256k1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + + diff --git a/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/04_ec_primitives.md b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/04_ec_primitives.md new file mode 100644 index 00000000000..26fb4c09e88 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -0,0 +1,101 @@ +--- +title: Elliptic Curve Primitives +keywords: [cryptographic primitives, Noir project] +--- + +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 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/crates/nargo_cli/tests/test_data/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-0.7.1/standard_library/cryptographic_primitives/05_eddsa.mdx b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/05_eddsa.mdx new file mode 100644 index 00000000000..8f060ed3316 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/05_eddsa.mdx @@ -0,0 +1,17 @@ +--- +title: EdDSA Verification +description: Learn about the cryptographic primitives regarding EdDSA +keywords: [cryptographic primitives, Noir project, eddsa, signatures] +--- + +import BlackBoxInfo from './common/_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 +``` + + diff --git a/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/common/_blackbox.mdx b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/common/_blackbox.mdx new file mode 100644 index 00000000000..9fe9b48fbff --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/cryptographic_primitives/common/_blackbox.mdx @@ -0,0 +1,5 @@ +:::info + +This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. + +::: \ No newline at end of file diff --git a/docs/versioned_docs/version-0.7.1/standard_library/field_methods.md b/docs/versioned_docs/version-0.7.1/standard_library/field_methods.md new file mode 100644 index 00000000000..4d1cdc953e9 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/field_methods.md @@ -0,0 +1,149 @@ +--- +title: Field Methods +description: + Learn about common methods on Noir Field, including to_le_bits, to_le_bytes, to_le_radix, + to_be_radix, pow_32, etc, and see code examples. +keywords: + [ + Noir Field, + to_le_bits, + to_le_bytes, + to_le_radix, + to_be_radix, + pow_32, + Little Endian, + Big Endian, + Vector, + Exponent, + ] +--- + +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; N] +``` + +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; N] +``` + +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); +} +``` + +## 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 +``` diff --git a/docs/versioned_docs/version-0.7.1/standard_library/logging.md b/docs/versioned_docs/version-0.7.1/standard_library/logging.md new file mode 100644 index 00000000000..649d35a3f0b --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/logging.md @@ -0,0 +1,55 @@ +--- +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, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +# Logging + +The standard library provides a familiar `println` statement you can use. Despite being a limited +implementation of rust's `println!` macro, this construct can be useful for debugging. + +The `println` statement only works for fields, integers and arrays (including strings). + +```rust +use dep::std; + +fn main(string: pub str<5>) { + let x = 5; + std::println(x) +} + +``` + +To view the output of the `println` statement you need to set the `--show-output` flag. + +``` +$ nargo prove --help +Create proof for this program. The proof is returned as a hex encoded string + +Usage: nargo prove [OPTIONS] [PROOF_NAME] [CIRCUIT_NAME] + +Arguments: + [PROOF_NAME] The name of the proof + [CIRCUIT_NAME] The name of the circuit build files (ACIR, proving and verification keys) + +Options: + -v, --verify Verify proof after proving + -s, --show-ssa Emit debug information for the intermediate SSA IR + -d, --deny-warnings Quit execution when warnings are emitted + --show-output Display output of `println` statements during tests + -h, --help Print help +``` diff --git a/docs/versioned_docs/version-0.7.1/standard_library/merkle_trees.md b/docs/versioned_docs/version-0.7.1/standard_library/merkle_trees.md new file mode 100644 index 00000000000..fc8909a4795 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/merkle_trees.md @@ -0,0 +1,59 @@ +--- +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/00_hashes.mdx#pedersen). + +```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(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); + std::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). \ No newline at end of file diff --git a/docs/versioned_docs/version-0.7.1/standard_library/zeroed.md b/docs/versioned_docs/version-0.7.1/standard_library/zeroed.md new file mode 100644 index 00000000000..97dab02dac2 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/standard_library/zeroed.md @@ -0,0 +1,25 @@ +--- +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 +- String +- Tuple +- Function + +Using it on other types could result in unexpected behavior. diff --git a/docs/versioned_docs/version-0.7.1/typescript.md b/docs/versioned_docs/version-0.7.1/typescript.md new file mode 100644 index 00000000000..fae002dfd28 --- /dev/null +++ b/docs/versioned_docs/version-0.7.1/typescript.md @@ -0,0 +1,262 @@ +--- +title: Working with TypeScript +description: + Learn how to interact with Noir programs using TypeScript. Follow this tutorial to compile your + program, specify inputs, initialize a prover & verifier, and prove and verify your program. +keywords: [TypeScript, Noir, tutorial, compile, inputs, prover, verifier, proof] +--- + +Interactions with Noir programs can also be performed in TypeScript, which can come in handy when +writing tests or when working in TypeScript-based projects like [Hardhat](https://hardhat.org/). + +This guide is based on the [noir-starter](https://github.com/signorecello/noir-starter) example. +Please refer to it for an example implementation. + +:::note + +You may find unexpected errors working with some frameworks such as `vite`. This is due to the +nature of `wasm` files and the way Noir uses web workers. As we figure it out, we suggest using +[Create React App](https://create-react-app.dev/), or [Next.js](https://nextjs.org/) for a quick +start. + +::: + +## Setup + +We're assuming you're using ES6 for both browser (for example with React), or nodejs. + +Install [Yarn](https://yarnpkg.com/) or [Node.js](https://nodejs.org/en). Init a new project with +`npm init`. Install Noir dependencies in your project by running: + +```bash +npm i @noir-lang/noir_wasm@0.3.2-fa0e9cff github:noir-lang/barretenberg#39a1547875f941ef6640217a42d8f34972425c97 @noir-lang/aztec_backend@0.1.0-0c3b2f2 +``` + +:::note + +While Noir is in rapid development, some packages could interfere with others. For that reason, you +should use these specified versions. Let us know if for some reason you need to use other ones. + +::: + +As for the circuit, we will use the _Standard Noir Example_ and place it in the `src` folder. Feel +free to use any other, as long as you refactor the below examples accordingly. + +This standard example is a program that multiplies input `x` with input `y` and returns the result: + +```rust +// src/main.nr +fn main(x: u32, y: pub u32) -> pub u32 { + let z = x * y; + z +} +``` + +One valid scenario for proving could be `x = 3`, `y = 4` and `return = 12` + +## Imports + +We need some imports, for both the `noir_wasm` library (which will compile the circuit into `wasm` +executables) and `aztec_backend` which is the actual proving backend we will be using. + +We also need to tell the compiler where to find the `.nr` files, so we need to import +`initialiseResolver`. + +```ts +import initNoirWasm, { acir_read_bytes, compile } from '@noir-lang/noir_wasm'; +import initialiseAztecBackend from '@noir-lang/aztec_backend'; +import { initialiseResolver } from '@noir-lang/noir-source-resolver'; +``` + +## Compiling + +We'll go over the code line-by-line later: + +```ts +export const compileCircuit = async () => { + await initNoirWasm(); + + return await fetch(new URL('../src/main.nr', import.meta.url)) + .then(r => r.text()) + .then(code => { + initialiseResolver((id: any) => { + return code; + }); + }) + .then(() => { + try { + const compiled_noir = compile({}); + return compiled_noir; + } catch (e) { + console.log('Error while compiling:', e); + } + }); +}; +``` + +1. First we're calling `initNoirWasm`. This is required on the browser only. +2. We then pass an URL that points to our `main.nr` file, and call `.then` on it so we can get the + actual text of the source code +3. We call `initialiseResolver` returning the source code +4. Finally, we can call the `compile` function + +This function should return us the compiled circuit. + +:::note + +You can use as many files as you need, +[importing them as you would do with Nargo](./modules_packages_crates/dependencies), and you don't +need to set them up in the `src` folder. Just mind the following particularities about +`initialiseResolver`: + +1. The `compile` function expects a `main.nr` file as an entry point. If you need another one, just + pass it as a `entry_point` parameter to `compile`. Check the + [noir starter](https://github.com/signorecello/noir-starter) for an example on multiple files and + a non-default entry point. +2. `initialiseResolver` needs to be synchronous +3. Different frameworks use different ways of fetching files. It's beyond the scope of this guide to + explain why and how, but for reference, + [noir starter](https://github.com/signorecello/noir-starter) uses both Next.js and node.js for + testing. + +Quick tip: an easy way to deal with `initialiseResolver` is just to prepare a +`{fileName: "literally_the_code"}` object beforehand + +::: + +## ACIR + +Noir compiles to two properties: + +1. The ACIR, which is the intermediate language used by backends such as Barretenberg +2. The ABI, which tells you which inputs are to be read + +Let's write a little function that gets us both, initializes the backend, and returns the ACIR as +bytes: + +```ts +export const getAcir = async () => { + const { circuit, abi } = await compileCircuit(); + await initialiseAztecBackend(); + + let acir_bytes = new Uint8Array(Buffer.from(circuit, 'hex')); + return acir_read_bytes(acir_bytes); +}; +``` + +Calling `getAcir()` now should return us the ACIR of the circuit, ready to be used in proofs. + +## Initializing Prover & Verifier + +Prior to proving and verifying, the prover and verifier have to first be initialized by calling +`barretenberg`'s `setup_generic_prover_and_verifier` with your Noir program's ACIR: + +```ts +let [prover, verifier] = await setup_generic_prover_and_verifier(acir); +``` + +This is probably a good time to store this prover and verifier into your state like React Context, +Redux, or others. + +## Proving + +The Noir program can then be executed and proved by calling `barretenberg`'s `create_proof` +function: + +```ts +const proof = await create_proof(prover, acir, abi); +``` + +On the browser, this proof can fail as it requires heavy loads to be run on worker threads. Here's a +quick example of a worker: + +```ts +// worker.ts +onmessage = async event => { + try { + await initializeAztecBackend(); + const { acir, input } = event.data; + const [prover, verifier] = await setup_generic_prover_and_verifier(acir); + const proof = await create_proof(prover, acir, input); + postMessage(proof); + } catch (er) { + postMessage(er); + } finally { + close(); + } +}; +``` + +Which would be called like this, for example: + +```ts +// index.ts +const worker = new Worker(new URL('./worker.ts', import.meta.url)); +worker.onmessage = e => { + if (e.data instanceof Error) { + // oh no! + } else { + // yey! + } +}; +worker.postMessage({ acir, input: { x: 3, y: 4 } }); +``` + +## Verifying + +The `proof` obtained can be verified by calling `barretenberg`'s `verify_proof` function: + +```ts +// 1_mul.ts +const verified = await verify_proof(verifier, proof); +``` + +The function should return `true` if the entire process is working as intended, which can be +asserted if you are writing a test script: + +```ts +expect(verified).eq(true); +``` + +## Verifying with Smart Contract + +Alternatively, a verifier smart contract can be generated and used for verifying Noir proofs in +TypeScript as well. + +This could be useful if the Noir program is designed to be decentrally verified and/or make use of +decentralized states and logics that is handled at the smart contract level. + +To generate the verifier smart contract using typescript: + +```ts +// generator.ts +import { writeFileSync } from 'fs'; + +const sc = verifier.SmartContract(); +syncWriteFile('../contracts/plonk_vk.sol', sc); + +function syncWriteFile(filename: string, data: any) { + writeFileSync(join(__dirname, filename), data, { + flag: 'w', + }); +} +``` + +You can then verify a Noir proof using the verifier contract, for example using Hardhat: + +```ts +// verifier.ts +import { ethers } from 'hardhat'; +import { Contract, ContractFactory, utils } from 'ethers'; + +let Verifier: ContractFactory; +let verifierContract: Contract; + +before(async () => { + Verifier = await ethers.getContractFactory('TurboVerifier'); + verifierContract = await Verifier.deploy(); +}); + +// Verify proof +const sc_verified = await verifierContract.verify(proof); +``` diff --git a/docs/versioned_docs/version-0.9.0/examples/merkle-proof.mdx b/docs/versioned_docs/version-0.9.0/examples/merkle-proof.mdx new file mode 100644 index 00000000000..6430780817c --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/examples/merkle-proof.mdx @@ -0,0 +1,48 @@ +--- +title: Merkle Proof 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] +--- + +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); + 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` +instead. + +```rust +let leaf = std::hash::hash_to_field(message); +``` + +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-0.9.0/getting_started/00_nargo_installation.md b/docs/versioned_docs/version-0.9.0/getting_started/00_nargo_installation.md new file mode 100644 index 00000000000..de30869732d --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/getting_started/00_nargo_installation.md @@ -0,0 +1,285 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs (e.g. compiling, proving, + verifying and more). Learn how to install and use Nargo for your projects with this comprehensive + guide. +keywords: [Nargo, command line tool, Noir programs, installation guide, how to use Nargo] +--- + +`nargo` is a command line tool for interacting with Noir programs (e.g. compiling, proving, +verifying and more). + +Alternatively, the interactions can also be performed in [TypeScript](../typescript). + +### UltraPlonk + +Nargo versions <0.5.0 of `aztec_backend` and `aztec_wasm_backend` are based on the TurboPlonk +version of Aztec Backend, which lacks efficient implementations of useful primitives (e.g. Keccak256 in 18k constraints, ECDSA verification in 36k constraints) that the UltraPlonk version offers. + +## Installation + +There are four approaches for installing Nargo: + +- [Option 1: Noirup](#option-1-noirup) +- [Option 2: Binaries](#option-2-binaries) +- [Option 3: Install via Nix](#option-3-install-via-nix) +- [Option 4: Compile from Source](#option-4-compile-from-source) + +Optionally you can also install [Noir VS Code extension] for syntax highlighting. + +### Option 1: Noirup + +If you're on OSX or Linux, the easiest way to start using Noir and Nargo is via noirup. Just open a +terminal and run: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done, 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. + +#### GitHub Actions + +You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as +installing `noirup` and running tests in your GitHub Action `yml` file. + +See the +[config file](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) in +this repo containing hash functions in Noir for an example. + +#### Nightly versions + +To install the nightly version of Noir (updated daily) run: + +```bash +noirup -n +``` + +### Option 2: Binaries + +See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous +platform specific binaries. + +#### Step 1 + +Paste and run the following in the terminal to extract and install the binary: + +> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend +> `sudo` and re-run it. + +##### macOS (Apple Silicon) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### macOS (Intel) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### Windows (PowerShell) + +Open PowerShell as Administrator and run: + +```powershell +mkdir -f -p "$env:USERPROFILE\.nargo\bin\"; ` +Invoke-RestMethod -Method Get -Uri https://github.com/noir-lang/noir/releases/download/v0.4.1/nargo-x86_64-pc-windows-msvc.zip -Outfile "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip"; ` +Expand-Archive -Path "$env:USERPROFILE\.nargo\bin\nargo-x86_64-pc-windows-msvc.zip" -DestinationPath "$env:USERPROFILE\.nargo\bin\"; ` +$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"; ` +$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path; ` +$NewPath = $OldPath + ’;’ + "$env:USERPROFILE\.nargo\bin\"; ` +Set-ItemProperty -Path "$Reg" -Name PATH –Value "$NewPath"; ` +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +``` + +##### Linux (Bash) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ +echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ +source ~/.bashrc +``` + +#### Step 2 + +Check if the installation was successful by running `nargo --help`. + +> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from +> Finder. Close the new terminal popped up and `nargo` should now be accessible. + +For a successful installation, you should see something similar to the following after running the +command: + +```sh +$ nargo --help + +Noir's package manager + +Usage: nargo + +Commands: + check Checks the constraint system for errors + 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 new binary project + 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 + gates Counts the occurrences of different gates in circuit + help Print this message or the help of the given subcommand(s) +``` + +### Option 3: Install via Nix + +Due to the large number of native dependencies, Noir projects can be installed via [Nix](https://nixos.org/). + +#### Installing Nix + +For the best experience, please follow these instructions to setup Nix: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +#### Install Nargo into your Nix profile + +1. Use `nix profile` to install Nargo + +```sh +nix profile install github:noir-lang/noir +``` + +### Option 4: Compile from Source + +Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. + +#### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +3. Install direnv into your Nix profile by running: + +```sh +nix profile install nixpkgs#direnv +``` + +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). + 1. For bash or zshell, add `eval "$(direnv hook bash)"` or `eval "$(direnv hook zsh)"` to your ~/.bashrc or ~/.zshrc file, respectively. +5. Restart your shell. + +#### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: + +```sh +git clone git@github.com:noir-lang/noir +``` + +> Replacing `noir` with whichever repository you want to work on. + +2. Navigate to the directory: + +```sh +cd noir +``` + +> Replacing `noir` with whichever repository you cloned. + +3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: + +```sh +direnv allow +``` + +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. + +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): + +```sh +code . +``` + +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +#### Building and testing + +Assuming you are using `direnv` to populate your environment, building and testing the project can be done +with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `flake.nix`, which is 1.66.0 at the time of this writing. + +If you want to build the entire project in an isolated sandbox, you can use Nix commands: + +1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. +2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. + +#### Without `direnv` + +If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. + +Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! + +## Uninstalling Nargo + +### Noirup + +If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` + +### Nix + +If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. + +```bash +rm ~/.nix-profile/bin/nargo +``` + +[git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git +[rust]: https://www.rust-lang.org/tools/install +[noir vs code extension]: https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir +[homebrew]: https://brew.sh/ +[cmake]: https://cmake.org/install/ +[llvm]: https://llvm.org/docs/GettingStarted.html +[openmp]: https://openmp.llvm.org/ +[barretenberg]: https://github.com/AztecProtocol/barretenberg diff --git a/docs/versioned_docs/version-0.9.0/getting_started/01_hello_world.md b/docs/versioned_docs/version-0.9.0/getting_started/01_hello_world.md new file mode 100644 index 00000000000..0f21ad45569 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/getting_started/01_hello_world.md @@ -0,0 +1,147 @@ +--- +title: Create 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, + ] +--- + +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 +``` + +For Windows CMD, run: + +```sh +> mkdir "%USERPROFILE%\projects" +> cd /d "%USERPROFILE%\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_ that contains 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](../language_concepts/data_types) 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](../language_concepts/comments) 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 on 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 with your preferred proof name, for example `p`: + +```sh +nargo prove p +``` + +A new folder _proofs_ would then be generated in your project directory, containing the proof file +`p.proof`. + +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 of name `p` by running: + +```sh +nargo verify p +``` + +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](breakdown), we will go into more detail on each step performed. diff --git a/docs/versioned_docs/version-0.9.0/getting_started/02_breakdown.md b/docs/versioned_docs/version-0.9.0/getting_started/02_breakdown.md new file mode 100644 index 00000000000..7c320cef9c5 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/getting_started/02_breakdown.md @@ -0,0 +1,154 @@ +--- +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] +--- + +This section breaks down our hello world program in section _1.2_. We elaborate on the project +structure and what the `prove` and `verify` commands did in the previous section. + +## 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_ 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_ contains public in/output values computed when executing the Noir program. + +_Nargo.toml_ contains the environmental options of your project. + +_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 the satisfaction of the condition (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 my_proof` 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 not equal constraint is due to the line `assert(x != y)`. + +2. Noir creates and stores the proof of this statement in the _proofs_ directory and names the proof + file _my_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 proof `p`: + +```bash +nargo prove p +``` + +This command looks for proof inputs in the custom **OtherProver.toml** and generates proof `pp`: + +```bash +nargo prove -p OtherProver pp +``` + +## Verifying a Proof + +When the command `nargo verify my_proof` is executed, two processes happen: + +1. Noir checks in the _proofs_ directory for a file called _my_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 from usually external sources and +verifies the validity of the proof against it. + +Take a private asset transfer as an example: + +A user on browser as the prover would retrieve private inputs (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. + +In the [next section](language_server), we will explain how to utilize the Noir Language Server. diff --git a/docs/versioned_docs/version-0.9.0/getting_started/03_language_server.md b/docs/versioned_docs/version-0.9.0/getting_started/03_language_server.md new file mode 100644 index 00000000000..e6f5dfc2faa --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/getting_started/03_language_server.md @@ -0,0 +1,31 @@ +--- +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] +--- + +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). + +### 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-0.9.0/index.md b/docs/versioned_docs/version-0.9.0/index.md new file mode 100644 index 00000000000..e56b24bccd8 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/index.md @@ -0,0 +1,103 @@ +--- +title: Introducing Noir +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, + ] +slug: / +--- + +This version of the book is being released with the public alpha. There will be a lot of features +that are missing in this version, however the syntax and the feel of the language will mostly be +completed. + +## What is Noir? + +Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. + +It's design choices are influenced heavily by Rust and focuses on a simple, familiar syntax. + +## Who is Noir for? + +Noir can be used for a variety of purposes. + +### Solidity Developers + +Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will +be modularised in the future; however, as of the alpha, you can use the [`nargo codegen-verifier`](./nargo/commands#nargo-codegen-verifier) command to create +a verifier contract. + +### Protocol Developers + +As a protocol developer, you may not want to use the Aztec backend due to it not being a fit for +your stack, or maybe you simply want to use a different proving system. Since Noir does not compile +to a specific proof system, it is possible for protocol developers to replace the PLONK-based +proving system with a different proving system altogether. + +### Blockchain developers + +As a blockchain developer, you will be constrained by parameters set by your blockchain (for example, the +proving system and smart contract language has been pre-defined). In order for you to use Noir in +your blockchain, a proving system backend and a smart contract interface +must be implemented for it. + +## What's new about Noir? + +Noir is simple and flexible in its design, as it does not compile immediately to a fixed +NP-complete language. Instead, Noir compiles to an intermediate language (ACIR), which itself can be compiled +to an arithmetic circuit (if choosing to target Aztec's barretenberg backend) or a rank-1 constraint system (if choosing to target an R1CS backend like Arkwork's Marlin backend, or others). + +This in itself brings up a few challenges within the design process, but allows one to decouple the programming language completely from the backend. This is similar in theory to LLVM. + +## Current Features + +Compiler: + +- Module System +- For expressions +- Arrays +- Bit Operations +- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Unsigned integers +- If statements +- Structures and Tuples +- Generics + +ACIR Supported OPCODES: + +- Sha256 +- Blake2s +- Schnorr signature verification +- MerkleMembership +- Pedersen +- HashToField + +## 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 + +See the section on [dependencies](./modules_packages_crates/dependencies) for more information. diff --git a/docs/versioned_docs/version-0.9.0/language_concepts/00_data_types.md b/docs/versioned_docs/version-0.9.0/language_concepts/00_data_types.md new file mode 100644 index 00000000000..abbadca86be --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/00_data_types.md @@ -0,0 +1,405 @@ +--- +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, + field type, + integer types, + boolean type, + array type, + tuple type, + struct type, + ] +--- + +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`. + +## Primitive Types + +A primitive type represents a single value. They can be private or public. + +### Fields + +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. + +### Integers + +An integer type is a range constrained field type. The Noir frontend currently supports unsigned, +arbitrary-sized integer types. + +An integer type is specified first with the letter `u`, indicating its unsigned nature, followed by +its length in bits (e.g. `32`). For example, a `u32` variable can store a value in the range of +$\\([0,2^{32}-1]\\)$: + +```rust +fn main(x : Field, y : u32) { + let z = x as u32 + y; +} +``` + +`x`, `y` and `z` are all private values in this example. However, `x` is a field while `y` and `z` +are unsigned 32-bit integers. If `y` or `z` exceeds the range $\\([0,2^{32}-1]\\)$, proofs created +will be rejected by the verifier. + +> **Note:** The default backend supports both even (e.g. `u16`, `u48`) and odd (e.g. `u5`, `u3`) +> sized integer types. + +### Booleans + +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. + +### Strings + +The string type is a fixed length value defined with `str`. + +You can use strings in `assert()` functions or print them with +`std::println()`. + +```rust +fn main(message : pub str<11>, hex_as_string : str<4>) { + std::println(message); + assert(message == "hello world"); + assert(hex_as_string == "0x41"); +} +``` + +## Compound Types + +A compound type groups together multiple values into one type. Elements within a compound type can +be private or public. + +### Arrays + +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]; +``` + +#### 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. + +### Slices + +:::caution + +This feature is experimental. You should expect it to change in future versions, +cause unexpected behavior, or simply not work at all. + +::: + +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. + +Slices are part of the [noir standard library](../standard_library/slice_methods) so you need to import the respective module in order to work with it. For example: + +```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() +} +``` + +### Vectors + +:::caution + +This feature is experimental. You should expect it to change in future versions, +cause unexpected behavior, or simply not work at all. + +::: + +A vector is a collection type similar to Rust's Vector type. It's convenient way to use slices as mutable arrays. + +Example: + +```rust +use std::collections::vec::Vec; + +let mut vector: Vec = Vec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +``` + +### Tuples + +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; +} +``` + +### Structs + +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. + +:::note +You can use Structs as inputs to the `main` function, but you can't output them +::: + +### 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](./06_generics.md): + +```rust +type Id = Size; + +fn main() { + let id: Id = 1; + let zero: u32 = 0; + assert(zero + 1 == id); +} +``` + +### BigInt + +You can acheive BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. + +## References + +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-0.9.0/language_concepts/01_functions.md b/docs/versioned_docs/version-0.9.0/language_concepts/01_functions.md new file mode 100644 index 00000000000..54c618599d2 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/01_functions.md @@ -0,0 +1,88 @@ +--- +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] +--- + +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() {} +``` + +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 : pub 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 : pub Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## 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); +``` diff --git a/docs/versioned_docs/version-0.9.0/language_concepts/02_control_flow.md b/docs/versioned_docs/version-0.9.0/language_concepts/02_control_flow.md new file mode 100644 index 00000000000..691c514d9a8 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/02_control_flow.md @@ -0,0 +1,42 @@ +--- +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] +--- + +## 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 +}; +``` + +## 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); +``` diff --git a/docs/versioned_docs/version-0.9.0/language_concepts/03_ops.md b/docs/versioned_docs/version-0.9.0/language_concepts/03_ops.md new file mode 100644 index 00000000000..da02b126059 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/03_ops.md @@ -0,0 +1,97 @@ +--- +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, + ] +--- + +# 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 indentically 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-0.9.0/language_concepts/04_assert.md b/docs/versioned_docs/version-0.9.0/language_concepts/04_assert.md new file mode 100644 index 00000000000..a25a946123d --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/04_assert.md @@ -0,0 +1,34 @@ +--- +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] +--- + +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); +} +``` + +The above snippet compiles because `==` is a predicate operation. Conversely, the following will not +compile: + +```rust +// INCORRECT + +fn main(x : Field, y : Field) { + assert(x + y); +} +``` + +> The rationale behind this not compiling is due to ambiguity. It is not clear if the above should +> equate to `x + y == 0` or if it should check the truthiness of the result. diff --git a/docs/versioned_docs/version-0.9.0/language_concepts/05_unconstrained.md b/docs/versioned_docs/version-0.9.0/language_concepts/05_unconstrained.md new file mode 100644 index 00000000000..6b621eda3eb --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/05_unconstrained.md @@ -0,0 +1,96 @@ +--- +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] +--- + + + +Unconstrained functions are functions which do not constrain any of the included computation and allow for non-determinisitic 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 XOR 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. diff --git a/docs/versioned_docs/version-0.9.0/language_concepts/06_generics.md b/docs/versioned_docs/version-0.9.0/language_concepts/06_generics.md new file mode 100644 index 00000000000..a4c207e09e4 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/06_generics.md @@ -0,0 +1,116 @@ +--- +title: Generics +description: + Learn how to use Generics in Noir +keywords: [Noir, Rust, generics, functions, structs] +--- + +# Generics + +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: comptime Field, +} + +impl RepeatedValue { + fn new(value: T) -> Self { + Self { value, count: 1 } + } + + fn increment(mut repeated: Self) -> Self { + repeated.count += 1; + repeated + } + + fn print(self) { + for _i in 0 .. self.count { + dep::std::println(self.value); + } + } +} + +fn main() { + let mut repeated = RepeatedValue::new("Hello!"); + repeated = repeated.increment(); + 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 + +Unlike Rust, Noir does not have traits, so how can one translate the equivalent of a trait bound in +Rust into Noir? That is, how can we write a function that is generic over some type `T`, while also +requiring there is a function like `eq: fn(T, T) -> bool` that works on the type? + +The answer is that we can translate this by passing in the function manually. Here's an example of +implementing array equality in Noir: + +```rust +fn array_eq(array1: [T; N], array2: [T; N], elem_eq: fn(T, T) -> bool) -> bool { + if array1.len() != array2.len() { + false + } else { + let mut result = true; + for i in 0 .. array1.len() { + result &= elem_eq(array1[i], array2[i]); + } + result + } +} + +fn main() { + assert(array_eq([1, 2, 3], [1, 2, 3], |a, b| a == b)); + + // We can use array_eq even for arrays of structs, as long as we have + // an equality function for these structs we can pass in + let array = [MyStruct::new(), MyStruct::new()]; + assert(array_eq(array, array, MyStruct::eq)); +} +``` + +You can see an example of generics in the tests +[here](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/generics/src/main.nr). diff --git a/docs/versioned_docs/version-0.9.0/language_concepts/07_mutability.md b/docs/versioned_docs/version-0.9.0/language_concepts/07_mutability.md new file mode 100644 index 00000000000..69798c7a276 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/07_mutability.md @@ -0,0 +1,120 @@ +--- +title: Mutability +description: + Learn about mutable variables, constants, and globals in Noir programming language. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +--- + +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() -> Field { + let x = 3; + helper(x); + x // x is still 3 +} + +fn helper(mut x: i32) { + x = 4; +} +``` + +## Comptime Values + +Comptime values are values that are known at compile-time. This is different to a witness +which changes per proof. If a comptime value that is being used in your program is changed, then your +circuit will also change. + +Comptime is slightly different from Rust's `const`. Namely, it is a bit more flexible in that normal functions can accept comptime parameters. For example, this is used to verify an array index is known at compile-time. Note that the "known at compile-time" here means "known after function inlining is performed while optimizing the program" and not "known during type-checking." + +Below we show how to declare a comptime value: + +```rust +fn main() { + let a: comptime Field = 5; + + // `comptime Field` can also be inferred: + let a = 5; +} +``` + +Comptime variables can be mutuable, but must be known at compile time: + +```rust +fn main(runtime_var: Field) -> pub Field { + let known_at_compile_time: comptime Field = 1; + + // The next line will cause an error + let bad_var: comptime Field = runtime_var; + +} +``` + +As `runtime_var` is a argument to the circuit it cannot be known at compile time and so assigning it to a comptime variable should fail. A circuit's arguments is the only way in which non-comptime variables can enter the circuit (excluding [brillig](./unconstrained) foreign calls). + +## Globals + +Noir also supports global variables. However, they must be compile-time variables. If `comptime` is +not explicitly written in the type annotation the compiler will implicitly specify the declaration +as compile-time. They can then be used like any other compile-time variable inside functions. The +global type can also be inferred by the compiler entirely. Globals can also be used to specify array +annotations for function parameters and can be imported from submodules. + +```rust +global N: Field = 5; // Same as `global N: comptime Field = 5` + +fn main(x : Field, y : [Field; N]) { + let res = x * N; + + assert(res == y[0]); + + let res2 = x * mysubmodule::N; + assert(res != res2); +} + +mod mysubmodule { + use dep::std; + + global N: Field = 10; + + fn my_helper() -> comptime Field { + let x = N; + x + } +} +``` + +## Why only local mutability? + +Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting +without applying additional overhead to the user. Modeling a mutable reference is not as +straightforward as on conventional architectures and would incur some possibly unexpected overhead. diff --git a/docs/versioned_docs/version-0.9.0/language_concepts/08_comments.md b/docs/versioned_docs/version-0.9.0/language_concepts/08_comments.md new file mode 100644 index 00000000000..3bb4d2f25a4 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/08_comments.md @@ -0,0 +1,32 @@ +--- +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] +--- + +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-0.9.0/language_concepts/09_distinct.md b/docs/versioned_docs/version-0.9.0/language_concepts/09_distinct.md new file mode 100644 index 00000000000..e7ff7f5017a --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/09_distinct.md @@ -0,0 +1,63 @@ +--- +title: Distinct Witnesses +--- + +The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures +that the witnesses being returned as public inputs are all unique. + +The `distinct` keyword is only used for return values on program entry points (usually the `main()` +function). + +When using `distinct` and `pub` simultaneously, `distinct` comes first. See the example below. + +You can read more about the problem this solves +[here](https://github.com/noir-lang/noir/issues/1183). + +## Example + +Without the `distinct` keyword, the following program + +```rust +fn main(x : pub Field, y : pub Field) -> pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + "return_witnesses": [3, 2, 4, 4] + } +} +``` + +Whereas (with the `distinct` keyword) + +```rust +fn main(x : pub Field, y : pub Field) -> distinct pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + //... + "return_witnesses": [3, 4, 5, 6] + } +} +``` diff --git a/docs/versioned_docs/version-0.9.0/language_concepts/10_shadowing.md b/docs/versioned_docs/version-0.9.0/language_concepts/10_shadowing.md new file mode 100644 index 00000000000..efd743e764f --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/language_concepts/10_shadowing.md @@ -0,0 +1,43 @@ +--- +title: Shadowing +--- + +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-0.9.0/modules_packages_crates/crates_and_packages.md b/docs/versioned_docs/version-0.9.0/modules_packages_crates/crates_and_packages.md new file mode 100644 index 00000000000..34f28a71148 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/modules_packages_crates/crates_and_packages.md @@ -0,0 +1,35 @@ +--- +title: Crates and Packages +description: + Learn how to use Crates and Packages in your Noir project +keywords: [Nargo, dependencies, package management, crates, package] +--- + +## 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 one of two forms: a binary crate or a library crate. + +_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. + +_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. + +### 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-0.9.0/modules_packages_crates/dependencies.md b/docs/versioned_docs/version-0.9.0/modules_packages_crates/dependencies.md new file mode 100644 index 00000000000..2807ad52046 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/modules_packages_crates/dependencies.md @@ -0,0 +1,110 @@ +--- +title: Managing 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] +--- + +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"} +``` + +## 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 + +``` +β”œβ”€β”€ binary_crate +β”‚Β Β  β”œβ”€β”€ Nargo.toml +β”‚Β Β  └── src +β”‚Β Β  └── main.nr +└── liba + β”œβ”€β”€ Nargo.toml + └── src + └── lib.nr +``` + +Inside of the binary crate, you can specify: + +```toml +# Nargo.toml + +[dependencies] +libA = { path = "../liba" } +``` + +## 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 liba referenced above: + +```rust +use dep::ecrecover; +use dep::libA; +``` + +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; +``` + +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}; +``` + +## 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-0.9.0/modules_packages_crates/modules.md b/docs/versioned_docs/version-0.9.0/modules_packages_crates/modules.md new file mode 100644 index 00000000000..e429b336511 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/modules_packages_crates/modules.md @@ -0,0 +1,104 @@ +--- +title: Understanding 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] +--- + +# Modules + +Noir's module system follows the same convention as the _newer_ version of Rust's module system. + +## Purpose of Modules + +Modules are used to organise 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-0.9.0/nargo/01_commands.md b/docs/versioned_docs/version-0.9.0/nargo/01_commands.md new file mode 100644 index 00000000000..d550e137258 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/nargo/01_commands.md @@ -0,0 +1,139 @@ +--- +title: Commands +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, + ] +--- + +## General options + +``` +Options: + -s, --show-ssa Emit debug information for the intermediate SSA IR + -d, --deny-warnings Quit execution when warnings are emitted + -h, --help Print help +``` + +## `nargo help [subcommand]` + +Prints the list of available commands or specific information of a subcommand. + +_Arguments_ + +- `` - The subcommand whose help message to display + +## `nargo check` + +Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output +values of the Noir program respectively. + +## `nargo codegen-verifier` + +Generate a Solidity verifier smart contract for the program. + +## `nargo compile ` + +Compile the program into a JSON build artifact file containing the ACIR representation and the ABI +of the circuit. This build artifact can then be used to generate and verify proofs. + +You can also use "build" as an alias for compile. + +For example, `nargo build `. + +_Arguments_ + +- `` - The name of the circuit file + +_Options_ + +- `-c, --contracts` - Compile each contract function used within the program +- `--print-acir` - Displays the ACIR for the compiled circuit + +## `nargo new [path]` + +Creates a new Noir project in a new folder called `` - Name of the package +- `[path]` - The path to save the new project + +## `nargo init` + +Creates a new Noir project in the current directory. + +## `nargo execute [witness_name]` + +Runs the Noir program and prints its return value. + +_Arguments_ + +- `[witness_name]` - The name of the witness + +_Usage_ + +The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which +must be filled in. + +To save the witness to file, run the command with a value for the `witness-name` argument. A +`.tr` file will then be saved in the `build` folder. + +> **Info:** The `.tr` file is the witness file. The witness file can be considered as program inputs +> parsed for your program's ACIR. +> +> This file can be passed along with circuit's ACIR into a TypeScript project for proving and +> verification. See the [TypeScript](../typescript#proving-and-verifying-externally-compiled-files) +> section to learn more. + +## `nargo prove ` + +Creates a proof for the program. + +_Arguments_ + +- `` - The name of the proof + +_Options_ + +- `-v, --verify` - Verify proof after proving + +## `nargo verify ` + +Given a proof and a program, verify whether the proof is valid. + +_Arguments_ + +- `` - The proof to verify + +## `nargo test ` + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. + +See an example on the [testing page](./testing). + +_Arguments_ + +- `` - a pattern to indicate to only run tests with names containing the pattern + +## `nargo gates` + +Counts the occurrences of different gates in circuit + +## `nargo lsp` + +Start a long-running Language Server process that communicates over stdin/stdout. +Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). diff --git a/docs/versioned_docs/version-0.9.0/nargo/02_testing.md b/docs/versioned_docs/version-0.9.0/nargo/02_testing.md new file mode 100644 index 00000000000..ba0bebd658b --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/nargo/02_testing.md @@ -0,0 +1,32 @@ +--- +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] +--- + +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 the all +the contraints which allows you to test that add returns the expected values. Test functions can't +have any arguments currently. + +This is much faster compared to testing in Typescript but the only downside is that you can't +explicitly test that a certain set of inputs are invalid. i.e. you can't say that you want +add(2^64-1, 2^64-1) to fail. diff --git a/docs/versioned_docs/version-0.9.0/nargo/03_solidity_verifier.md b/docs/versioned_docs/version-0.9.0/nargo/03_solidity_verifier.md new file mode 100644 index 00000000000..9ac60cb0ba7 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/nargo/03_solidity_verifier.md @@ -0,0 +1,129 @@ +--- +title: 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, + ] +--- + +For certain applications, it may be desirable to run the verifier as a smart contract instead of on +a local machine. + +Compile a Solidity verifier contract for your Noir program by running: + +```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 on any EVM blockchain acting as a verifier smart contract. + +> **Note:** It is possible to compile 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 compilation of verifier contracts in +> Solidity only for the time being. + +## Verify + +To verify a proof using the Solidity verifier contract, call the `verify` function with the +following signature: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +You can see an example of how the `verify` function is called 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"); +``` + +### Public Inputs + +:::tip + +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. + +::: + +The verifier contract uses the output (return) value of a Noir program as a public input. So if you +have the following function + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +then `verify` in `plonk_vk.sol` will expect 3 public inputs. Passing two inputs will result in an +error like `Reason: PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case the 3 inputs to `verify` would be ordered as `[pubkey_x, pubkey_y, return]`. + +#### Struct inputs + +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) { + //... +} +``` + +Structs will be flattened so that the array of inputs is 1-dimensional array. The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +## Noir for EVM chains + +You can currently deploy the Solidity verifier contracts to most EVM compatible chains. EVM chains that have been tested and are known to work include: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +Other EVM chains should work, but have not been tested directly by our team. 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. + +### Unsupported chains + +Unfortunately not all "EVM" chains are supported. + +**zkSync** and the **Polygon zkEVM** do _not_ currently support proof verification via Solidity verifier contracts. They are missing the bn256 precompile contract that the verifier contract requires. Once these chains support this precompile, they may work. diff --git a/docs/versioned_docs/version-0.9.0/standard_library/black_box_fns.md b/docs/versioned_docs/version-0.9.0/standard_library/black_box_fns.md new file mode 100644 index 00000000000..c758846b688 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/black_box_fns.md @@ -0,0 +1,45 @@ +--- +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. + +:::warning + +It is likely that not all backends will support a particular black box function. + +::: + +Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. + +Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: + +```rust +#[foreign(sha256)] +fn sha256(_input : [u8; N]) -> [u8; 32] {} +``` + +## Function list + +Here is a list of the current black box functions that are supported by UltraPlonk: + +- AES +- [SHA256](./cryptographic_primitives/hashes#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr) +- [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Pedersen](./cryptographic_primitives/hashes#pedersen) +- [HashToField128Security](./cryptographic_primitives/hashes#hash_to_field) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [Compute merkle root](./merkle_trees#compute_merkle_root) +- AND +- XOR +- RANGE +- [Keccak256](./cryptographic_primitives/hashes#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. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. + +You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/acvm/blob/acir-v0.12.0/acir/src/circuit/black_box_functions.rs). diff --git a/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives.md b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives.md new file mode 100644 index 00000000000..2df4f929474 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives.md @@ -0,0 +1,14 @@ +--- +title: Cryptographic primitives in Noir +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-0.9.0/standard_library/cryptographic_primitives/00_hashes.mdx b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/00_hashes.mdx new file mode 100644 index 00000000000..31a84cdb753 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/00_hashes.mdx @@ -0,0 +1,146 @@ +--- +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] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +## sha256 + +Given an array of bytes, returns the resulting sha256 hash. + +```rust +fn sha256(_input : [u8]) -> [u8; 32] +``` + +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 +fn blake2s(_input : [u8]) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let hash = std::hash::blake2s(x); +} +``` + + + +## pedersen + +Given an array of Fields, returns the Pedersen hash. + +```rust +fn pedersen(_input : [Field]) -> [Field; 2] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let hash = std::hash::pedersen(x); +} +``` + + + +## 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 +fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149] // some random bytes + let message_size = 4; + let hash = std::hash::keccak256(x, message_size); +} +``` + + + +## 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 +fn main() +{ + let hash1 = std::hash::poseidon::bn254::hash_2([1, 2]); + assert(hash1 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); +} +``` + +## 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_bn254(x); +} +``` + +## hash_to_field + +```rust +fn hash_to_field(_input : [Field; N]) -> 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-0.9.0/standard_library/cryptographic_primitives/01_scalar.mdx b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/01_scalar.mdx new file mode 100644 index 00000000000..62265cddb1e --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/01_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, + ] +--- + +import BlackBoxInfo from './common/\_blackbox.mdx'; + +## scalar_mul::fixed_base + +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 +fn fixed_base(_input : Field) -> [Field; 2] +``` + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base(x); + std::println(scal); +} +``` + + diff --git a/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/02_schnorr.mdx b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/02_schnorr.mdx new file mode 100644 index 00000000000..0e219c0e5ff --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/02_schnorr.mdx @@ -0,0 +1,37 @@ +--- +title: Schnorr Signatures +description: Learn how you can verify Schnorr signatures using Noir +keywords: [cryptographic primitives, Noir project, schnorr, signatures] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +## schnorr::verify_signature + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). + +```rust +fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool +``` + +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() +); + +... +``` + + diff --git a/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx new file mode 100644 index 00000000000..3934a0338d0 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx @@ -0,0 +1,45 @@ +--- +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] +--- + +import BlackBoxInfo from './common/_blackbox.mdx'; + +Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 curves. + +## ecdsa_secp256k1::verify_signature + +Verifier for ECDSA Secp256k1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + +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_secp256r1::verify_signature + +Verifier for ECDSA Secp256r1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + +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); +} +``` + + diff --git a/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/04_ec_primitives.md b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/04_ec_primitives.md new file mode 100644 index 00000000000..6e6b19b6861 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -0,0 +1,101 @@ +--- +title: Elliptic Curve Primitives +keywords: [cryptographic primitives, Noir project] +--- + +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/crates/nargo_cli/tests/test_data/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-0.9.0/standard_library/cryptographic_primitives/05_eddsa.mdx b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/05_eddsa.mdx new file mode 100644 index 00000000000..8f060ed3316 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/05_eddsa.mdx @@ -0,0 +1,17 @@ +--- +title: EdDSA Verification +description: Learn about the cryptographic primitives regarding EdDSA +keywords: [cryptographic primitives, Noir project, eddsa, signatures] +--- + +import BlackBoxInfo from './common/_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 +``` + + diff --git a/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/common/_blackbox.mdx b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/common/_blackbox.mdx new file mode 100644 index 00000000000..9fe9b48fbff --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/cryptographic_primitives/common/_blackbox.mdx @@ -0,0 +1,5 @@ +:::info + +This is a black box function. Read [this section](../black_box_fns) to learn more about black box functions in Noir. + +::: \ No newline at end of file diff --git a/docs/versioned_docs/version-0.9.0/standard_library/field_methods.md b/docs/versioned_docs/version-0.9.0/standard_library/field_methods.md new file mode 100644 index 00000000000..4d1cdc953e9 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/field_methods.md @@ -0,0 +1,149 @@ +--- +title: Field Methods +description: + Learn about common methods on Noir Field, including to_le_bits, to_le_bytes, to_le_radix, + to_be_radix, pow_32, etc, and see code examples. +keywords: + [ + Noir Field, + to_le_bits, + to_le_bytes, + to_le_radix, + to_be_radix, + pow_32, + Little Endian, + Big Endian, + Vector, + Exponent, + ] +--- + +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; N] +``` + +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; N] +``` + +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); +} +``` + +## 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 +``` diff --git a/docs/versioned_docs/version-0.9.0/standard_library/logging.md b/docs/versioned_docs/version-0.9.0/standard_library/logging.md new file mode 100644 index 00000000000..42a84be1992 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/logging.md @@ -0,0 +1,42 @@ +--- +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, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +# Logging + +The standard library provides a familiar `println` statement you can use. Despite being a limited +implementation of rust's `println!` macro, this construct can be useful for debugging. + +The `println` statement is unconstrained, so it works for outputting integers, fields, strings, and even structs or expressions. For example: + +```rust +use dep::std; + +struct Person { + age : Field, + height : Field, +} + +fn main(age : Field, height : Field) { + let person = Person { age : age, height : height }; + std::println(person); + std::println(age + height); + std::println("Hello world!"); +} + +``` diff --git a/docs/versioned_docs/version-0.9.0/standard_library/merkle_trees.md b/docs/versioned_docs/version-0.9.0/standard_library/merkle_trees.md new file mode 100644 index 00000000000..57d8c4a9e4f --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/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/00_hashes.mdx#pedersen). + +```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(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); + std::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-0.9.0/standard_library/recursion.md b/docs/versioned_docs/version-0.9.0/standard_library/recursion.md new file mode 100644 index 00000000000..4705ae6c575 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/recursion.md @@ -0,0 +1,96 @@ +--- +title: Recursive Proofs +description: Learn about how to write recursive proofs in Noir. +keywords: [recursion, recursive proofs, verification_key, aggregation object, 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. + +The `verify_proof` function takes a verification key, proof and public inputs for a zk program, as well as a key hash and an input aggregation object. The key hash is used to check the validity of the verification key and the input aggregation object is required by some proving systems. The `verify_proof` function returns an output aggregation object that can then be fed into future iterations of the proof verification if required. + +```rust +#[foreign(verify_proof)] +fn verify_proof(_verification_key : [Field], _proof : [Field], _public_input : Field, _key_hash : Field, _input_aggregation_object : [Field]) -> [Field] {} +``` + +:::info + +This is a black box function. Read [this section](./black_box_fns) to learn more about black box functions in Noir. + +::: + +## Aggregation Object + +The purpose of the input aggregation object is a little less clear though (and the output aggregation object that is returned from the `std::verify_proof` method). 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. In the case of PLONK the recursive aggregation object is two G1 points (expressed as 16 witness values). The final verifier (in our case this is most often the smart contract verifier) has to be aware of this aggregation object to execute a pairing and check the validity of these points (thus completing the recursive verification). + +So for example in this circuit: + +```rust +use dep::std; + +fn main( + verification_key : [Field; 114], + proof : [Field; 94], + public_inputs : [Field; 1], + key_hash : Field, + input_aggregation_object : [Field; 16], + proof_b : [Field; 94], +) -> pub [Field; 16] { + let output_aggregation_object_a = std::verify_proof( + verification_key, + proof, + public_inputs, + key_hash, + input_aggregation_object + ); + + let output_aggregation_object = std::verify_proof( + verification_key, + proof_b, + public_inputs, + key_hash, + output_aggregation_object_a + ); + + let mut output = [0; 16]; + for i in 0..16 { + output[i] = output_aggregation_object[i]; + } + output +} +``` + +In this example we have a circuit, that generates proofs A and B, that is being verified in circuit C. Assuming that the proof being passed in is not already a recursive proof, the `input_aggregation_object` will be all zeros. It will then generate an `output_aggregation_object`. This blob of data then becomes the `input_aggregation_object` of the next recursive aggregation we wish to compute. We can see here as the same public inputs, verification key, and key hash are used that we are verifying two proofs generated from the same circuit in this single circuit. `std::verify_proof` returns a `[Field]` because the size of an aggregation object is proof system dependent--in barretenberg, aggregation objects are two G1 points, while in Halo2, the aggregation object is a list of G1 points that is log the circuit size. So for the final step we convert the slice into an array of size 16 because we are generating proofs using UltraPlonk. + +## 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. They should be checked against in the circuit after construction of a new aggregation state. + +### `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. + +### `input_aggregation_object` + +An aggregation object is blob of data that the top-level verifier must run some proof system specific algorithm on to complete verification. The size is proof system specific and will be set by the backend integrating this opcode. The input aggregation object is only not `None` when we are verifying a previous recursive aggregation in the current circuit. If this is the first recursive aggregation there is no input aggregation object. It is left to the backend to determine how to handle when there is no input aggregation object. + +## Return value + +### `output_aggregation_object` + +This is the result of a recursive aggregation and is what will be fed into the next verifier. +The next verifier can either perform a final verification (returning true or false) or perform another recursive aggregation where this output aggregation object will be the input aggregation object of the next recursive aggregation. + +## Example + +You can see an example of how to do recursive proofs in [this example recursion demo repo](https://github.com/Savio-Sou/recursion-demo/tree/main). diff --git a/docs/versioned_docs/version-0.9.0/standard_library/slice_methods.md b/docs/versioned_docs/version-0.9.0/standard_library/slice_methods.md new file mode 100644 index 00000000000..8b93d8ea427 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/slice_methods.md @@ -0,0 +1,279 @@ +--- +title: Slice Methods +description: + Learn about the commonly used methods available for slices in Noir, including push_back, len, srt, map, fold, reduce, all, and any. +keywords: [rust, slice, methods, push_back, len, sort, fold, reduce, all, any] +--- + +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]. + +## 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); +``` + +View the corresponding test file [here]([test-file]. + +## len + +Returns the length of a slice + +```rust +fn len(_slice: [T]) -> comptime Field +``` + +Example: + +```rust +fn main() { + let slic = [42, 42] + assert(slic.len() == 2); +} +``` + +## sort + +Returns a new sorted slice. The original slice remains untouched. Notice that this function will +only work for slices of fields or integers, not for any arbitrary type. This is because the sorting +logic the function 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(_slice: [T]) -> [T] +``` + +Example: + +```rust +fn main() { + let slic = [42, 32] + let sorted = slic.sort(); + assert(sorted == [32, 42]); +} +``` + +## sort_via + +Sorts the slice with a custom comparison function + +```rust +fn sort_via(mut a: [T], ordering: fn(T, T) -> bool) -> [T] +``` + +Example: + +```rust +fn main() { + let slic = [42, 32] + let sorted_ascending = slic.sort_via(|a, b| a < b); + assert(sorted_ascending == [32, 42]); // verifies + + let sorted_descending = slic.sort_via(|a, b| a > b); + assert(sorted_descending == [32, 42]); // does not verify +} +``` + +## map + +Applies a function to each element of the slice, returning a new slice containing the mapped elements. + +```rust +fn map(f: fn(T) -> U) -> [U] +``` + +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 slice, returning the final accumulated value. The first +parameter is the initial value. + +```rust +fn fold(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 slice, 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 slic = [2,2,2,2,2] + let folded = slic.fold(0, |a, b| a + b); + assert(folded == 10); +} + +``` + +## reduce + +Same as fold, but uses the first element as starting element. + +```rust +fn reduce(f: fn(T, T) -> T) -> T +``` + +Example: + +```rust +fn main() { + let slic = [2,2,2,2,2] + let reduced = slic.reduce(|a, b| a + b); + assert(reduced == 10); +} +``` + +## all + +Returns true if all the elements satisfy the given predicate + +```rust +fn all(predicate: fn(T) -> bool) -> bool +``` + +Example: + +```rust +fn main() { + let slic = [2,2,2,2,2] + let all = slic.all(|a| a == 2); + assert(all); +} +``` + +## any + +Returns true if any of the elements satisfy the given predicate + +```rust +fn any(predicate: fn(T) -> bool) -> bool +``` + +Example: + +```rust +fn main() { + let slic = [2,2,2,2,5] + let any = slic.any(|a| a == 5); + assert(any); +} + +``` + +[test-file]: https://github.com/noir-lang/noir/blob/f387ec1475129732f72ba294877efdf6857135ac/crates/nargo_cli/tests/test_data_ssa_refactor/slices/src/main.nr + diff --git a/docs/versioned_docs/version-0.9.0/standard_library/zeroed.md b/docs/versioned_docs/version-0.9.0/standard_library/zeroed.md new file mode 100644 index 00000000000..97dab02dac2 --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/standard_library/zeroed.md @@ -0,0 +1,25 @@ +--- +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 +- String +- Tuple +- Function + +Using it on other types could result in unexpected behavior. diff --git a/docs/versioned_docs/version-0.9.0/typescript.md b/docs/versioned_docs/version-0.9.0/typescript.md new file mode 100644 index 00000000000..8608783784c --- /dev/null +++ b/docs/versioned_docs/version-0.9.0/typescript.md @@ -0,0 +1,243 @@ +--- +title: Working with TypeScript +description: + Learn how to interact with Noir programs using TypeScript. Follow this tutorial to compile your + program, specify inputs, initialize a prover & verifier, and prove and verify your program. +keywords: [TypeScript, Noir, tutorial, compile, inputs, prover, verifier, proof] +--- + +Interactions with Noir programs can also be performed in TypeScript, which can come in handy when +writing tests or when working in TypeScript-based projects like [Hardhat](https://hardhat.org/). + +You can check the complete code for this tutorial here: [browser with next.js](https://github.com/signorecello/noir-min-browser-example) and [node.js](https://github.com/signorecello/noir-min-nodejs-example). If you want just a browser boilerplate to start with, check out the [noir-starter](https://github.com/noir-lang/noir-starter) for an example implementation. + +:::note + +You may find unexpected errors working with some frameworks such as `vite`. This is due to the +nature of `wasm` files and the way Noir uses web workers. As we figure it out, we suggest using +[Create React App](https://create-react-app.dev/), or [Next.js](https://nextjs.org/) for a quick +start. + +::: + +## Setup + +Make sure you are using Noir version >= 0.10.1. + +You can check your current version by running `nargo --version`. + +You can install version 0.10.1 with noirup with + +```bash +noirup -v 0.10.1 +``` + +See the [Installation page](./getting_started/nargo_installation) for more info. + +We're assuming you're using ES6 and ESM for both browser (for example with React), or nodejs. Install [Node.js](https://nodejs.org/en). Init a new project with `npm init` and add `"type": "module"` to your `package.json`, to let `node` know we're using the new ESM sytem: + +```json +{ + "type": "module" + // the rest of your package.json +} +``` + +Install Noir dependencies in your project by running: + +```bash +npm i @aztec/bb.js@0.3.6 https://git@github.com/noir-lang/acvm-simulator-wasm.git#b9d9ca9dfc5140839f23998d9466307215607c42 fflate ethers@5.7.2 +``` + +This will install the `acvm-simulator` that will generate our witness, and the proving backend barretenberg `bb.js`. + +We're also installing `ethers` because we're too lazy to write a function that pads public inputs with 32bytes, and `fflate` to help us decompress our circuit bytecode. + +Since we're with typescript and using `nodejs` types, we also recommend to install the `@types/node` package, otherwise your IDE will scream at you. + +```bash +npm i --save-dev @types/node +``` + +:::note + +While Noir is in rapid development, some packages could interfere with others. For that reason, you +should use these specified versions. Let us know if for some reason you need to use other ones. + +::: + +As for the circuit, run `nargo init` to create a new Noir project. + +We will use a Standard Noir Example and place it in the `src` folder. This program simply multiplies input `x` with input `y` and returns the result `z`. The verifier doesn't know the value of `x`: we're proving that we know it without making it public. + +```rust +// src/main.nr +fn main(x: u32, y: pub u32) -> pub u32 { + let z = x * y; + z +} +``` + +One valid scenario for proving could be `x = 3`, `y = 4` and `return = 12` + +## Compiling + +In order to start proving, we need to compile our circuit into the intermediate representation used by our backend. As of today, you have to do that with `nargo`. Just hop to your circuits folder and run `nargo compile`. + +:::info + +At this time, you need to use a nightly version of nargo. Using [noirup](./getting_started/00_nargo_installation.md#option-1-noirup) you can do this simply by running `noirup -n`. + +::: + +You should have a `json` file in `target/` with your circuit's bytecode. The json file is name based on the project name specified in Nargo.toml, so for a project named "test", it will be at `target/test.json`. You can then import that file normally. + +```ts +import circuit from '../target/test.json' assert { type: 'json' }; +``` + +## Decompressing the circuit + +The compiled circuit comes compressed. We need to decompress it, that's where `fflate` comes in. + +```ts +import { decompressSync } from 'fflate'; + +const acirBuffer = Buffer.from(circuit.bytecode, 'base64'); +const acirBufferUncompressed = decompressSync(acirBuffer); +``` + +From here, it's highly recommended you store `acirBuffer` and `acirBufferUncompressed` close by, as they will be used for witness generation and proving. + +## Initializing ACVM and BB.JS + +:::note + +This step will eventually be abstracted away as Noir tooling matures. For now, you should be fine just literally copy-pasting most of this into your own code. + +::: + +Before proving, `bb.js` needs to be initialized. We need to import some functions and use them + +```ts +import { Crs, newBarretenbergApiAsync, RawBuffer } from '@aztec/bb.js/dest/node/index.js'; + +const api = await newBarretenbergApiAsync(4); + +const [exact, circuitSize, subgroup] = await api.acirGetCircuitSizes(acirBufferUncompressed); +const subgroupSize = Math.pow(2, Math.ceil(Math.log2(circuitSize))); +const crs = await Crs.new(subgroupSize + 1); +await api.commonInitSlabAllocator(subgroupSize); +await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data())); + +const acirComposer = await api.acirNewAcirComposer(subgroupSize); +``` + +We should take two very useful objects from here: `api` and `acirComposer`. Make sure to keep these close by! + +:::info + +On the browser, you also need to init the ACVM. You can do that by importing it and calling it like: + +```ts +import initACVM, { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; + +await initACVM(); +// the rest of your code +``` + +::: + +## Generating witnesses + +Witness generation is what allows us to prove with arbitrary inputs (like user inputs on a form, game, etc). In this example, our input is a simple object with our circuit inputs `x`, `y`, and return `z` (fun fact: the return value in Noir is actually a public input!). We're wrapping it in a function, so it can be conveniently called later on. + +```ts +import { ethers } from 'ethers'; // I'm lazy so I'm using ethers to pad my input +import { executeCircuit, compressWitness } from '@noir-lang/acvm_js'; + +async function generateWitness(input: any, acirBuffer: Buffer): Promise { + const initialWitness = new Map(); + initialWitness.set(1, ethers.utils.hexZeroPad(`0x${input.x.toString(16)}`, 32)); + initialWitness.set(2, ethers.utils.hexZeroPad(`0x${input.y.toString(16)}`, 32)); + + const witnessMap = await executeCircuit(acirBuffer, initialWitness, () => { + throw Error('unexpected oracle'); + }); + + const witnessBuff = compressWitness(witnessMap); + return witnessBuff; +} +``` + +## Proving + +Finally, we're ready to prove with our backend. Just like with the witness generation, could be useful to wrap it in its own function: + +```ts +async function generateProof(witness: Uint8Array) { + const proof = await api.acirCreateProof( + acirComposer, + acirBufferUncompressed, + decompressSync(witness), + false, + ); + return proof; +} +``` + +## Verifying + +Our backend should also be ready to verify our proof: + +```ts +async function verifyProof(proof: Uint8Array) { + await api.acirInitProvingKey(acirComposer, acirBufferUncompressed); + const verified = await api.acirVerifyProof(acirComposer, proof, false); + return verified; +} +``` + +## Now for the fun part + +Let's call our functions, and destroy our API! + +```ts +const input = { x: 3, y: 4 }; +const witness = await generateWitness(input, acirBuffer); +console.log('Witness generated!'); +const proof = await generateProof(witness); +console.log('Proof generated!'); +await verifyProof(proof); +console.log('Proof verified!'); +api.destroy(); +``` + +You can use [this](https://gist.github.com/critesjosh/6f3ba19fdc9298b24e90ba4f736247dc) tsconfig.json. You can see the script [here](https://gist.github.com/critesjosh/4aa36e87a0cc3f09feaf1febb4d11348). + +## Verifying with Smart Contract + +Alternatively, a verifier smart contract can be generated and used for verifying Noir proofs in +TypeScript as well. + +This could be useful if the Noir program is designed to be decentrally verified and/or make use of +decentralized states and logics that is handled at the smart contract level. + +This assumes you've already ran `nargo codegen-verifier`, got your smart contract, and deployed it with Hardhat, Foundry, or your tool of choice. You can then verify a Noir proof by simply calling it. + +Currently, `bb.js` appends the public inputs to the proof. However, these inputs need to be fed separately to the verifier contract. A simple solution is to just slice them from the resulting proof, like this: + +```ts +import { ethers } from 'ethers'; // example using ethers v5 +import artifacts from '../artifacts/circuits/contract/plonk_vk.sol/UltraVerifier.json'; // I compiled using Hardhat, so I'm getting my abi from here + +const verifierAddress = '0x123455'; // your verifier address +const provider = new ethers.providers.Web3Provider(window.ethereum); +const signer = this.provider.getSigner(); + +const contract = new ethers.Contract(verifierAddress, artifacts.abi, signer); + +const publicInputs = proof.slice(0, 32); +const slicedProof = proof.slice(32); +await contract.verify(slicedProof, [publicInputs]); +``` diff --git a/docs/versioned_sidebars/version-0.10.5-sidebars.json b/docs/versioned_sidebars/version-0.10.5-sidebars.json new file mode 100644 index 00000000000..a51ebf87643 --- /dev/null +++ b/docs/versioned_sidebars/version-0.10.5-sidebars.json @@ -0,0 +1,111 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index", + "label": "Noir" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "Examples", + "items": [ + { + "type": "autogenerated", + "dirName": "examples" + } + ] + }, + { + "type": "category", + "label": "Nargo", + "items": [ + { + "type": "autogenerated", + "dirName": "nargo" + } + ] + }, + { + "type": "category", + "label": "Language Concepts", + "items": [ + { + "type": "category", + "label": "Data Types", + "link": { + "type": "doc", + "id": "language_concepts/data_types" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "language_concepts/data_types" + } + ] + }, + "language_concepts/functions", + "language_concepts/control_flow", + "language_concepts/ops", + "language_concepts/assert", + "language_concepts/unconstrained", + "language_concepts/generics", + "language_concepts/mutability", + "language_concepts/lambdas", + "language_concepts/comments", + "language_concepts/distinct", + "language_concepts/shadowing" + ] + }, + { + "type": "category", + "label": "Noir Standard Library", + "items": [ + { + "type": "category", + "label": "Cryptographic Primitives", + "link": { + "type": "doc", + "id": "standard_library/cryptographic_primitives" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "standard_library/cryptographic_primitives" + } + ] + }, + "standard_library/recursion", + "standard_library/logging", + "standard_library/merkle_trees", + "standard_library/zeroed", + "standard_library/black_box_fns", + "standard_library/options" + ] + }, + { + "type": "category", + "label": "Modules, Packages and Crates", + "items": [ + { + "type": "autogenerated", + "dirName": "modules_packages_crates" + } + ] + }, + { + "type": "doc", + "id": "typescript", + "label": "Working with Typescript" + } + ] +} diff --git a/docs/versioned_sidebars/version-0.6.0-sidebars.json b/docs/versioned_sidebars/version-0.6.0-sidebars.json new file mode 100644 index 00000000000..7323ae1c504 --- /dev/null +++ b/docs/versioned_sidebars/version-0.6.0-sidebars.json @@ -0,0 +1,90 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index", + "label": "Noir" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "Examples", + "items": [ + { + "type": "autogenerated", + "dirName": "examples" + } + ] + }, + { + "type": "category", + "label": "Nargo", + "items": [ + { + "type": "autogenerated", + "dirName": "nargo" + } + ] + }, + { + "type": "category", + "label": "Language Concepts", + "items": [ + { + "type": "autogenerated", + "dirName": "language_concepts" + } + ] + }, + { + "type": "category", + "label": "Noir Standard Library", + "items": [ + { + "type": "category", + "label": "Cryptographic Primitives", + "link": { + "type": "doc", + "id": "standard_library/cryptographic_primitives" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "standard_library/cryptographic_primitives" + } + ] + }, + "standard_library/array_methods", + "standard_library/field_methods", + "standard_library/logging", + "standard_library/merkle_trees", + "standard_library/zeroed", + "standard_library/black_box_fns" + ] + }, + { + "type": "category", + "label": "Modules, Packages and Crates", + "items": [ + { + "type": "autogenerated", + "dirName": "modules_packages_crates" + } + ] + }, + { + "type": "doc", + "id": "typescript", + "label": "Working with Typescript" + } + ] +} diff --git a/docs/versioned_sidebars/version-0.7.1-sidebars.json b/docs/versioned_sidebars/version-0.7.1-sidebars.json new file mode 100644 index 00000000000..7323ae1c504 --- /dev/null +++ b/docs/versioned_sidebars/version-0.7.1-sidebars.json @@ -0,0 +1,90 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index", + "label": "Noir" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "Examples", + "items": [ + { + "type": "autogenerated", + "dirName": "examples" + } + ] + }, + { + "type": "category", + "label": "Nargo", + "items": [ + { + "type": "autogenerated", + "dirName": "nargo" + } + ] + }, + { + "type": "category", + "label": "Language Concepts", + "items": [ + { + "type": "autogenerated", + "dirName": "language_concepts" + } + ] + }, + { + "type": "category", + "label": "Noir Standard Library", + "items": [ + { + "type": "category", + "label": "Cryptographic Primitives", + "link": { + "type": "doc", + "id": "standard_library/cryptographic_primitives" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "standard_library/cryptographic_primitives" + } + ] + }, + "standard_library/array_methods", + "standard_library/field_methods", + "standard_library/logging", + "standard_library/merkle_trees", + "standard_library/zeroed", + "standard_library/black_box_fns" + ] + }, + { + "type": "category", + "label": "Modules, Packages and Crates", + "items": [ + { + "type": "autogenerated", + "dirName": "modules_packages_crates" + } + ] + }, + { + "type": "doc", + "id": "typescript", + "label": "Working with Typescript" + } + ] +} diff --git a/docs/versioned_sidebars/version-0.9.0-sidebars.json b/docs/versioned_sidebars/version-0.9.0-sidebars.json new file mode 100644 index 00000000000..190363917e0 --- /dev/null +++ b/docs/versioned_sidebars/version-0.9.0-sidebars.json @@ -0,0 +1,91 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index", + "label": "Noir" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "Examples", + "items": [ + { + "type": "autogenerated", + "dirName": "examples" + } + ] + }, + { + "type": "category", + "label": "Nargo", + "items": [ + { + "type": "autogenerated", + "dirName": "nargo" + } + ] + }, + { + "type": "category", + "label": "Language Concepts", + "items": [ + { + "type": "autogenerated", + "dirName": "language_concepts" + } + ] + }, + { + "type": "category", + "label": "Noir Standard Library", + "items": [ + { + "type": "category", + "label": "Cryptographic Primitives", + "link": { + "type": "doc", + "id": "standard_library/cryptographic_primitives" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "standard_library/cryptographic_primitives" + } + ] + }, + "standard_library/slice_methods", + "standard_library/field_methods", + "standard_library/recursion", + "standard_library/logging", + "standard_library/merkle_trees", + "standard_library/zeroed", + "standard_library/black_box_fns" + ] + }, + { + "type": "category", + "label": "Modules, Packages and Crates", + "items": [ + { + "type": "autogenerated", + "dirName": "modules_packages_crates" + } + ] + }, + { + "type": "doc", + "id": "typescript", + "label": "Working with Typescript" + } + ] +} diff --git a/docs/versions.json b/docs/versions.json new file mode 100644 index 00000000000..26d22536e02 --- /dev/null +++ b/docs/versions.json @@ -0,0 +1,6 @@ +[ + "0.10.5", + "0.9.0", + "0.7.1", + "0.6.0" +] diff --git a/package.json b/package.json index a72d208f55b..47c77ffa945 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "tooling/noir_js", "tooling/noir_js_backend_barretenberg", "acvm-repo/acvm_js", - "release-tests" + "release-tests", + "docs" ], "scripts": { "build": "yarn workspaces foreach --parallel --topological-dev --verbose run build", diff --git a/yarn.lock b/yarn.lock index 856493ee802..71338f8f3a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,333 +29,2601 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.8.10": - version: 0.8.10 - resolution: "@aztec/bb.js@npm:0.8.10" +"@algolia/autocomplete-core@npm:1.9.3": + version: 1.9.3 + resolution: "@algolia/autocomplete-core@npm:1.9.3" 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: c77f6e27f626edca1477e4d94794d43b373dfcb527f00579e20270fc92794f9e4bc5df2c25ebbce564700c114cdf69e0b213ddb0192c24af4fc4cdf468918702 + "@algolia/autocomplete-plugin-algolia-insights": 1.9.3 + "@algolia/autocomplete-shared": 1.9.3 + checksum: ce78048568660184a4fa3c6548f344a7f5ce0ba45d4cfc233f9756b6d4f360afd5ae3a18efefcd27a626d3a0d6cf22d9cba3e21b217afae62b8e9d11bc4960da languageName: node linkType: hard -"@babel/code-frame@npm:^7.12.11": - version: 7.22.13 - resolution: "@babel/code-frame@npm:7.22.13" +"@algolia/autocomplete-plugin-algolia-insights@npm:1.9.3": + version: 1.9.3 + resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.9.3" dependencies: - "@babel/highlight": ^7.22.13 - chalk: ^2.4.2 - checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 + "@algolia/autocomplete-shared": 1.9.3 + peerDependencies: + search-insights: ">= 1 < 3" + checksum: 030695bf692021c27f52a3d4931efed23032796e326d4ae7957ae91b51c36a10dc2d885fb043909e853f961c994b8e9ff087f50bb918cfa075370562251a199f languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-validator-identifier@npm:7.22.20" - checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc +"@algolia/autocomplete-preset-algolia@npm:1.9.3": + version: 1.9.3 + resolution: "@algolia/autocomplete-preset-algolia@npm:1.9.3" + dependencies: + "@algolia/autocomplete-shared": 1.9.3 + peerDependencies: + "@algolia/client-search": ">= 4.9.1 < 6" + algoliasearch: ">= 4.9.1 < 6" + checksum: 1ab3273d3054b348eed286ad1a54b21807846326485507b872477b827dc688006d4f14233cebd0bf49b2932ec8e29eca6d76e48a3c9e9e963b25153b987549c0 languageName: node linkType: hard -"@babel/highlight@npm:^7.22.13": - version: 7.22.20 - resolution: "@babel/highlight@npm:7.22.20" +"@algolia/autocomplete-shared@npm:1.9.3": + version: 1.9.3 + resolution: "@algolia/autocomplete-shared@npm:1.9.3" + peerDependencies: + "@algolia/client-search": ">= 4.9.1 < 6" + algoliasearch: ">= 4.9.1 < 6" + checksum: 06014c8b08d30c452de079f48c0235d8fa09904bf511da8dc1b7e491819940fd4ff36b9bf65340242b2e157a26799a3b9aea01feee9c5bf67be3c48d7dff43d7 + languageName: node + linkType: hard + +"@algolia/cache-browser-local-storage@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/cache-browser-local-storage@npm:4.20.0" dependencies: - "@babel/helper-validator-identifier": ^7.22.20 - chalk: ^2.4.2 - js-tokens: ^4.0.0 - checksum: 84bd034dca309a5e680083cd827a766780ca63cef37308404f17653d32366ea76262bd2364b2d38776232f2d01b649f26721417d507e8b4b6da3e4e739f6d134 + "@algolia/cache-common": 4.20.0 + checksum: b9ca7e190ab77ddf4d30d22223345f69fc89899aa6887ee716e4ffcef14c8c9d28b782cb7cc96a0f04eed95a989878a6feca5b9aa6add0cd1846222c3308bb65 languageName: node linkType: hard -"@chainsafe/as-sha256@npm:^0.3.1": - version: 0.3.1 - resolution: "@chainsafe/as-sha256@npm:0.3.1" - checksum: 58ea733be1657b0e31dbf48b0dba862da0833df34a81c1460c7352f04ce90874f70003cbf34d0afb9e5e53a33ee2d63a261a8b12462be85b2ba0a6f7f13d6150 +"@algolia/cache-common@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/cache-common@npm:4.20.0" + checksum: a46377de8a309feea109aae1283fc9157c73766a4c51e3085870a1fc49f6e33698814379f3bbdf475713fa0663dace86fc90f0466e64469b1b885a0538abace4 languageName: node linkType: hard -"@chainsafe/persistent-merkle-tree@npm:^0.4.2": - version: 0.4.2 - resolution: "@chainsafe/persistent-merkle-tree@npm:0.4.2" +"@algolia/cache-in-memory@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/cache-in-memory@npm:4.20.0" dependencies: - "@chainsafe/as-sha256": ^0.3.1 - checksum: f9cfcb2132a243992709715dbd28186ab48c7c0c696f29d30857693cca5526bf753974a505ef68ffd5623bbdbcaa10f9083f4dd40bf99eb6408e451cc26a1a9e + "@algolia/cache-common": 4.20.0 + checksum: 3d67dcfae431605c8b9b1502f14865722f13b97b2822e1e3ed53bbf7bf66a120a825ccf5ed03476ebdf4aa15482dad5bfc6c2c93d81f07f862c373c689f49317 languageName: node linkType: hard -"@chainsafe/persistent-merkle-tree@npm:^0.5.0": - version: 0.5.0 - resolution: "@chainsafe/persistent-merkle-tree@npm:0.5.0" +"@algolia/client-account@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/client-account@npm:4.20.0" dependencies: - "@chainsafe/as-sha256": ^0.3.1 - checksum: 2c67203da776c79cd3a6132e2d672fe132393b2e63dc71604e3134acc8c0ec25cc5e431051545939ea0f7c5ff2066fb806b9e5cab974ca085d046226a1671f7d + "@algolia/client-common": 4.20.0 + "@algolia/client-search": 4.20.0 + "@algolia/transporter": 4.20.0 + checksum: b59e9c7a324bbfba4abdab3f41d333522eb1abce7dab74e69d297acd9ee2a3c60e82e5e9db42e6a46b5ea26a35728533e6e4ff846c631b588ceb73d14dcbc5fb languageName: node linkType: hard -"@chainsafe/ssz@npm:^0.10.0": - version: 0.10.2 - resolution: "@chainsafe/ssz@npm:0.10.2" +"@algolia/client-analytics@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/client-analytics@npm:4.20.0" dependencies: - "@chainsafe/as-sha256": ^0.3.1 - "@chainsafe/persistent-merkle-tree": ^0.5.0 - checksum: 6bb70cf741d0a19dd0b28b3f6f067b96fa39f556e2eefa6ac745b21db9c3b3a8393dc3cca8ff4a6ce065ed71ddc3fb1b2b390a92004b9d01067c26e2558e5503 + "@algolia/client-common": 4.20.0 + "@algolia/client-search": 4.20.0 + "@algolia/requester-common": 4.20.0 + "@algolia/transporter": 4.20.0 + checksum: 0be4120ab72162e0640e49eedddff81bfc2c590e9a9322d1788b8c01e06fdabcaaaa9cd75b5b516e502deb888d3ba2285ac5e1c3bb91fc9eb552a24a716dc6e3 languageName: node linkType: hard -"@chainsafe/ssz@npm:^0.9.2": - version: 0.9.4 - resolution: "@chainsafe/ssz@npm:0.9.4" +"@algolia/client-common@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/client-common@npm:4.20.0" dependencies: - "@chainsafe/as-sha256": ^0.3.1 - "@chainsafe/persistent-merkle-tree": ^0.4.2 - case: ^1.6.3 - checksum: c6eaedeae9e5618b3c666ff4507a27647f665a8dcf17d5ca86da4ed4788c5a93868f256d0005467d184fdf35ec03f323517ec2e55ec42492d769540a2ec396bc + "@algolia/requester-common": 4.20.0 + "@algolia/transporter": 4.20.0 + checksum: 88a27b5f8bba38349e1dbe47634e2ee159a413ff1a3baf6a65fbf244835f8d368e9f0a5ccce8bfe94ec405b38608be5bed45bcb140517f3aba6fe3b7045db373 languageName: node linkType: hard -"@cspotcode/source-map-support@npm:^0.8.0": - version: 0.8.1 - resolution: "@cspotcode/source-map-support@npm:0.8.1" +"@algolia/client-personalization@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/client-personalization@npm:4.20.0" dependencies: - "@jridgewell/trace-mapping": 0.3.9 - checksum: 5718f267085ed8edb3e7ef210137241775e607ee18b77d95aa5bd7514f47f5019aa2d82d96b3bf342ef7aa890a346fa1044532ff7cc3009e7d24fce3ce6200fa + "@algolia/client-common": 4.20.0 + "@algolia/requester-common": 4.20.0 + "@algolia/transporter": 4.20.0 + checksum: ddb92ebe135564e03db6ac75da7fdc1c7500a0deffb7e41d5a02a413216a06daea008f8062dab606ba8af4c3c34e550354f48e6ea7b048882c385d915643799a languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-arm64@npm:0.17.19" - conditions: os=android & cpu=arm64 +"@algolia/client-search@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/client-search@npm:4.20.0" + dependencies: + "@algolia/client-common": 4.20.0 + "@algolia/requester-common": 4.20.0 + "@algolia/transporter": 4.20.0 + checksum: 9fb6624dab6753f336f3207ee2af3558baeec4772ef739b6f6ed6a754c366e2e8d62cbf1cf8b28d5f763bec276a0a5fc36db2bf6f53a707890a411afcf550e92 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-arm@npm:0.17.19" - conditions: os=android & cpu=arm +"@algolia/events@npm:^4.0.1": + version: 4.0.1 + resolution: "@algolia/events@npm:4.0.1" + checksum: 4f63943f4554cfcfed91d8b8c009a49dca192b81056d8c75e532796f64828cd69899852013e81ff3fff07030df8782b9b95c19a3da0845786bdfe22af42442c2 languageName: node linkType: hard -"@esbuild/android-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-x64@npm:0.17.19" - conditions: os=android & cpu=x64 +"@algolia/logger-common@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/logger-common@npm:4.20.0" + checksum: 06ed28f76b630c8e7597534b15138ab6f71c10dfc6e13f1fb1b76965b39c88fd1d9cb3fe6bb9d046de6533ebcbe5ad92e751bc36fabe98ceda39d1d5f47bb637 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/darwin-arm64@npm:0.17.19" - conditions: os=darwin & cpu=arm64 +"@algolia/logger-console@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/logger-console@npm:4.20.0" + dependencies: + "@algolia/logger-common": 4.20.0 + checksum: 721dffe37563e2998d4c361f09a05736b4baa141bfb7da25d50f890ba8257ac99845dd94b43d0d6db38e2fdab96508a726e184a00e5b1e83ef18a16da6fc716c languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/darwin-x64@npm:0.17.19" - conditions: os=darwin & cpu=x64 +"@algolia/requester-browser-xhr@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/requester-browser-xhr@npm:4.20.0" + dependencies: + "@algolia/requester-common": 4.20.0 + checksum: 669790c7dfd491318976b9d61d98d9785880d7385ba33669f3f8b9c66ea88320bcded82d34f58b5df74b2cb8beb62ef48a28d39117f7997be84348c9fa7f6132 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/freebsd-arm64@npm:0.17.19" - conditions: os=freebsd & cpu=arm64 +"@algolia/requester-common@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/requester-common@npm:4.20.0" + checksum: 8580ffd2be146bbdb5d4a57668bba4a5014f406cb2e5c65f596db6babab46c48d30c6e4732034ee1f987970aa27dcdab567959d654fa5fa74c4bcaf98312a724 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/freebsd-x64@npm:0.17.19" - conditions: os=freebsd & cpu=x64 +"@algolia/requester-node-http@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/requester-node-http@npm:4.20.0" + dependencies: + "@algolia/requester-common": 4.20.0 + checksum: 7857114b59c67e0d22e8a7ff3f755d11534a1602a4fc80802d3b35802777880a4980420914ea4a6e3e21198f5bacb95906289ce1bb9372458bf6a60a723bee59 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-arm64@npm:0.17.19" - conditions: os=linux & cpu=arm64 +"@algolia/transporter@npm:4.20.0": + version: 4.20.0 + resolution: "@algolia/transporter@npm:4.20.0" + dependencies: + "@algolia/cache-common": 4.20.0 + "@algolia/logger-common": 4.20.0 + "@algolia/requester-common": 4.20.0 + checksum: f834d5c8fcb7dfa9b7044cb81e9fab44a32f9dd0c3868a0f85fe0de4f4d27ad11fdc9c3c78541bc944c2593f4be56517a8ce593309d062b8a46ca0d6fcb5dcbc languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-arm@npm:0.17.19" - conditions: os=linux & cpu=arm +"@ampproject/remapping@npm:^2.2.0": + version: 2.2.1 + resolution: "@ampproject/remapping@npm:2.2.1" + dependencies: + "@jridgewell/gen-mapping": ^0.3.0 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-ia32@npm:0.17.19" - conditions: os=linux & cpu=ia32 +"@aztec/bb.js@npm:0.8.10": + version: 0.8.10 + resolution: "@aztec/bb.js@npm:0.8.10" + 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: c77f6e27f626edca1477e4d94794d43b373dfcb527f00579e20270fc92794f9e4bc5df2c25ebbce564700c114cdf69e0b213ddb0192c24af4fc4cdf468918702 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-loong64@npm:0.17.19" - conditions: os=linux & cpu=loong64 +"@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.8.3": + version: 7.22.13 + resolution: "@babel/code-frame@npm:7.22.13" + dependencies: + "@babel/highlight": ^7.22.13 + chalk: ^2.4.2 + checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-mips64el@npm:0.17.19" - conditions: os=linux & cpu=mips64el +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.2": + version: 7.23.2 + resolution: "@babel/compat-data@npm:7.23.2" + checksum: d8dc27437d40907b271161d4c88ffe72ccecb034c730deb1960a417b59a14d7c5ebca8cd80dd458a01cd396a7a329eb48cddcc3791b5a84da33d7f278f7bec6a + languageName: node + linkType: hard + +"@babel/core@npm:7.12.9": + version: 7.12.9 + resolution: "@babel/core@npm:7.12.9" + dependencies: + "@babel/code-frame": ^7.10.4 + "@babel/generator": ^7.12.5 + "@babel/helper-module-transforms": ^7.12.1 + "@babel/helpers": ^7.12.5 + "@babel/parser": ^7.12.7 + "@babel/template": ^7.12.7 + "@babel/traverse": ^7.12.9 + "@babel/types": ^7.12.7 + convert-source-map: ^1.7.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.1 + json5: ^2.1.2 + lodash: ^4.17.19 + resolve: ^1.3.2 + semver: ^5.4.1 + source-map: ^0.5.0 + checksum: 4d34eca4688214a4eb6bd5dde906b69a7824f17b931f52cd03628a8ac94d8fbe15565aebffdde106e974c8738cd64ac62c6a6060baa7139a06db1f18c4ff872d + languageName: node + linkType: hard + +"@babel/core@npm:^7.18.6, @babel/core@npm:^7.19.6": + version: 7.23.2 + resolution: "@babel/core@npm:7.23.2" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.23.0 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-module-transforms": ^7.23.0 + "@babel/helpers": ^7.23.2 + "@babel/parser": ^7.23.0 + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.23.2 + "@babel/types": ^7.23.0 + convert-source-map: ^2.0.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.3 + semver: ^6.3.1 + checksum: 003897718ded16f3b75632d63cd49486bf67ff206cc7ebd1a10d49e2456f8d45740910d5ec7e42e3faf0deec7a2e96b1a02e766d19a67a8309053f0d4e57c0fe languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-ppc64@npm:0.17.19" - conditions: os=linux & cpu=ppc64 +"@babel/generator@npm:^7.12.5, @babel/generator@npm:^7.18.7, @babel/generator@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/generator@npm:7.23.0" + dependencies: + "@babel/types": ^7.23.0 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 8efe24adad34300f1f8ea2add420b28171a646edc70f2a1b3e1683842f23b8b7ffa7e35ef0119294e1901f45bfea5b3dc70abe1f10a1917ccdfb41bed69be5f1 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-riscv64@npm:0.17.19" - conditions: os=linux & cpu=riscv64 +"@babel/helper-annotate-as-pure@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 53da330f1835c46f26b7bf4da31f7a496dee9fd8696cca12366b94ba19d97421ce519a74a837f687749318f94d1a37f8d1abcbf35e8ed22c32d16373b2f6198d languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-s390x@npm:0.17.19" - conditions: os=linux & cpu=s390x +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + checksum: 639c697a1c729f9fafa2dd4c9af2e18568190299b5907bd4c2d0bc818fcbd1e83ffeecc2af24327a7faa7ac4c34edd9d7940510a5e66296c19bad17001cf5c7a languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-x64@npm:0.17.19" - conditions: os=linux & cpu=x64 +"@babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6": + version: 7.22.15 + resolution: "@babel/helper-compilation-targets@npm:7.22.15" + dependencies: + "@babel/compat-data": ^7.22.9 + "@babel/helper-validator-option": ^7.22.15 + browserslist: ^4.21.9 + lru-cache: ^5.1.1 + semver: ^6.3.1 + checksum: ce85196769e091ae54dd39e4a80c2a9df1793da8588e335c383d536d54f06baf648d0a08fc873044f226398c4ded15c4ae9120ee18e7dfd7c639a68e3cdc9980 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/netbsd-x64@npm:0.17.19" - conditions: os=netbsd & cpu=x64 +"@babel/helper-create-class-features-plugin@npm:^7.22.11, @babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-create-class-features-plugin@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.5 + "@babel/helper-function-name": ^7.22.5 + "@babel/helper-member-expression-to-functions": ^7.22.15 + "@babel/helper-optimise-call-expression": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.9 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 52c500d8d164abb3a360b1b7c4b8fff77bc4a5920d3a2b41ae6e1d30617b0dc0b972c1f5db35b1752007e04a748908b4a99bc872b73549ae837e87dcdde005a3 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/openbsd-x64@npm:0.17.19" - conditions: os=openbsd & cpu=x64 +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + regexpu-core: ^5.3.1 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 0243b8d4854f1dc8861b1029a46d3f6393ad72f366a5a08e36a4648aa682044f06da4c6e87a456260e1e1b33c999f898ba591a0760842c1387bcc93fbf2151a6 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/sunos-x64@npm:0.17.19" - conditions: os=sunos & cpu=x64 +"@babel/helper-define-polyfill-provider@npm:^0.4.3": + version: 0.4.3 + resolution: "@babel/helper-define-polyfill-provider@npm:0.4.3" + dependencies: + "@babel/helper-compilation-targets": ^7.22.6 + "@babel/helper-plugin-utils": ^7.22.5 + debug: ^4.1.1 + lodash.debounce: ^4.0.8 + resolve: ^1.14.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 5d21e3f47b320e4b5b644195ec405e7ebc3739e48e65899efc808c5fa9c3bf5b06ce0d8ff5246ca99d1411e368f4557bc66730196c5781a5c4e986ee703bee79 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-arm64@npm:0.17.19" - conditions: os=win32 & cpu=arm64 +"@babel/helper-environment-visitor@npm:^7.22.20, @babel/helper-environment-visitor@npm:^7.22.5": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-ia32@npm:0.17.19" - conditions: os=win32 & cpu=ia32 +"@babel/helper-function-name@npm:^7.22.5, @babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" + dependencies: + "@babel/template": ^7.22.15 + "@babel/types": ^7.23.0 + checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-x64@npm:0.17.19" - conditions: os=win32 & cpu=x64 +"@babel/helper-hoist-variables@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-hoist-variables@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": - version: 4.4.0 - resolution: "@eslint-community/eslint-utils@npm:4.4.0" +"@babel/helper-member-expression-to-functions@npm:^7.22.15": + version: 7.23.0 + resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" dependencies: - eslint-visitor-keys: ^3.3.0 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22 + "@babel/types": ^7.23.0 + checksum: 494659361370c979ada711ca685e2efe9460683c36db1b283b446122596602c901e291e09f2f980ecedfe6e0f2bd5386cb59768285446530df10c14df1024e75 languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.5.1": - version: 4.9.1 - resolution: "@eslint-community/regexpp@npm:4.9.1" - checksum: 06fb839e9c756f6375cc545c2f2e05a0a64576bd6370e8e3c07983fd29a3d6e164ef4aa48a361f7d27e6713ab79c83053ff6a2ccb78748bc955e344279c4a3b6 +"@babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-module-imports@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702 languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.6.1": - version: 4.8.1 - resolution: "@eslint-community/regexpp@npm:4.8.1" - checksum: 82d62c845ef42b810f268cfdc84d803a2da01735fb52e902fd34bdc09f92464a094fd8e4802839874b000b2f73f67c972859e813ba705233515d3e954f234bf2 +"@babel/helper-module-transforms@npm:^7.12.1, @babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-module-transforms@npm:7.23.0" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-simple-access": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/helper-validator-identifier": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 6e2afffb058cf3f8ce92f5116f710dda4341c81cfcd872f9a0197ea594f7ce0ab3cb940b0590af2fe99e60d2e5448bfba6bca8156ed70a2ed4be2adc8586c891 languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.2": - version: 2.1.2 - resolution: "@eslint/eslintrc@npm:2.1.2" +"@babel/helper-optimise-call-expression@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.6.0 - globals: ^13.19.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: bc742a1e3b361f06fedb4afb6bf32cbd27171292ef7924f61c62f2aed73048367bcc7ac68f98c06d4245cd3fabc43270f844e3c1699936d4734b3ac5398814a7 + "@babel/types": ^7.22.5 + checksum: c70ef6cc6b6ed32eeeec4482127e8be5451d0e5282d5495d5d569d39eb04d7f1d66ec99b327f45d1d5842a9ad8c22d48567e93fc502003a47de78d122e355f7c languageName: node linkType: hard -"@eslint/js@npm:8.50.0": - version: 8.50.0 - resolution: "@eslint/js@npm:8.50.0" - checksum: 302478f2acaaa7228729ec6a04f56641590185e1d8cd1c836a6db8a6b8009f80a57349341be9fbb9aa1721a7a569d1be3ffc598a33300d22816f11832095386c +"@babel/helper-plugin-utils@npm:7.10.4": + version: 7.10.4 + resolution: "@babel/helper-plugin-utils@npm:7.10.4" + checksum: 639ed8fc462b97a83226cee6bb081b1d77e7f73e8b033d2592ed107ee41d96601e321e5ea53a33e47469c7f1146b250a3dcda5ab873c7de162ab62120c341a41 languageName: node linkType: hard -"@esm-bundle/chai@npm:^4.3.4-fix.0": - version: 4.3.4 - resolution: "@esm-bundle/chai@npm:4.3.4" - dependencies: - "@types/chai": ^4.2.12 - checksum: 6d1237e9b8309b31ca55d12abe03642ab58550fdac24d0acbfeae6ab14182f72cedf646c6e858fd7ef592b4034ddd23ce5882ff22b8ab9b7952327e9f3f8c3f5 +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.22.5 + resolution: "@babel/helper-plugin-utils@npm:7.22.5" + checksum: c0fc7227076b6041acd2f0e818145d2e8c41968cc52fb5ca70eed48e21b8fe6dd88a0a91cbddf4951e33647336eb5ae184747ca706817ca3bef5e9e905151ff5 languageName: node linkType: hard -"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/abi@npm:5.7.0" +"@babel/helper-remap-async-to-generator@npm:^7.22.20, @babel/helper-remap-async-to-generator@npm:^7.22.5": + version: 7.22.20 + resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" dependencies: - "@ethersproject/address": ^5.7.0 - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/constants": ^5.7.0 - "@ethersproject/hash": ^5.7.0 - "@ethersproject/keccak256": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - "@ethersproject/properties": ^5.7.0 - "@ethersproject/strings": ^5.7.0 - checksum: bc6962bb6cb854e4d2a4d65b2c49c716477675b131b1363312234bdbb7e19badb7d9ce66f4ca2a70ae2ea84f7123dbc4e300a1bfe5d58864a7eafabc1466627e + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-wrap-function": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 2fe6300a6f1b58211dffa0aed1b45d4958506d096543663dba83bd9251fe8d670fa909143a65b45e72acb49e7e20fbdb73eae315d9ddaced467948c3329986e7 languageName: node linkType: hard -"@ethersproject/abstract-provider@npm:5.7.0, @ethersproject/abstract-provider@npm:^5.7.0": +"@babel/helper-replace-supers@npm:^7.22.5, @babel/helper-replace-supers@npm:^7.22.9": + version: 7.22.20 + resolution: "@babel/helper-replace-supers@npm:7.22.20" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-member-expression-to-functions": ^7.22.15 + "@babel/helper-optimise-call-expression": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a0008332e24daedea2e9498733e3c39b389d6d4512637e000f96f62b797e702ee24a407ccbcd7a236a551590a38f31282829a8ef35c50a3c0457d88218cae639 + languageName: node + linkType: hard + +"@babel/helper-simple-access@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-simple-access@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: fe9686714caf7d70aedb46c3cce090f8b915b206e09225f1e4dbc416786c2fdbbee40b38b23c268b7ccef749dd2db35f255338fb4f2444429874d900dede5ad2 + languageName: node + linkType: hard + +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 1012ef2295eb12dc073f2b9edf3425661e9b8432a3387e62a8bc27c42963f1f216ab3124228015c748770b2257b4f1fda882ca8fa34c0bf485e929ae5bc45244 + languageName: node + linkType: hard + +"@babel/helper-split-export-declaration@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/helper-split-export-declaration@npm:7.22.6" + dependencies: + "@babel/types": ^7.22.5 + checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-string-parser@npm:7.22.5" + checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-validator-option@npm:7.22.15" + checksum: 68da52b1e10002a543161494c4bc0f4d0398c8fdf361d5f7f4272e95c45d5b32d974896d44f6a0ea7378c9204988879d73613ca683e13bd1304e46d25ff67a8d + languageName: node + linkType: hard + +"@babel/helper-wrap-function@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-wrap-function@npm:7.22.20" + dependencies: + "@babel/helper-function-name": ^7.22.5 + "@babel/template": ^7.22.15 + "@babel/types": ^7.22.19 + checksum: 221ed9b5572612aeb571e4ce6a256f2dee85b3c9536f1dd5e611b0255e5f59a3d0ec392d8d46d4152149156a8109f92f20379b1d6d36abb613176e0e33f05fca + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.12.5, @babel/helpers@npm:^7.23.2": + version: 7.23.2 + resolution: "@babel/helpers@npm:7.23.2" + dependencies: + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.23.2 + "@babel/types": ^7.23.0 + checksum: aaf4828df75ec460eaa70e5c9f66e6dadc28dae3728ddb7f6c13187dbf38030e142194b83d81aa8a31bbc35a5529a5d7d3f3cf59d5d0b595f5dd7f9d8f1ced8e + languageName: node + linkType: hard + +"@babel/highlight@npm:^7.22.13": + version: 7.22.20 + resolution: "@babel/highlight@npm:7.22.20" + dependencies: + "@babel/helper-validator-identifier": ^7.22.20 + chalk: ^2.4.2 + js-tokens: ^4.0.0 + checksum: 84bd034dca309a5e680083cd827a766780ca63cef37308404f17653d32366ea76262bd2364b2d38776232f2d01b649f26721417d507e8b4b6da3e4e739f6d134 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.12.7, @babel/parser@npm:^7.18.8, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/parser@npm:7.23.0" + bin: + parser: ./bin/babel-parser.js + checksum: 453fdf8b9e2c2b7d7b02139e0ce003d1af21947bbc03eb350fb248ee335c9b85e4ab41697ddbdd97079698de825a265e45a0846bb2ed47a2c7c1df833f42a354 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 8910ca21a7ec7c06f7b247d4b86c97c5aa15ef321518f44f6f490c5912fdf82c605aaa02b90892e375d82ccbedeadfdeadd922c1b836c9dd4c596871bf654753 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/plugin-transform-optional-chaining": ^7.22.15 + peerDependencies: + "@babel/core": ^7.13.0 + checksum: fbefedc0da014c37f1a50a8094ce7dbbf2181ae93243f23d6ecba2499b5b20196c2124d6a4dfe3e9e0125798e80593103e456352a4beb4e5c6f7c75efb80fdac + languageName: node + linkType: hard + +"@babel/plugin-proposal-object-rest-spread@npm:7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-object-rest-spread": ^7.8.0 + "@babel/plugin-transform-parameters": ^7.12.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 221a41630c9a7162bf0416c71695b3f7f38482078a1d0d3af7abdc4f07ea1c9feed890399158d56c1d0278c971fe6f565ce822e9351e4481f7d98e9ff735dced + languageName: node + linkType: hard + +"@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2": + version: 7.21.0-placeholder-for-preset-env.2 + resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d97745d098b835d55033ff3a7fb2b895b9c5295b08a5759e4f20df325aa385a3e0bc9bd5ad8f2ec554a44d4e6525acfc257b8c5848a1345cb40f26a30e277e91 + languageName: node + linkType: hard + +"@babel/plugin-syntax-async-generators@npm:^7.8.4": + version: 7.8.4 + resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-properties@npm:^7.12.13": + version: 7.12.13 + resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" + dependencies: + "@babel/helper-plugin-utils": ^7.12.13 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-static-block@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 + languageName: node + linkType: hard + +"@babel/plugin-syntax-dynamic-import@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ce307af83cf433d4ec42932329fad25fa73138ab39c7436882ea28742e1c0066626d224e0ad2988724c82644e41601cef607b36194f695cb78a1fcdc959637bd + languageName: node + linkType: hard + +"@babel/plugin-syntax-export-namespace-from@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-export-namespace-from@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 85740478be5b0de185228e7814451d74ab8ce0a26fcca7613955262a26e99e8e15e9da58f60c754b84515d4c679b590dbd3f2148f0f58025f4ae706f1c5a5d4a + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-assertions@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2b8b5572db04a7bef1e6cd20debf447e4eef7cb012616f5eceb8fa3e23ce469b8f76ee74fd6d1e158ba17a8f58b0aec579d092fb67c5a30e83ccfbc5754916c1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-attributes@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 197b3c5ea2a9649347f033342cb222ab47f4645633695205c0250c6bf2af29e643753b8bb24a2db39948bef08e7c540babfd365591eb57fc110cb30b425ffc47 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-meta@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b + languageName: node + linkType: hard + +"@babel/plugin-syntax-json-strings@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-syntax-jsx@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d4b9b589c484b2e0856799770f060dff34c67b24d7f4526f66309a0e0e9cf388a5c1f2c0da329d1973cc87d1b2cede8f3dc8facfac59e785d6393a003bcdd0f9 + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-jsx@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8829d30c2617ab31393d99cec2978e41f014f4ac6f01a1cecf4c4dd8320c3ec12fdc3ce121126b2d8d32f6887e99ca1a0bad53dedb1e6ad165640b92b24980ce + languageName: node + linkType: hard + +"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: aff33577037e34e515911255cdbb1fd39efee33658aa00b8a5fd3a4b903585112d037cce1cc9e4632f0487dc554486106b79ccd5ea63a2e00df4363f6d4ff886 + languageName: node + linkType: hard + +"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-object-rest-spread@npm:7.8.3, @babel/plugin-syntax-object-rest-spread@npm:^7.8.0, @babel/plugin-syntax-object-rest-spread@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-chaining@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 + languageName: node + linkType: hard + +"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda + languageName: node + linkType: hard + +"@babel/plugin-syntax-top-level-await@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e + languageName: node + linkType: hard + +"@babel/plugin-syntax-typescript@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-typescript@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8ab7718fbb026d64da93681a57797d60326097fd7cb930380c8bffd9eb101689e90142c760a14b51e8e69c88a73ba3da956cb4520a3b0c65743aee5c71ef360a + languageName: node + linkType: hard + +"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a651d700fe63ff0ddfd7186f4ebc24447ca734f114433139e3c027bc94a900d013cf1ef2e2db8430425ba542e39ae160c3b05f06b59fd4656273a3df97679e9c + languageName: node + linkType: hard + +"@babel/plugin-transform-arrow-functions@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 35abb6c57062802c7ce8bd96b2ef2883e3124370c688bbd67609f7d2453802fb73944df8808f893b6c67de978eb2bcf87bbfe325e46d6f39b5fcb09ece11d01a + languageName: node + linkType: hard + +"@babel/plugin-transform-async-generator-functions@npm:^7.23.2": + version: 7.23.2 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.2" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-remap-async-to-generator": ^7.22.20 + "@babel/plugin-syntax-async-generators": ^7.8.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e1abae0edcda7304d7c17702ac25a127578791b89c4f767d60589249fa3e50ec33f8c9ff39d3d8d41f00b29947654eaddd4fd586e04c4d598122db745fab2868 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-to-generator@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.22.5" + dependencies: + "@babel/helper-module-imports": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-remap-async-to-generator": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b95f23f99dcb379a9f0a1c2a3bbea3f8dc0e1b16dc1ac8b484fe378370169290a7a63d520959a9ba1232837cf74a80e23f6facbe14fd42a3cda6d3c2d7168e62 + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoped-functions@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 416b1341858e8ca4e524dee66044735956ced5f478b2c3b9bc11ec2285b0c25d7dbb96d79887169eb938084c95d0a89338c8b2fe70d473bd9dc92e5d9db1732c + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoping@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/plugin-transform-block-scoping@npm:7.23.0" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0cfe925cc3b5a3ad407e2253fab3ceeaa117a4b291c9cb245578880872999bca91bd83ffa0128ae9ca356330702e1ef1dcb26804f28d2cef678239caf629f73e + languageName: node + linkType: hard + +"@babel/plugin-transform-class-properties@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-class-properties@npm:7.22.5" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b830152dfc2ff2f647f0abe76e6251babdfbef54d18c4b2c73a6bf76b1a00050a5d998dac80dc901a48514e95604324943a9dd39317073fe0928b559e0e0c579 + languageName: node + linkType: hard + +"@babel/plugin-transform-class-static-block@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-class-static-block@npm:7.22.11" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.11 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + peerDependencies: + "@babel/core": ^7.12.0 + checksum: 69f040506fad66f1c6918d288d0e0edbc5c8a07c8b4462c1184ad2f9f08995d68b057126c213871c0853ae0c72afc60ec87492049dfacb20902e32346a448bcb + languageName: node + linkType: hard + +"@babel/plugin-transform-classes@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-classes@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-environment-visitor": ^7.22.5 + "@babel/helper-function-name": ^7.22.5 + "@babel/helper-optimise-call-expression": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.9 + "@babel/helper-split-export-declaration": ^7.22.6 + globals: ^11.1.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d3f4d0c107dd8a3557ea3575cc777fab27efa92958b41e4a9822f7499725c1f554beae58855de16ddec0a7b694e45f59a26cea8fbde4275563f72f09c6e039a0 + languageName: node + linkType: hard + +"@babel/plugin-transform-computed-properties@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-computed-properties@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/template": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c2a77a0f94ec71efbc569109ec14ea2aa925b333289272ced8b33c6108bdbb02caf01830ffc7e49486b62dec51911924d13f3a76f1149f40daace1898009e131 + languageName: node + linkType: hard + +"@babel/plugin-transform-destructuring@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/plugin-transform-destructuring@npm:7.23.0" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cd6dd454ccc2766be551e4f8a04b1acc2aa539fa19e5c7501c56cc2f8cc921dd41a7ffb78455b4c4b2f954fcab8ca4561ba7c9c7bd5af9f19465243603d18cc3 + languageName: node + linkType: hard + +"@babel/plugin-transform-dotall-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 409b658d11e3082c8f69e9cdef2d96e4d6d11256f005772425fb230cc48fd05945edbfbcb709dab293a1a2f01f9c8a5bb7b4131e632b23264039d9f95864b453 + languageName: node + linkType: hard + +"@babel/plugin-transform-duplicate-keys@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bb1280fbabaab6fab2ede585df34900712698210a3bd413f4df5bae6d8c24be36b496c92722ae676a7a67d060a4624f4d6c23b923485f906bfba8773c69f55b4 + languageName: node + linkType: hard + +"@babel/plugin-transform-dynamic-import@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 78fc9c532210bf9e8f231747f542318568ac360ee6c27e80853962c984283c73da3f8f8aebe83c2096090a435b356b092ed85de617a156cbe0729d847632be45 + languageName: node + linkType: hard + +"@babel/plugin-transform-exponentiation-operator@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.22.5" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f2d660c1b1d51ad5fec1cd5ad426a52187204068c4158f8c4aa977b31535c61b66898d532603eef21c15756827be8277f724c869b888d560f26d7fe848bb5eae + languageName: node + linkType: hard + +"@babel/plugin-transform-export-namespace-from@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 73af5883a321ed56a4bfd43c8a7de0164faebe619287706896fc6ee2f7a4e69042adaa1338c0b8b4bdb9f7e5fdceb016fb1d40694cb43ca3b8827429e8aac4bf + languageName: node + linkType: hard + +"@babel/plugin-transform-for-of@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-for-of@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f395ae7bce31e14961460f56cf751b5d6e37dd27d7df5b1f4e49fec1c11b6f9cf71991c7ffbe6549878591e87df0d66af798cf26edfa4bfa6b4c3dba1fb2f73a + languageName: node + linkType: hard + +"@babel/plugin-transform-function-name@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-function-name@npm:7.22.5" + dependencies: + "@babel/helper-compilation-targets": ^7.22.5 + "@babel/helper-function-name": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cff3b876357999cb8ae30e439c3ec6b0491a53b0aa6f722920a4675a6dd5b53af97a833051df4b34791fe5b3dd326ccf769d5c8e45b322aa50ee11a660b17845 + languageName: node + linkType: hard + +"@babel/plugin-transform-json-strings@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-json-strings@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-json-strings": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 50665e5979e66358c50e90a26db53c55917f78175127ac2fa05c7888d156d418ffb930ec0a109353db0a7c5f57c756ce01bfc9825d24cbfd2b3ec453f2ed8cba + languageName: node + linkType: hard + +"@babel/plugin-transform-literals@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-literals@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ec37cc2ffb32667af935ab32fe28f00920ec8a1eb999aa6dc6602f2bebd8ba205a558aeedcdccdebf334381d5c57106c61f52332045730393e73410892a9735b + languageName: node + linkType: hard + +"@babel/plugin-transform-logical-assignment-operators@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c664e9798e85afa7f92f07b867682dee7392046181d82f5d21bae6f2ca26dfe9c8375cdc52b7483c3fc09a983c1989f60eff9fbc4f373b0c0a74090553d05739 + languageName: node + linkType: hard + +"@babel/plugin-transform-member-expression-literals@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ec4b0e07915ddd4fda0142fd104ee61015c208608a84cfa13643a95d18760b1dc1ceb6c6e0548898b8c49e5959a994e46367260176dbabc4467f729b21868504 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-amd@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/plugin-transform-modules-amd@npm:7.23.0" + dependencies: + "@babel/helper-module-transforms": ^7.23.0 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 5d92875170a37b8282d4bcd805f55829b8fab0f9c8d08b53d32a7a0bfdc62b868e489b52d329ae768ecafc0c993eed0ad7a387baa673ac33211390a9f833ab5d + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.23.0" + dependencies: + "@babel/helper-module-transforms": ^7.23.0 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-simple-access": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7fb25997194053e167c4207c319ff05362392da841bd9f42ddb3caf9c8798a5d203bd926d23ddf5830fdf05eddc82c2810f40d1287e3a4f80b07eff13d1024b5 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-systemjs@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.0" + dependencies: + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-module-transforms": ^7.23.0 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2d481458b22605046badea2317d5cc5c94ac3031c2293e34c96f02063f5b02af0979c4da6a8fbc67cc249541575dc9c6d710db6b919ede70b7337a22d9fd57a7 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-umd@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-modules-umd@npm:7.22.5" + dependencies: + "@babel/helper-module-transforms": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 46622834c54c551b231963b867adbc80854881b3e516ff29984a8da989bd81665bd70e8cba6710345248e97166689310f544aee1a5773e262845a8f1b3e5b8b4 + languageName: node + linkType: hard + +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 3ee564ddee620c035b928fdc942c5d17e9c4b98329b76f9cefac65c111135d925eb94ed324064cd7556d4f5123beec79abea1d4b97d1c8a2a5c748887a2eb623 + languageName: node + linkType: hard + +"@babel/plugin-transform-new-target@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-new-target@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6b72112773487a881a1d6ffa680afde08bad699252020e86122180ee7a88854d5da3f15d9bca3331cf2e025df045604494a8208a2e63b486266b07c14e2ffbf3 + languageName: node + linkType: hard + +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 167babecc8b8fe70796a7b7d34af667ebbf43da166c21689502e5e8cc93180b7a85979c77c9f64b7cce431b36718bd0a6df9e5e0ffea4ae22afb22cfef886372 + languageName: node + linkType: hard + +"@babel/plugin-transform-numeric-separator@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: af064d06a4a041767ec396a5f258103f64785df290e038bba9f0ef454e6c914f2ac45d862bbdad8fac2c7ad47fa4e95356f29053c60c100a0160b02a995fe2a3 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-rest-spread@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.15" + dependencies: + "@babel/compat-data": ^7.22.9 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-transform-parameters": ^7.22.15 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 62197a6f12289c1c1bd57f3bed9f0f765ca32390bfe91e0b5561dd94dd9770f4480c4162dec98da094bc0ba99d2c2ebba68de47c019454041b0b7a68ba2ec66d + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-object-super@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b71887877d74cb64dbccb5c0324fa67e31171e6a5311991f626650e44a4083e5436a1eaa89da78c0474fb095d4ec322d63ee778b202d33aa2e4194e1ed8e62d7 + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-catch-binding@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f17abd90e1de67c84d63afea29c8021c74abb2794d3a6eeafb0bbe7372d3db32aefca386e392116ec63884537a4a2815d090d26264d259bacc08f6e3ed05294c + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-chaining@npm:^7.22.15, @babel/plugin-transform-optional-chaining@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.23.0" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f702634f2b97e5260dbec0d4bde05ccb6f4d96d7bfa946481aeacfa205ca846cb6e096a38312f9d51fdbdac1f258f211138c5f7075952e46a5bf8574de6a1329 + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.12.1, @babel/plugin-transform-parameters@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-parameters@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 541188bb7d1876cad87687b5c7daf90f63d8208ae83df24acb1e2b05020ad1c78786b2723ca4054a83fcb74fb6509f30c4cacc5b538ee684224261ad5fb047c1 + languageName: node + linkType: hard + +"@babel/plugin-transform-private-methods@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-private-methods@npm:7.22.5" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 321479b4fcb6d3b3ef622ab22fd24001e43d46e680e8e41324c033d5810c84646e470f81b44cbcbef5c22e99030784f7cac92f1829974da7a47a60a7139082c3 + languageName: node + linkType: hard + +"@babel/plugin-transform-private-property-in-object@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.11" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.11 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4d029d84901e53c46dead7a46e2990a7bc62470f4e4ca58a0d063394f86652fd58fe4eea1eb941da3669cd536b559b9d058b342b59300026346b7a2a51badac8 + languageName: node + linkType: hard + +"@babel/plugin-transform-property-literals@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-property-literals@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 796176a3176106f77fcb8cd04eb34a8475ce82d6d03a88db089531b8f0453a2fb8b0c6ec9a52c27948bc0ea478becec449893741fc546dfc3930ab927e3f9f2e + languageName: node + linkType: hard + +"@babel/plugin-transform-react-constant-elements@npm:^7.18.12": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-constant-elements@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 596db90e37174dd703f4859fef3c86156a7c8564d8351168ac6fdca79c912ef8b8746ae04516ac3909d2cc750702d58d451badacb3c54ea998938ad05d99f9d2 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-display-name@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-display-name@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a12bfd1e4e93055efca3ace3c34722571bda59d9740dca364d225d9c6e3ca874f134694d21715c42cc63d79efd46db9665bd4a022998767f9245f1e29d5d204d + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-development@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.22.5" + dependencies: + "@babel/plugin-transform-react-jsx": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 36bc3ff0b96bb0ef4723070a50cfdf2e72cfd903a59eba448f9fe92fea47574d6f22efd99364413719e1f3fb3c51b6c9b2990b87af088f8486a84b2a5f9e4560 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx@npm:^7.22.15, @babel/plugin-transform-react-jsx@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/plugin-transform-react-jsx@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-jsx": ^7.22.5 + "@babel/types": ^7.22.15 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3899054e89550c3a0ef041af7c47ee266e2e934f498ee80fefeda778a6aa177b48aa8b4d2a8bf5848de977fec564571699ab952d9fa089c4c19b45ddb121df09 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-pure-annotations@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.22.5" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 092021c4f404e267002099ec20b3f12dd730cb90b0d83c5feed3dc00dbe43b9c42c795a18e7c6c7d7bddea20c7dd56221b146aec81b37f2e7eb5137331c61120 + languageName: node + linkType: hard + +"@babel/plugin-transform-regenerator@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-transform-regenerator@npm:7.22.10" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + regenerator-transform: ^0.15.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e13678d62d6fa96f11cb8b863f00e8693491e7adc88bfca3f2820f80cbac8336e7dec3a596eee6a1c4663b7ececc3564f2cd7fb44ed6d4ce84ac2bb7f39ecc6e + languageName: node + linkType: hard + +"@babel/plugin-transform-reserved-words@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-reserved-words@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3ffd7dbc425fe8132bfec118b9817572799cab1473113a635d25ab606c1f5a2341a636c04cf6b22df3813320365ed5a965b5eeb3192320a10e4cc2c137bd8bfc + languageName: node + linkType: hard + +"@babel/plugin-transform-runtime@npm:^7.18.6": + version: 7.23.2 + resolution: "@babel/plugin-transform-runtime@npm:7.23.2" + dependencies: + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + babel-plugin-polyfill-corejs2: ^0.4.6 + babel-plugin-polyfill-corejs3: ^0.8.5 + babel-plugin-polyfill-regenerator: ^0.5.3 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 09f4273bfe9600c67e72e26f853f11c24ee4c1cbb3935c4a28a94d388e7c0d8733479d868c333cb34e9c236f1765788c6daef7852331f5c70a3b5543fd0247a1 + languageName: node + linkType: hard + +"@babel/plugin-transform-shorthand-properties@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a5ac902c56ea8effa99f681340ee61bac21094588f7aef0bc01dff98246651702e677552fa6d10e548c4ac22a3ffad047dd2f8c8f0540b68316c2c203e56818b + languageName: node + linkType: hard + +"@babel/plugin-transform-spread@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-spread@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 5587f0deb60b3dfc9b274e269031cc45ec75facccf1933ea2ea71ced9fd3ce98ed91bb36d6cd26817c14474b90ed998c5078415f0eab531caf301496ce24c95c + languageName: node + linkType: hard + +"@babel/plugin-transform-sticky-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 63b2c575e3e7f96c32d52ed45ee098fb7d354b35c2223b8c8e76840b32cc529ee0c0ceb5742fd082e56e91e3d82842a367ce177e82b05039af3d602c9627a729 + languageName: node + linkType: hard + +"@babel/plugin-transform-template-literals@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-template-literals@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 27e9bb030654cb425381c69754be4abe6a7c75b45cd7f962cd8d604b841b2f0fb7b024f2efc1c25cc53f5b16d79d5e8cfc47cacbdaa983895b3aeefa3e7e24ff + languageName: node + linkType: hard + +"@babel/plugin-transform-typeof-symbol@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 82a53a63ffc3010b689ca9a54e5f53b2718b9f4b4a9818f36f9b7dba234f38a01876680553d2716a645a61920b5e6e4aaf8d4a0064add379b27ca0b403049512 + languageName: node + linkType: hard + +"@babel/plugin-transform-typescript@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-typescript@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-typescript": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c5d96cdbf0e1512707aa1c1e3ac6b370a25fd9c545d26008ce44eb13a47bd7fd67a1eb799c98b5ccc82e33a345fda55c0055e1fe3ed97646ed405dd13020b226 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-escapes@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.22.10" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 807f40ed1324c8cb107c45358f1903384ca3f0ef1d01c5a3c5c9b271c8d8eec66936a3dcc8d75ddfceea9421420368c2e77ae3adef0a50557e778dfe296bf382 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-property-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2495e5f663cb388e3d888b4ba3df419ac436a5012144ac170b622ddfc221f9ea9bdba839fa2bc0185cb776b578030666406452ec7791cbf0e7a3d4c88ae9574c + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6b5d1404c8c623b0ec9bd436c00d885a17d6a34f3f2597996343ddb9d94f6379705b21582dfd4cec2c47fd34068872e74ab6b9580116c0566b3f9447e2a7fa06 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-sets-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: c042070f980b139547f8b0179efbc049ac5930abec7fc26ed7a41d89a048d8ab17d362200e204b6f71c3c20d6991a0e74415e1a412a49adc8131c2a40c04822e + languageName: node + linkType: hard + +"@babel/preset-env@npm:^7.18.6, @babel/preset-env@npm:^7.19.4": + version: 7.23.2 + resolution: "@babel/preset-env@npm:7.23.2" + dependencies: + "@babel/compat-data": ^7.23.2 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.22.15 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.22.15 + "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 + "@babel/plugin-syntax-async-generators": ^7.8.4 + "@babel/plugin-syntax-class-properties": ^7.12.13 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + "@babel/plugin-syntax-import-assertions": ^7.22.5 + "@babel/plugin-syntax-import-attributes": ^7.22.5 + "@babel/plugin-syntax-import-meta": ^7.10.4 + "@babel/plugin-syntax-json-strings": ^7.8.3 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + "@babel/plugin-syntax-top-level-await": ^7.14.5 + "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 + "@babel/plugin-transform-arrow-functions": ^7.22.5 + "@babel/plugin-transform-async-generator-functions": ^7.23.2 + "@babel/plugin-transform-async-to-generator": ^7.22.5 + "@babel/plugin-transform-block-scoped-functions": ^7.22.5 + "@babel/plugin-transform-block-scoping": ^7.23.0 + "@babel/plugin-transform-class-properties": ^7.22.5 + "@babel/plugin-transform-class-static-block": ^7.22.11 + "@babel/plugin-transform-classes": ^7.22.15 + "@babel/plugin-transform-computed-properties": ^7.22.5 + "@babel/plugin-transform-destructuring": ^7.23.0 + "@babel/plugin-transform-dotall-regex": ^7.22.5 + "@babel/plugin-transform-duplicate-keys": ^7.22.5 + "@babel/plugin-transform-dynamic-import": ^7.22.11 + "@babel/plugin-transform-exponentiation-operator": ^7.22.5 + "@babel/plugin-transform-export-namespace-from": ^7.22.11 + "@babel/plugin-transform-for-of": ^7.22.15 + "@babel/plugin-transform-function-name": ^7.22.5 + "@babel/plugin-transform-json-strings": ^7.22.11 + "@babel/plugin-transform-literals": ^7.22.5 + "@babel/plugin-transform-logical-assignment-operators": ^7.22.11 + "@babel/plugin-transform-member-expression-literals": ^7.22.5 + "@babel/plugin-transform-modules-amd": ^7.23.0 + "@babel/plugin-transform-modules-commonjs": ^7.23.0 + "@babel/plugin-transform-modules-systemjs": ^7.23.0 + "@babel/plugin-transform-modules-umd": ^7.22.5 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5 + "@babel/plugin-transform-new-target": ^7.22.5 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.11 + "@babel/plugin-transform-numeric-separator": ^7.22.11 + "@babel/plugin-transform-object-rest-spread": ^7.22.15 + "@babel/plugin-transform-object-super": ^7.22.5 + "@babel/plugin-transform-optional-catch-binding": ^7.22.11 + "@babel/plugin-transform-optional-chaining": ^7.23.0 + "@babel/plugin-transform-parameters": ^7.22.15 + "@babel/plugin-transform-private-methods": ^7.22.5 + "@babel/plugin-transform-private-property-in-object": ^7.22.11 + "@babel/plugin-transform-property-literals": ^7.22.5 + "@babel/plugin-transform-regenerator": ^7.22.10 + "@babel/plugin-transform-reserved-words": ^7.22.5 + "@babel/plugin-transform-shorthand-properties": ^7.22.5 + "@babel/plugin-transform-spread": ^7.22.5 + "@babel/plugin-transform-sticky-regex": ^7.22.5 + "@babel/plugin-transform-template-literals": ^7.22.5 + "@babel/plugin-transform-typeof-symbol": ^7.22.5 + "@babel/plugin-transform-unicode-escapes": ^7.22.10 + "@babel/plugin-transform-unicode-property-regex": ^7.22.5 + "@babel/plugin-transform-unicode-regex": ^7.22.5 + "@babel/plugin-transform-unicode-sets-regex": ^7.22.5 + "@babel/preset-modules": 0.1.6-no-external-plugins + "@babel/types": ^7.23.0 + babel-plugin-polyfill-corejs2: ^0.4.6 + babel-plugin-polyfill-corejs3: ^0.8.5 + babel-plugin-polyfill-regenerator: ^0.5.3 + core-js-compat: ^3.31.0 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 49327ef584b529b56aedd6577937b80c0d89603c68b23795495a13af04b5aa008db9ad04cd280423600cdc0d3cce13ae9d0d9a977db5c8193697b20ced8a10b2 + languageName: node + linkType: hard + +"@babel/preset-modules@npm:0.1.6-no-external-plugins": + version: 0.1.6-no-external-plugins + resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" + dependencies: + "@babel/helper-plugin-utils": ^7.0.0 + "@babel/types": ^7.4.4 + esutils: ^2.0.2 + peerDependencies: + "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 + checksum: 4855e799bc50f2449fb5210f78ea9e8fd46cf4f242243f1e2ed838e2bd702e25e73e822e7f8447722a5f4baa5e67a8f7a0e403f3e7ce04540ff743a9c411c375 + languageName: node + linkType: hard + +"@babel/preset-react@npm:^7.18.6": + version: 7.22.15 + resolution: "@babel/preset-react@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-transform-react-display-name": ^7.22.5 + "@babel/plugin-transform-react-jsx": ^7.22.15 + "@babel/plugin-transform-react-jsx-development": ^7.22.5 + "@babel/plugin-transform-react-pure-annotations": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c3ef99dfa2e9f57d2e08603e883aa20f47630a826c8e413888a93ae6e0084b5016871e463829be125329d40a1ba0a89f7c43d77b6dab52083c225cb43e63d10e + languageName: node + linkType: hard + +"@babel/preset-typescript@npm:^7.18.6": + version: 7.23.2 + resolution: "@babel/preset-typescript@npm:7.23.2" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-syntax-jsx": ^7.22.5 + "@babel/plugin-transform-modules-commonjs": ^7.23.0 + "@babel/plugin-transform-typescript": ^7.22.15 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c4b065c90e7f085dd7a0e57032983ac230c7ffd1d616e4c2b66581e765d5befc9271495f33250bf1cf9b4d436239c8ca3b19ada9f6c419c70bdab2cf6c868f9f + languageName: node + linkType: hard + +"@babel/regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "@babel/regjsgen@npm:0.8.0" + checksum: 89c338fee774770e5a487382170711014d49a68eb281e74f2b5eac88f38300a4ad545516a7786a8dd5702e9cf009c94c2f582d200f077ac5decd74c56b973730 + languageName: node + linkType: hard + +"@babel/runtime-corejs3@npm:^7.18.6": + version: 7.23.2 + resolution: "@babel/runtime-corejs3@npm:7.23.2" + dependencies: + core-js-pure: ^3.30.2 + regenerator-runtime: ^0.14.0 + checksum: 922f25c47996a8af604cea82441e41be8b11910e96c662511e54120078f4c64258c045a28a311467a8f14a0c17f46a1f057f7c0501e567869a4343a6ce017962 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.8.4": + version: 7.23.2 + resolution: "@babel/runtime@npm:7.23.2" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 6c4df4839ec75ca10175f636d6362f91df8a3137f86b38f6cd3a4c90668a0fe8e9281d320958f4fbd43b394988958585a17c3aab2a4ea6bf7316b22916a371fb + languageName: node + linkType: hard + +"@babel/template@npm:^7.12.7, @babel/template@npm:^7.22.15, @babel/template@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/template@npm:7.22.15" + dependencies: + "@babel/code-frame": ^7.22.13 + "@babel/parser": ^7.22.15 + "@babel/types": ^7.22.15 + checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.12.9, @babel/traverse@npm:^7.18.8, @babel/traverse@npm:^7.23.2": + version: 7.23.2 + resolution: "@babel/traverse@npm:7.23.2" + dependencies: + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.23.0 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/parser": ^7.23.0 + "@babel/types": ^7.23.0 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: 26a1eea0dde41ab99dde8b9773a013a0dc50324e5110a049f5d634e721ff08afffd54940b3974a20308d7952085ac769689369e9127dea655f868c0f6e1ab35d + languageName: node + linkType: hard + +"@babel/types@npm:^7.12.7, @babel/types@npm:^7.20.0, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.23.0 + resolution: "@babel/types@npm:7.23.0" + dependencies: + "@babel/helper-string-parser": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 + to-fast-properties: ^2.0.0 + checksum: 215fe04bd7feef79eeb4d33374b39909ce9cad1611c4135a4f7fdf41fe3280594105af6d7094354751514625ea92d0875aba355f53e86a92600f290e77b0e604 + languageName: node + linkType: hard + +"@chainsafe/as-sha256@npm:^0.3.1": + version: 0.3.1 + resolution: "@chainsafe/as-sha256@npm:0.3.1" + checksum: 58ea733be1657b0e31dbf48b0dba862da0833df34a81c1460c7352f04ce90874f70003cbf34d0afb9e5e53a33ee2d63a261a8b12462be85b2ba0a6f7f13d6150 + languageName: node + linkType: hard + +"@chainsafe/persistent-merkle-tree@npm:^0.4.2": + version: 0.4.2 + resolution: "@chainsafe/persistent-merkle-tree@npm:0.4.2" + dependencies: + "@chainsafe/as-sha256": ^0.3.1 + checksum: f9cfcb2132a243992709715dbd28186ab48c7c0c696f29d30857693cca5526bf753974a505ef68ffd5623bbdbcaa10f9083f4dd40bf99eb6408e451cc26a1a9e + languageName: node + linkType: hard + +"@chainsafe/persistent-merkle-tree@npm:^0.5.0": + version: 0.5.0 + resolution: "@chainsafe/persistent-merkle-tree@npm:0.5.0" + dependencies: + "@chainsafe/as-sha256": ^0.3.1 + checksum: 2c67203da776c79cd3a6132e2d672fe132393b2e63dc71604e3134acc8c0ec25cc5e431051545939ea0f7c5ff2066fb806b9e5cab974ca085d046226a1671f7d + languageName: node + linkType: hard + +"@chainsafe/ssz@npm:^0.10.0": + version: 0.10.2 + resolution: "@chainsafe/ssz@npm:0.10.2" + dependencies: + "@chainsafe/as-sha256": ^0.3.1 + "@chainsafe/persistent-merkle-tree": ^0.5.0 + checksum: 6bb70cf741d0a19dd0b28b3f6f067b96fa39f556e2eefa6ac745b21db9c3b3a8393dc3cca8ff4a6ce065ed71ddc3fb1b2b390a92004b9d01067c26e2558e5503 + languageName: node + linkType: hard + +"@chainsafe/ssz@npm:^0.9.2": + version: 0.9.4 + resolution: "@chainsafe/ssz@npm:0.9.4" + dependencies: + "@chainsafe/as-sha256": ^0.3.1 + "@chainsafe/persistent-merkle-tree": ^0.4.2 + case: ^1.6.3 + checksum: c6eaedeae9e5618b3c666ff4507a27647f665a8dcf17d5ca86da4ed4788c5a93868f256d0005467d184fdf35ec03f323517ec2e55ec42492d769540a2ec396bc + languageName: node + linkType: hard + +"@colors/colors@npm:1.5.0": + version: 1.5.0 + resolution: "@colors/colors@npm:1.5.0" + checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 + languageName: node + linkType: hard + +"@cspotcode/source-map-support@npm:^0.8.0": + version: 0.8.1 + resolution: "@cspotcode/source-map-support@npm:0.8.1" + dependencies: + "@jridgewell/trace-mapping": 0.3.9 + checksum: 5718f267085ed8edb3e7ef210137241775e607ee18b77d95aa5bd7514f47f5019aa2d82d96b3bf342ef7aa890a346fa1044532ff7cc3009e7d24fce3ce6200fa + languageName: node + linkType: hard + +"@discoveryjs/json-ext@npm:0.5.7": + version: 0.5.7 + resolution: "@discoveryjs/json-ext@npm:0.5.7" + checksum: 2176d301cc258ea5c2324402997cf8134ebb212469c0d397591636cea8d3c02f2b3cf9fd58dcb748c7a0dade77ebdc1b10284fa63e608c033a1db52fddc69918 + languageName: node + linkType: hard + +"@docsearch/css@npm:3.5.2": + version: 3.5.2 + resolution: "@docsearch/css@npm:3.5.2" + checksum: d1d60dd230dd48f896755f21bd20b59583ba844212d7d336953ae48d389baaf868bdf83320fb734a4ed679c3f95b15d620cf3764cd538f6941cae239f8c9d35d + languageName: node + linkType: hard + +"@docsearch/react@npm:^3.1.1": + version: 3.5.2 + resolution: "@docsearch/react@npm:3.5.2" + dependencies: + "@algolia/autocomplete-core": 1.9.3 + "@algolia/autocomplete-preset-algolia": 1.9.3 + "@docsearch/css": 3.5.2 + algoliasearch: ^4.19.1 + peerDependencies: + "@types/react": ">= 16.8.0 < 19.0.0" + react: ">= 16.8.0 < 19.0.0" + react-dom: ">= 16.8.0 < 19.0.0" + search-insights: ">= 1 < 3" + peerDependenciesMeta: + "@types/react": + optional: true + react: + optional: true + react-dom: + optional: true + search-insights: + optional: true + checksum: 4b4584c2c73fc18cbd599047538896450974e134c2c74f19eb202db0ce8e6c3c49c6f65ed6ade61c796d476d3cbb55d6be58df62bc9568a0c72d88e42fca1d16 + languageName: node + linkType: hard + +"@docusaurus/core@npm:2.4.3, @docusaurus/core@npm:^2.4.0": + version: 2.4.3 + resolution: "@docusaurus/core@npm:2.4.3" + dependencies: + "@babel/core": ^7.18.6 + "@babel/generator": ^7.18.7 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/plugin-transform-runtime": ^7.18.6 + "@babel/preset-env": ^7.18.6 + "@babel/preset-react": ^7.18.6 + "@babel/preset-typescript": ^7.18.6 + "@babel/runtime": ^7.18.6 + "@babel/runtime-corejs3": ^7.18.6 + "@babel/traverse": ^7.18.8 + "@docusaurus/cssnano-preset": 2.4.3 + "@docusaurus/logger": 2.4.3 + "@docusaurus/mdx-loader": 2.4.3 + "@docusaurus/react-loadable": 5.5.2 + "@docusaurus/utils": 2.4.3 + "@docusaurus/utils-common": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + "@slorber/static-site-generator-webpack-plugin": ^4.0.7 + "@svgr/webpack": ^6.2.1 + autoprefixer: ^10.4.7 + babel-loader: ^8.2.5 + babel-plugin-dynamic-import-node: ^2.3.3 + boxen: ^6.2.1 + chalk: ^4.1.2 + chokidar: ^3.5.3 + clean-css: ^5.3.0 + cli-table3: ^0.6.2 + combine-promises: ^1.1.0 + commander: ^5.1.0 + copy-webpack-plugin: ^11.0.0 + core-js: ^3.23.3 + css-loader: ^6.7.1 + css-minimizer-webpack-plugin: ^4.0.0 + cssnano: ^5.1.12 + del: ^6.1.1 + detect-port: ^1.3.0 + escape-html: ^1.0.3 + eta: ^2.0.0 + file-loader: ^6.2.0 + fs-extra: ^10.1.0 + html-minifier-terser: ^6.1.0 + html-tags: ^3.2.0 + html-webpack-plugin: ^5.5.0 + import-fresh: ^3.3.0 + leven: ^3.1.0 + lodash: ^4.17.21 + mini-css-extract-plugin: ^2.6.1 + postcss: ^8.4.14 + postcss-loader: ^7.0.0 + prompts: ^2.4.2 + react-dev-utils: ^12.0.1 + react-helmet-async: ^1.3.0 + react-loadable: "npm:@docusaurus/react-loadable@5.5.2" + react-loadable-ssr-addon-v5-slorber: ^1.0.1 + react-router: ^5.3.3 + react-router-config: ^5.1.1 + react-router-dom: ^5.3.3 + rtl-detect: ^1.0.4 + semver: ^7.3.7 + serve-handler: ^6.1.3 + shelljs: ^0.8.5 + terser-webpack-plugin: ^5.3.3 + tslib: ^2.4.0 + update-notifier: ^5.1.0 + url-loader: ^4.1.1 + wait-on: ^6.0.1 + webpack: ^5.73.0 + webpack-bundle-analyzer: ^4.5.0 + webpack-dev-server: ^4.9.3 + webpack-merge: ^5.8.0 + webpackbar: ^5.0.2 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + bin: + docusaurus: bin/docusaurus.mjs + checksum: cce7173ee131364857c16f70f94155ba0e1b044cde54045fb0cf62ad138f8d8ef093f5aba7c7617a9aa0545b3ee3930aec2e09f645daec015696968338963013 + languageName: node + linkType: hard + +"@docusaurus/cssnano-preset@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/cssnano-preset@npm:2.4.3" + dependencies: + cssnano-preset-advanced: ^5.3.8 + postcss: ^8.4.14 + postcss-sort-media-queries: ^4.2.1 + tslib: ^2.4.0 + checksum: f4a4c60b075c23541da90e00ae26af2e7eaadf20d783b37b9110a5e34599e4e91947425e33bad58ba71abee81c85cca99f5d7d76575f53fbaf73617b55e39c62 + languageName: node + linkType: hard + +"@docusaurus/logger@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/logger@npm:2.4.3" + dependencies: + chalk: ^4.1.2 + tslib: ^2.4.0 + checksum: f026a8233aa317f16ce5b25c6785a431f319c52fc07a1b9e26f4b3df2197974e75830a16b6140314f8f4ef02dc19242106ec2ae1599740b26d516cc34c56102f + languageName: node + linkType: hard + +"@docusaurus/mdx-loader@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/mdx-loader@npm:2.4.3" + dependencies: + "@babel/parser": ^7.18.8 + "@babel/traverse": ^7.18.8 + "@docusaurus/logger": 2.4.3 + "@docusaurus/utils": 2.4.3 + "@mdx-js/mdx": ^1.6.22 + escape-html: ^1.0.3 + file-loader: ^6.2.0 + fs-extra: ^10.1.0 + image-size: ^1.0.1 + mdast-util-to-string: ^2.0.0 + remark-emoji: ^2.2.0 + stringify-object: ^3.3.0 + tslib: ^2.4.0 + unified: ^9.2.2 + unist-util-visit: ^2.0.3 + url-loader: ^4.1.1 + webpack: ^5.73.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 5a774f7ea5f484e888b2bd1bf8b182279e3788afec779eb8920cf468b92ab8d83a1ae8be51925074241a4d1a38d989cfb366d2baf0f67ed6f063342395a7ca8e + languageName: node + linkType: hard + +"@docusaurus/module-type-aliases@npm:2.4.3, @docusaurus/module-type-aliases@npm:^2.4.0": + version: 2.4.3 + resolution: "@docusaurus/module-type-aliases@npm:2.4.3" + dependencies: + "@docusaurus/react-loadable": 5.5.2 + "@docusaurus/types": 2.4.3 + "@types/history": ^4.7.11 + "@types/react": "*" + "@types/react-router-config": "*" + "@types/react-router-dom": "*" + react-helmet-async: "*" + react-loadable: "npm:@docusaurus/react-loadable@5.5.2" + peerDependencies: + react: "*" + react-dom: "*" + checksum: 22ce1a6a20acc35cdd2ec57e55f29e65dbe0fb3a46aaa8c033ec78bf04cd3087f0523c816c744ed311095512dd686c83e0a8619cc1a2a937c27cd54527739c38 + languageName: node + linkType: hard + +"@docusaurus/plugin-content-blog@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/plugin-content-blog@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/logger": 2.4.3 + "@docusaurus/mdx-loader": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils": 2.4.3 + "@docusaurus/utils-common": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + cheerio: ^1.0.0-rc.12 + feed: ^4.2.2 + fs-extra: ^10.1.0 + lodash: ^4.17.21 + reading-time: ^1.5.0 + tslib: ^2.4.0 + unist-util-visit: ^2.0.3 + utility-types: ^3.10.0 + webpack: ^5.73.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 9fd41331c609b9488eea363e617e3763a814c75f83eb1b858cef402a0f5b96f67a342e25ff8c333489e550eb4d379eae09a88b986a97c25170fe203662e2f1ae + languageName: node + linkType: hard + +"@docusaurus/plugin-content-docs@npm:2.4.3, @docusaurus/plugin-content-docs@npm:^2.0.0-rc.1": + version: 2.4.3 + resolution: "@docusaurus/plugin-content-docs@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/logger": 2.4.3 + "@docusaurus/mdx-loader": 2.4.3 + "@docusaurus/module-type-aliases": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + "@types/react-router-config": ^5.0.6 + combine-promises: ^1.1.0 + fs-extra: ^10.1.0 + import-fresh: ^3.3.0 + js-yaml: ^4.1.0 + lodash: ^4.17.21 + tslib: ^2.4.0 + utility-types: ^3.10.0 + webpack: ^5.73.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: bc01201f64721131eb84f264e51c7497b8034d2a3d99d762169f5dc456c3d8882acfa01fdbaa8fdc6e2e220479b36e0c9e8e17397bf887884589535bdeaeb4bb + languageName: node + linkType: hard + +"@docusaurus/plugin-content-pages@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/plugin-content-pages@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/mdx-loader": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + fs-extra: ^10.1.0 + tslib: ^2.4.0 + webpack: ^5.73.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 00439c2e1a1f345cd549739db13a3610b6d9f7ffa6cf7507ad6ac1f3c8d24041947acc2a446be7edf1a613cf354a50d1133aa28ddf64a0eff6ed8a31bf1a542f + languageName: node + linkType: hard + +"@docusaurus/plugin-debug@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/plugin-debug@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils": 2.4.3 + fs-extra: ^10.1.0 + react-json-view: ^1.21.3 + tslib: ^2.4.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 88955828b72e463e04501cc6bedf802208e377ae0f4d72735625bcbb47918afc4f2588355c6914064cfdbe4945d3da6473ce76319aa1f66dd975b3b43c4c39b0 + languageName: node + linkType: hard + +"@docusaurus/plugin-google-analytics@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/plugin-google-analytics@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + tslib: ^2.4.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 6e30de6b5c479493614a5552a295f07ffb9c83f3740a68c7d4dbac378b8288da7430f26cdc246d763855c6084ad86a6f87286e6c8b40f4817794bb1a04e109ea + languageName: node + linkType: hard + +"@docusaurus/plugin-google-gtag@npm:2.4.3, @docusaurus/plugin-google-gtag@npm:^2.4.0": + version: 2.4.3 + resolution: "@docusaurus/plugin-google-gtag@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + tslib: ^2.4.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 4aaac4d262b3bb7fc3f16620c5329b90db92bf28361ced54f2945fc0e4669483e2f36b076332e0ee9d11b6233cd2c81ca35c953119bad42171e62571c1692d6a + languageName: node + linkType: hard + +"@docusaurus/plugin-google-tag-manager@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/plugin-google-tag-manager@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + tslib: ^2.4.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: c3af89b4d41fab463d853cbfbe8f43d384f702dd09fd914fffcca01fdf94c282d1b98d762c9142fe21f6471f5dd643679e8d11344c95fdf6657aff0618c3c7a5 + languageName: node + linkType: hard + +"@docusaurus/plugin-sitemap@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/plugin-sitemap@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/logger": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils": 2.4.3 + "@docusaurus/utils-common": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + fs-extra: ^10.1.0 + sitemap: ^7.1.1 + tslib: ^2.4.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: cf96b9f0e32cefa58e37a4bc2f0a112ea657f06faf47b780ec2ba39d5e2daca6486a73f3b376c56ad3bb42f3f0c3f70a783f1ce1964b74e2ba273e6f439e439b + languageName: node + linkType: hard + +"@docusaurus/preset-classic@npm:^2.4.0": + version: 2.4.3 + resolution: "@docusaurus/preset-classic@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/plugin-content-blog": 2.4.3 + "@docusaurus/plugin-content-docs": 2.4.3 + "@docusaurus/plugin-content-pages": 2.4.3 + "@docusaurus/plugin-debug": 2.4.3 + "@docusaurus/plugin-google-analytics": 2.4.3 + "@docusaurus/plugin-google-gtag": 2.4.3 + "@docusaurus/plugin-google-tag-manager": 2.4.3 + "@docusaurus/plugin-sitemap": 2.4.3 + "@docusaurus/theme-classic": 2.4.3 + "@docusaurus/theme-common": 2.4.3 + "@docusaurus/theme-search-algolia": 2.4.3 + "@docusaurus/types": 2.4.3 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: a321badc44696adf4ab2d4a5d6c93f595e8c17988aec9609d325928a1d60f5e0205b23fe849b28ddaed24f7935829e86c402f6b761d6e65db4224270b9dd443c + languageName: node + linkType: hard + +"@docusaurus/react-loadable@npm:5.5.2, react-loadable@npm:@docusaurus/react-loadable@5.5.2": + version: 5.5.2 + resolution: "@docusaurus/react-loadable@npm:5.5.2" + dependencies: + "@types/react": "*" + prop-types: ^15.6.2 + peerDependencies: + react: "*" + checksum: 930fb9e2936412a12461f210acdc154a433283921ca43ac3fc3b84cb6c12eb738b3a3719373022bf68004efeb1a928dbe36c467d7a1f86454ed6241576d936e7 + languageName: node + linkType: hard + +"@docusaurus/theme-classic@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/theme-classic@npm:2.4.3" + dependencies: + "@docusaurus/core": 2.4.3 + "@docusaurus/mdx-loader": 2.4.3 + "@docusaurus/module-type-aliases": 2.4.3 + "@docusaurus/plugin-content-blog": 2.4.3 + "@docusaurus/plugin-content-docs": 2.4.3 + "@docusaurus/plugin-content-pages": 2.4.3 + "@docusaurus/theme-common": 2.4.3 + "@docusaurus/theme-translations": 2.4.3 + "@docusaurus/types": 2.4.3 + "@docusaurus/utils": 2.4.3 + "@docusaurus/utils-common": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + "@mdx-js/react": ^1.6.22 + clsx: ^1.2.1 + copy-text-to-clipboard: ^3.0.1 + infima: 0.2.0-alpha.43 + lodash: ^4.17.21 + nprogress: ^0.2.0 + postcss: ^8.4.14 + prism-react-renderer: ^1.3.5 + prismjs: ^1.28.0 + react-router-dom: ^5.3.3 + rtlcss: ^3.5.0 + tslib: ^2.4.0 + utility-types: ^3.10.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 215b7fa416f40ce68773265a168af47fa770583ebe33ec7b34c7e082dfe7c79252b589a6b26532cb0ab7dd089611a9cd0e20c94df097be320a227b98e3b3fbb8 + languageName: node + linkType: hard + +"@docusaurus/theme-common@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/theme-common@npm:2.4.3" + dependencies: + "@docusaurus/mdx-loader": 2.4.3 + "@docusaurus/module-type-aliases": 2.4.3 + "@docusaurus/plugin-content-blog": 2.4.3 + "@docusaurus/plugin-content-docs": 2.4.3 + "@docusaurus/plugin-content-pages": 2.4.3 + "@docusaurus/utils": 2.4.3 + "@docusaurus/utils-common": 2.4.3 + "@types/history": ^4.7.11 + "@types/react": "*" + "@types/react-router-config": "*" + clsx: ^1.2.1 + parse-numeric-range: ^1.3.0 + prism-react-renderer: ^1.3.5 + tslib: ^2.4.0 + use-sync-external-store: ^1.2.0 + utility-types: ^3.10.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 76817f548705542124d708c804e724674ec9bf996a5cb2a5c9a2919416367567cca4a3fa6055589990c339f6e1fb9d3944e25ed30b79fabe191db00d6ef986ca + languageName: node + linkType: hard + +"@docusaurus/theme-search-algolia@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/theme-search-algolia@npm:2.4.3" + dependencies: + "@docsearch/react": ^3.1.1 + "@docusaurus/core": 2.4.3 + "@docusaurus/logger": 2.4.3 + "@docusaurus/plugin-content-docs": 2.4.3 + "@docusaurus/theme-common": 2.4.3 + "@docusaurus/theme-translations": 2.4.3 + "@docusaurus/utils": 2.4.3 + "@docusaurus/utils-validation": 2.4.3 + algoliasearch: ^4.13.1 + algoliasearch-helper: ^3.10.0 + clsx: ^1.2.1 + eta: ^2.0.0 + fs-extra: ^10.1.0 + lodash: ^4.17.21 + tslib: ^2.4.0 + utility-types: ^3.10.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: 665d244c25bff21dd45c983c9b85f9827d2dd58945b802d645370b5e7092820532faf488c0bc0ce88e8fc0088c7f56eb9abb96589cf3857372c1b61bba6cbed7 + languageName: node + linkType: hard + +"@docusaurus/theme-translations@npm:2.4.3, @docusaurus/theme-translations@npm:^2.0.0-rc.1": + version: 2.4.3 + resolution: "@docusaurus/theme-translations@npm:2.4.3" + dependencies: + fs-extra: ^10.1.0 + tslib: ^2.4.0 + checksum: 8424583a130b0d32b6adf578dc5daeefaad199019c8a6a23fbd67577209be64923cde59d423ea9d41d6e7cfc2318e7fa6a17a665e8ae1c871ce0880525f9b8fd + languageName: node + linkType: hard + +"@docusaurus/types@npm:2.4.3": + version: 2.4.3 + resolution: "@docusaurus/types@npm:2.4.3" + dependencies: + "@types/history": ^4.7.11 + "@types/react": "*" + commander: ^5.1.0 + joi: ^17.6.0 + react-helmet-async: ^1.3.0 + utility-types: ^3.10.0 + webpack: ^5.73.0 + webpack-merge: ^5.8.0 + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + checksum: c123c45630e885b588f808baa06a97f8408a3381906f65cb92ae75732aedfca6ab2cada94f969c08e043b885b95298616440326259b789010e0986cbcd7a960b + languageName: node + linkType: hard + +"@docusaurus/utils-common@npm:2.4.3, @docusaurus/utils-common@npm:^2.0.0-rc.1": + version: 2.4.3 + resolution: "@docusaurus/utils-common@npm:2.4.3" + dependencies: + tslib: ^2.4.0 + peerDependencies: + "@docusaurus/types": "*" + peerDependenciesMeta: + "@docusaurus/types": + optional: true + checksum: 1ae315d8d8ce7a0163a698ffdca55b734d21f336512138c128bc0fa2a8d224edbaad0c8dbd7a3de2e8ef734dc2656c505d09066dee4fc84819d153593abb8984 + languageName: node + linkType: hard + +"@docusaurus/utils-validation@npm:2.4.3, @docusaurus/utils-validation@npm:^2.0.0-rc.1": + version: 2.4.3 + resolution: "@docusaurus/utils-validation@npm:2.4.3" + dependencies: + "@docusaurus/logger": 2.4.3 + "@docusaurus/utils": 2.4.3 + joi: ^17.6.0 + js-yaml: ^4.1.0 + tslib: ^2.4.0 + checksum: d3472b3f7a0a029c2cef1f00bc9db403d5f7e74e2091eccbc45d06f5776a84fd73bd1a18cf3a8a3cc0348ce49f753a1300deac670c2a82c56070cc40ca9df06e + languageName: node + linkType: hard + +"@docusaurus/utils@npm:2.4.3, @docusaurus/utils@npm:^2.0.0-rc.1": + version: 2.4.3 + resolution: "@docusaurus/utils@npm:2.4.3" + dependencies: + "@docusaurus/logger": 2.4.3 + "@svgr/webpack": ^6.2.1 + escape-string-regexp: ^4.0.0 + file-loader: ^6.2.0 + fs-extra: ^10.1.0 + github-slugger: ^1.4.0 + globby: ^11.1.0 + gray-matter: ^4.0.3 + js-yaml: ^4.1.0 + lodash: ^4.17.21 + micromatch: ^4.0.5 + resolve-pathname: ^3.0.0 + shelljs: ^0.8.5 + tslib: ^2.4.0 + url-loader: ^4.1.1 + webpack: ^5.73.0 + peerDependencies: + "@docusaurus/types": "*" + peerDependenciesMeta: + "@docusaurus/types": + optional: true + checksum: dd1aa7688d1a4b2775e13a91d528608ceab33c57a921404d9a989867c31c8ef17fe3892e4f5680dfb4a783da7b9973e2077e907ff4ac172927433e606e8fa9b9 + languageName: node + linkType: hard + +"@easyops-cn/autocomplete.js@npm:^0.38.1": + version: 0.38.1 + resolution: "@easyops-cn/autocomplete.js@npm:0.38.1" + dependencies: + cssesc: ^3.0.0 + immediate: ^3.2.3 + checksum: d88b61f12c383856b8d5cedf176a6d07a21e013dc2c78be029af81e2e026ece2bb988c6ea7f9951a2759c2e6f806ea1d1c9627bf36d9cbe376e897a94ce5da09 + languageName: node + linkType: hard + +"@easyops-cn/docusaurus-search-local@npm:^0.35.0": + version: 0.35.0 + resolution: "@easyops-cn/docusaurus-search-local@npm:0.35.0" + dependencies: + "@docusaurus/plugin-content-docs": ^2.0.0-rc.1 + "@docusaurus/theme-translations": ^2.0.0-rc.1 + "@docusaurus/utils": ^2.0.0-rc.1 + "@docusaurus/utils-common": ^2.0.0-rc.1 + "@docusaurus/utils-validation": ^2.0.0-rc.1 + "@easyops-cn/autocomplete.js": ^0.38.1 + "@node-rs/jieba": ^1.6.0 + cheerio: ^1.0.0-rc.3 + clsx: ^1.1.1 + debug: ^4.2.0 + fs-extra: ^10.0.0 + klaw-sync: ^6.0.0 + lunr: ^2.3.9 + lunr-languages: ^1.4.0 + mark.js: ^8.11.1 + tslib: ^2.4.0 + peerDependencies: + "@docusaurus/theme-common": ^2.0.0-rc.1 + react: ^16.14.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 + checksum: 726b7b5d52f3fd01286e5a97bb2f5d27ae0ace2be7a7742c92b0bf11d56f2f44a16f6b7af556f5676ffa2a3b94c244d17ea9804894553f94ba66b98249e1e10f + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-arm64@npm:0.17.19" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-arm@npm:0.17.19" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/android-x64@npm:0.17.19" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/darwin-arm64@npm:0.17.19" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/darwin-x64@npm:0.17.19" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/freebsd-arm64@npm:0.17.19" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/freebsd-x64@npm:0.17.19" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-arm64@npm:0.17.19" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-arm@npm:0.17.19" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-ia32@npm:0.17.19" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-loong64@npm:0.17.19" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-mips64el@npm:0.17.19" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-ppc64@npm:0.17.19" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-riscv64@npm:0.17.19" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-s390x@npm:0.17.19" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/linux-x64@npm:0.17.19" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/netbsd-x64@npm:0.17.19" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/openbsd-x64@npm:0.17.19" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/sunos-x64@npm:0.17.19" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-arm64@npm:0.17.19" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-ia32@npm:0.17.19" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.17.19": + version: 0.17.19 + resolution: "@esbuild/win32-x64@npm:0.17.19" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": + version: 4.4.0 + resolution: "@eslint-community/eslint-utils@npm:4.4.0" + dependencies: + eslint-visitor-keys: ^3.3.0 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.5.1": + version: 4.9.1 + resolution: "@eslint-community/regexpp@npm:4.9.1" + checksum: 06fb839e9c756f6375cc545c2f2e05a0a64576bd6370e8e3c07983fd29a3d6e164ef4aa48a361f7d27e6713ab79c83053ff6a2ccb78748bc955e344279c4a3b6 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.6.1": + version: 4.8.1 + resolution: "@eslint-community/regexpp@npm:4.8.1" + checksum: 82d62c845ef42b810f268cfdc84d803a2da01735fb52e902fd34bdc09f92464a094fd8e4802839874b000b2f73f67c972859e813ba705233515d3e954f234bf2 + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^2.1.2": + version: 2.1.2 + resolution: "@eslint/eslintrc@npm:2.1.2" + dependencies: + ajv: ^6.12.4 + debug: ^4.3.2 + espree: ^9.6.0 + globals: ^13.19.0 + ignore: ^5.2.0 + import-fresh: ^3.2.1 + js-yaml: ^4.1.0 + minimatch: ^3.1.2 + strip-json-comments: ^3.1.1 + checksum: bc742a1e3b361f06fedb4afb6bf32cbd27171292ef7924f61c62f2aed73048367bcc7ac68f98c06d4245cd3fabc43270f844e3c1699936d4734b3ac5398814a7 + languageName: node + linkType: hard + +"@eslint/js@npm:8.50.0": + version: 8.50.0 + resolution: "@eslint/js@npm:8.50.0" + checksum: 302478f2acaaa7228729ec6a04f56641590185e1d8cd1c836a6db8a6b8009f80a57349341be9fbb9aa1721a7a569d1be3ffc598a33300d22816f11832095386c + languageName: node + linkType: hard + +"@esm-bundle/chai@npm:^4.3.4-fix.0": + version: 4.3.4 + resolution: "@esm-bundle/chai@npm:4.3.4" + dependencies: + "@types/chai": ^4.2.12 + checksum: 6d1237e9b8309b31ca55d12abe03642ab58550fdac24d0acbfeae6ab14182f72cedf646c6e858fd7ef592b4034ddd23ce5882ff22b8ab9b7952327e9f3f8c3f5 + languageName: node + linkType: hard + +"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.7.0": + version: 5.7.0 + resolution: "@ethersproject/abi@npm:5.7.0" + dependencies: + "@ethersproject/address": ^5.7.0 + "@ethersproject/bignumber": ^5.7.0 + "@ethersproject/bytes": ^5.7.0 + "@ethersproject/constants": ^5.7.0 + "@ethersproject/hash": ^5.7.0 + "@ethersproject/keccak256": ^5.7.0 + "@ethersproject/logger": ^5.7.0 + "@ethersproject/properties": ^5.7.0 + "@ethersproject/strings": ^5.7.0 + checksum: bc6962bb6cb854e4d2a4d65b2c49c716477675b131b1363312234bdbb7e19badb7d9ce66f4ca2a70ae2ea84f7123dbc4e300a1bfe5d58864a7eafabc1466627e + languageName: node + linkType: hard + +"@ethersproject/abstract-provider@npm:5.7.0, @ethersproject/abstract-provider@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abstract-provider@npm:5.7.0" dependencies: @@ -747,6 +3015,22 @@ __metadata: languageName: node linkType: hard +"@hapi/hoek@npm:^9.0.0": + version: 9.3.0 + resolution: "@hapi/hoek@npm:9.3.0" + checksum: 4771c7a776242c3c022b168046af4e324d116a9d2e1d60631ee64f474c6e38d1bb07092d898bf95c7bc5d334c5582798a1456321b2e53ca817d4e7c88bc25b43 + languageName: node + linkType: hard + +"@hapi/topo@npm:^5.0.0": + version: 5.1.0 + resolution: "@hapi/topo@npm:5.1.0" + dependencies: + "@hapi/hoek": ^9.0.0 + checksum: 604dfd5dde76d5c334bd03f9001fce69c7ce529883acf92da96f4fe7e51221bf5e5110e964caca287a6a616ba027c071748ab636ff178ad750547fba611d6014 + languageName: node + linkType: hard + "@humanwhocodes/config-array@npm:^0.11.11": version: 0.11.11 resolution: "@humanwhocodes/config-array@npm:0.11.11" @@ -786,6 +3070,40 @@ __metadata: languageName: node linkType: hard +"@jest/schemas@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/schemas@npm:29.6.3" + dependencies: + "@sinclair/typebox": ^0.27.8 + checksum: 910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 + languageName: node + linkType: hard + +"@jest/types@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/types@npm:29.6.3" + dependencies: + "@jest/schemas": ^29.6.3 + "@types/istanbul-lib-coverage": ^2.0.0 + "@types/istanbul-reports": ^3.0.0 + "@types/node": "*" + "@types/yargs": ^17.0.8 + chalk: ^4.0.0 + checksum: a0bcf15dbb0eca6bdd8ce61a3fb055349d40268622a7670a3b2eb3c3dbafe9eb26af59938366d520b86907b9505b0f9b29b85cec11579a9e580694b87cd90fcc + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": + version: 0.3.3 + resolution: "@jridgewell/gen-mapping@npm:0.3.3" + dependencies: + "@jridgewell/set-array": ^1.0.1 + "@jridgewell/sourcemap-codec": ^1.4.10 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 4a74944bd31f22354fc01c3da32e83c19e519e3bbadafa114f6da4522ea77dd0c2842607e923a591d60a76699d819a2fbb6f3552e277efdb9b58b081390b60ab + languageName: node + linkType: hard + "@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.1 resolution: "@jridgewell/resolve-uri@npm:3.1.1" @@ -793,6 +3111,23 @@ __metadata: languageName: node linkType: hard +"@jridgewell/set-array@npm:^1.0.1": + version: 1.1.2 + resolution: "@jridgewell/set-array@npm:1.1.2" + checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e + languageName: node + linkType: hard + +"@jridgewell/source-map@npm:^0.3.3": + version: 0.3.5 + resolution: "@jridgewell/source-map@npm:0.3.5" + dependencies: + "@jridgewell/gen-mapping": ^0.3.0 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 1ad4dec0bdafbade57920a50acec6634f88a0eb735851e0dda906fa9894e7f0549c492678aad1a10f8e144bfe87f238307bf2a914a1bc85b7781d345417e9f6f + languageName: node + linkType: hard + "@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" @@ -810,7 +3145,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12": +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.19 resolution: "@jridgewell/trace-mapping@npm:0.3.19" dependencies: @@ -820,6 +3155,13 @@ __metadata: languageName: node linkType: hard +"@leichtgewicht/ip-codec@npm:^2.0.1": + version: 2.0.4 + resolution: "@leichtgewicht/ip-codec@npm:2.0.4" + checksum: 468de1f04d33de6d300892683d7c8aecbf96d1e2c5fe084f95f816e50a054d45b7c1ebfb141a1447d844b86a948733f6eebd92234da8581c84a1ad4de2946a2d + languageName: node + linkType: hard + "@mdn/browser-compat-data@npm:^4.0.0": version: 4.2.1 resolution: "@mdn/browser-compat-data@npm:4.2.1" @@ -827,6 +3169,49 @@ __metadata: languageName: node linkType: hard +"@mdx-js/mdx@npm:^1.6.22": + version: 1.6.22 + resolution: "@mdx-js/mdx@npm:1.6.22" + dependencies: + "@babel/core": 7.12.9 + "@babel/plugin-syntax-jsx": 7.12.1 + "@babel/plugin-syntax-object-rest-spread": 7.8.3 + "@mdx-js/util": 1.6.22 + babel-plugin-apply-mdx-type-prop: 1.6.22 + babel-plugin-extract-import-names: 1.6.22 + camelcase-css: 2.0.1 + detab: 2.0.4 + hast-util-raw: 6.0.1 + lodash.uniq: 4.5.0 + mdast-util-to-hast: 10.0.1 + remark-footnotes: 2.0.0 + remark-mdx: 1.6.22 + remark-parse: 8.0.3 + remark-squeeze-paragraphs: 4.0.0 + style-to-object: 0.3.0 + unified: 9.2.0 + unist-builder: 2.0.3 + unist-util-visit: 2.0.3 + checksum: 0839b4a3899416326ea6578fe9e470af319da559bc6d3669c60942e456b49a98eebeb3358c623007b4786a2175a450d2c51cd59df64639013c5a3d22366931a6 + languageName: node + linkType: hard + +"@mdx-js/react@npm:^1.6.22": + version: 1.6.22 + resolution: "@mdx-js/react@npm:1.6.22" + peerDependencies: + react: ^16.13.1 || ^17.0.0 + checksum: bc84bd514bc127f898819a0c6f1a6915d9541011bd8aefa1fcc1c9bea8939f31051409e546bdec92babfa5b56092a16d05ef6d318304ac029299df5181dc94c8 + languageName: node + linkType: hard + +"@mdx-js/util@npm:1.6.22": + version: 1.6.22 + resolution: "@mdx-js/util@npm:1.6.22" + checksum: 4b393907e39a1a75214f0314bf72a0adfa5e5adffd050dd5efe9c055b8549481a3cfc9f308c16dfb33311daf3ff63added7d5fd1fe52db614c004f886e0e559a + languageName: node + linkType: hard + "@metamask/eth-sig-util@npm:^4.0.0": version: 4.0.1 resolution: "@metamask/eth-sig-util@npm:4.0.1" @@ -861,6 +3246,145 @@ __metadata: languageName: node linkType: hard +"@node-rs/jieba-android-arm-eabi@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-android-arm-eabi@npm:1.7.2" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@node-rs/jieba-android-arm64@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-android-arm64@npm:1.7.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@node-rs/jieba-darwin-arm64@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-darwin-arm64@npm:1.7.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@node-rs/jieba-darwin-x64@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-darwin-x64@npm:1.7.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@node-rs/jieba-freebsd-x64@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-freebsd-x64@npm:1.7.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@node-rs/jieba-linux-arm-gnueabihf@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-linux-arm-gnueabihf@npm:1.7.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@node-rs/jieba-linux-arm64-gnu@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-linux-arm64-gnu@npm:1.7.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@node-rs/jieba-linux-arm64-musl@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-linux-arm64-musl@npm:1.7.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@node-rs/jieba-linux-x64-gnu@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-linux-x64-gnu@npm:1.7.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@node-rs/jieba-linux-x64-musl@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-linux-x64-musl@npm:1.7.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@node-rs/jieba-win32-arm64-msvc@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-win32-arm64-msvc@npm:1.7.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@node-rs/jieba-win32-ia32-msvc@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-win32-ia32-msvc@npm:1.7.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@node-rs/jieba-win32-x64-msvc@npm:1.7.2": + version: 1.7.2 + resolution: "@node-rs/jieba-win32-x64-msvc@npm:1.7.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@node-rs/jieba@npm:^1.6.0": + version: 1.7.2 + resolution: "@node-rs/jieba@npm:1.7.2" + dependencies: + "@node-rs/jieba-android-arm-eabi": 1.7.2 + "@node-rs/jieba-android-arm64": 1.7.2 + "@node-rs/jieba-darwin-arm64": 1.7.2 + "@node-rs/jieba-darwin-x64": 1.7.2 + "@node-rs/jieba-freebsd-x64": 1.7.2 + "@node-rs/jieba-linux-arm-gnueabihf": 1.7.2 + "@node-rs/jieba-linux-arm64-gnu": 1.7.2 + "@node-rs/jieba-linux-arm64-musl": 1.7.2 + "@node-rs/jieba-linux-x64-gnu": 1.7.2 + "@node-rs/jieba-linux-x64-musl": 1.7.2 + "@node-rs/jieba-win32-arm64-msvc": 1.7.2 + "@node-rs/jieba-win32-ia32-msvc": 1.7.2 + "@node-rs/jieba-win32-x64-msvc": 1.7.2 + dependenciesMeta: + "@node-rs/jieba-android-arm-eabi": + optional: true + "@node-rs/jieba-android-arm64": + optional: true + "@node-rs/jieba-darwin-arm64": + optional: true + "@node-rs/jieba-darwin-x64": + optional: true + "@node-rs/jieba-freebsd-x64": + optional: true + "@node-rs/jieba-linux-arm-gnueabihf": + optional: true + "@node-rs/jieba-linux-arm64-gnu": + optional: true + "@node-rs/jieba-linux-arm64-musl": + optional: true + "@node-rs/jieba-linux-x64-gnu": + optional: true + "@node-rs/jieba-linux-x64-musl": + optional: true + "@node-rs/jieba-win32-arm64-msvc": + optional: true + "@node-rs/jieba-win32-ia32-msvc": + optional: true + "@node-rs/jieba-win32-x64-msvc": + optional: true + checksum: 47108c5e84993ba2ddbc1d922ecb840b74668d61ff8ec83137a300c02e6c97748e64d98f23484dce7d1aee9d00dcf3d1921ccb5375b83ed8474650d0fc1e7e60 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -1337,6 +3861,13 @@ __metadata: languageName: node linkType: hard +"@polka/url@npm:^1.0.0-next.20": + version: 1.0.0-next.23 + resolution: "@polka/url@npm:1.0.0-next.23" + checksum: 4b0330de1ceecd1002c7e7449094d0c41f2ed0e21765f4835ccc7b003f2f024ac557d503b9ffdf0918cf50b80d5b8c99dfc5a91927e7b3c468b09c6bb42a3c41 + languageName: node + linkType: hard + "@puppeteer/browsers@npm:0.5.0": version: 0.5.0 resolution: "@puppeteer/browsers@npm:0.5.0" @@ -1499,6 +4030,219 @@ __metadata: languageName: node linkType: hard +"@sideway/address@npm:^4.1.3": + version: 4.1.4 + resolution: "@sideway/address@npm:4.1.4" + dependencies: + "@hapi/hoek": ^9.0.0 + checksum: b9fca2a93ac2c975ba12e0a6d97853832fb1f4fb02393015e012b47fa916a75ca95102d77214b2a29a2784740df2407951af8c5dde054824c65577fd293c4cdb + languageName: node + linkType: hard + +"@sideway/formula@npm:^3.0.1": + version: 3.0.1 + resolution: "@sideway/formula@npm:3.0.1" + checksum: e4beeebc9dbe2ff4ef0def15cec0165e00d1612e3d7cea0bc9ce5175c3263fc2c818b679bd558957f49400ee7be9d4e5ac90487e1625b4932e15c4aa7919c57a + languageName: node + linkType: hard + +"@sideway/pinpoint@npm:^2.0.0": + version: 2.0.0 + resolution: "@sideway/pinpoint@npm:2.0.0" + checksum: 0f4491e5897fcf5bf02c46f5c359c56a314e90ba243f42f0c100437935daa2488f20482f0f77186bd6bf43345095a95d8143ecf8b1f4d876a7bc0806aba9c3d2 + languageName: node + linkType: hard + +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 + languageName: node + linkType: hard + +"@sindresorhus/is@npm:^0.14.0": + version: 0.14.0 + resolution: "@sindresorhus/is@npm:0.14.0" + checksum: 971e0441dd44ba3909b467219a5e242da0fc584048db5324cfb8048148fa8dcc9d44d71e3948972c4f6121d24e5da402ef191420d1266a95f713bb6d6e59c98a + languageName: node + linkType: hard + +"@slorber/static-site-generator-webpack-plugin@npm:^4.0.7": + version: 4.0.7 + resolution: "@slorber/static-site-generator-webpack-plugin@npm:4.0.7" + dependencies: + eval: ^0.1.8 + p-map: ^4.0.0 + webpack-sources: ^3.2.2 + checksum: a1e1d8b22dd51059524993f3fdd6861db10eb950debc389e5dd650702287fa2004eace03e6bc8f25b977bd7bc01d76a50aa271cbb73c58a8ec558945d728f307 + languageName: node + linkType: hard + +"@svgr/babel-plugin-add-jsx-attribute@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:6.5.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cab83832830a57735329ed68f67c03b57ca21fa037b0134847b0c5c0ef4beca89956d7dacfbf7b2a10fd901e7009e877512086db2ee918b8c69aee7742ae32c0 + languageName: node + linkType: hard + +"@svgr/babel-plugin-remove-jsx-attribute@npm:*": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ff992893c6c4ac802713ba3a97c13be34e62e6d981c813af40daabcd676df68a72a61bd1e692bb1eda3587f1b1d700ea462222ae2153bb0f46886632d4f88d08 + languageName: node + linkType: hard + +"@svgr/babel-plugin-remove-jsx-empty-expression@npm:*": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0fb691b63a21bac00da3aa2dccec50d0d5a5b347ff408d60803b84410d8af168f2656e4ba1ee1f24dab0ae4e4af77901f2928752bb0434c1f6788133ec599ec8 + languageName: node + linkType: hard + +"@svgr/babel-plugin-replace-jsx-attribute-value@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/babel-plugin-replace-jsx-attribute-value@npm:6.5.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b7d2125758e766e1ebd14b92216b800bdc976959bc696dbfa1e28682919147c1df4bb8b1b5fd037d7a83026e27e681fea3b8d3741af8d3cf4c9dfa3d412125df + languageName: node + linkType: hard + +"@svgr/babel-plugin-svg-dynamic-title@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/babel-plugin-svg-dynamic-title@npm:6.5.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0fd42ebf127ae9163ef341e84972daa99bdcb9e6ed3f83aabd95ee173fddc43e40e02fa847fbc0a1058cf5549f72b7960a2c5e22c3e4ac18f7e3ac81277852ae + languageName: node + linkType: hard + +"@svgr/babel-plugin-svg-em-dimensions@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/babel-plugin-svg-em-dimensions@npm:6.5.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c1550ee9f548526fa66fd171e3ffb5696bfc4e4cd108a631d39db492c7410dc10bba4eb5a190e9df824bf806130ccc586ae7d2e43c547e6a4f93bbb29a18f344 + languageName: node + linkType: hard + +"@svgr/babel-plugin-transform-react-native-svg@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/babel-plugin-transform-react-native-svg@npm:6.5.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4c924af22b948b812629e80efb90ad1ec8faae26a232d8ca8a06b46b53e966a2c415a57806a3ff0ea806a622612e546422719b69ec6839717a7755dac19171d9 + languageName: node + linkType: hard + +"@svgr/babel-plugin-transform-svg-component@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/babel-plugin-transform-svg-component@npm:6.5.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e496bb5ee871feb6bcab250b6e067322da7dd5c9c2b530b41e5586fe090f86611339b49d0a909c334d9b24cbca0fa755c949a2526c6ad03c6b5885666874cf5f + languageName: node + linkType: hard + +"@svgr/babel-preset@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/babel-preset@npm:6.5.1" + dependencies: + "@svgr/babel-plugin-add-jsx-attribute": ^6.5.1 + "@svgr/babel-plugin-remove-jsx-attribute": "*" + "@svgr/babel-plugin-remove-jsx-empty-expression": "*" + "@svgr/babel-plugin-replace-jsx-attribute-value": ^6.5.1 + "@svgr/babel-plugin-svg-dynamic-title": ^6.5.1 + "@svgr/babel-plugin-svg-em-dimensions": ^6.5.1 + "@svgr/babel-plugin-transform-react-native-svg": ^6.5.1 + "@svgr/babel-plugin-transform-svg-component": ^6.5.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9f124be39a8e64f909162f925b3a63ddaa5a342a5e24fc0b7f7d9d4d7f7e3b916596c754fb557dc259928399cad5366a27cb231627a0d2dcc4b13ac521cf05af + languageName: node + linkType: hard + +"@svgr/core@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/core@npm:6.5.1" + dependencies: + "@babel/core": ^7.19.6 + "@svgr/babel-preset": ^6.5.1 + "@svgr/plugin-jsx": ^6.5.1 + camelcase: ^6.2.0 + cosmiconfig: ^7.0.1 + checksum: fd6d6d5da5aeb956703310480b626c1fb3e3973ad9fe8025efc1dcf3d895f857b70d100c63cf32cebb20eb83c9607bafa464c9436e18fe6fe4fafdc73ed6b1a5 + languageName: node + linkType: hard + +"@svgr/hast-util-to-babel-ast@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/hast-util-to-babel-ast@npm:6.5.1" + dependencies: + "@babel/types": ^7.20.0 + entities: ^4.4.0 + checksum: 37923cce1b3f4e2039077b0c570b6edbabe37d1cf1a6ee35e71e0fe00f9cffac450eec45e9720b1010418131a999cb0047331ba1b6d1d2c69af1b92ac785aacf + languageName: node + linkType: hard + +"@svgr/plugin-jsx@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/plugin-jsx@npm:6.5.1" + dependencies: + "@babel/core": ^7.19.6 + "@svgr/babel-preset": ^6.5.1 + "@svgr/hast-util-to-babel-ast": ^6.5.1 + svg-parser: ^2.0.4 + peerDependencies: + "@svgr/core": ^6.0.0 + checksum: 42f22847a6bdf930514d7bedd3c5e1fd8d53eb3594779f9db16cb94c762425907c375cd8ec789114e100a4d38068aca6c7ab5efea4c612fba63f0630c44cc859 + languageName: node + linkType: hard + +"@svgr/plugin-svgo@npm:^6.5.1": + version: 6.5.1 + resolution: "@svgr/plugin-svgo@npm:6.5.1" + dependencies: + cosmiconfig: ^7.0.1 + deepmerge: ^4.2.2 + svgo: ^2.8.0 + peerDependencies: + "@svgr/core": "*" + checksum: cd2833530ac0485221adc2146fd992ab20d79f4b12eebcd45fa859721dd779483158e11dfd9a534858fe468416b9412416e25cbe07ac7932c44ed5fa2021c72e + languageName: node + linkType: hard + +"@svgr/webpack@npm:^6.2.1": + version: 6.5.1 + resolution: "@svgr/webpack@npm:6.5.1" + dependencies: + "@babel/core": ^7.19.6 + "@babel/plugin-transform-react-constant-elements": ^7.18.12 + "@babel/preset-env": ^7.19.4 + "@babel/preset-react": ^7.18.6 + "@babel/preset-typescript": ^7.18.6 + "@svgr/core": ^6.5.1 + "@svgr/plugin-jsx": ^6.5.1 + "@svgr/plugin-svgo": ^6.5.1 + checksum: d10582eb4fa82a5b6d314cb49f2c640af4fd3a60f5b76095d2b14e383ef6a43a6f4674b68774a21787dbde69dec0a251cfcfc3f9a96c82754ba5d5c6daf785f0 + languageName: node + linkType: hard + +"@szmarczak/http-timer@npm:^1.1.2": + version: 1.1.2 + resolution: "@szmarczak/http-timer@npm:1.1.2" + dependencies: + defer-to-connect: ^1.0.1 + checksum: 4d9158061c5f397c57b4988cde33a163244e4f02df16364f103971957a32886beb104d6180902cbe8b38cb940e234d9f98a4e486200deca621923f62f50a06fe + languageName: node + linkType: hard + "@tootallnate/once@npm:2": version: 2.0.0 resolution: "@tootallnate/once@npm:2.0.0" @@ -1506,6 +4250,13 @@ __metadata: languageName: node linkType: hard +"@trysound/sax@npm:0.2.0": + version: 0.2.0 + resolution: "@trysound/sax@npm:0.2.0" + checksum: 11226c39b52b391719a2a92e10183e4260d9651f86edced166da1d95f39a0a1eaa470e44d14ac685ccd6d3df7e2002433782872c0feeb260d61e80f21250e65c + languageName: node + linkType: hard + "@tsconfig/node10@npm:^1.0.7": version: 1.0.9 resolution: "@tsconfig/node10@npm:1.0.9" @@ -1578,6 +4329,15 @@ __metadata: languageName: node linkType: hard +"@types/bonjour@npm:^3.5.9": + version: 3.5.11 + resolution: "@types/bonjour@npm:3.5.11" + dependencies: + "@types/node": "*" + checksum: 12fb86a1bb4a610f16ef6d7d68f85e7c31070029f02b6622073794a271e75abcf58230ed205a2ae23c53be2c08b9e507d3b91fa0dc9dfe76c4b1f5e19e9370cb + languageName: node + linkType: hard + "@types/chai-as-promised@npm:^7.1.3": version: 7.1.6 resolution: "@types/chai-as-promised@npm:7.1.6" @@ -1611,6 +4371,16 @@ __metadata: languageName: node linkType: hard +"@types/connect-history-api-fallback@npm:^1.3.5": + version: 1.5.1 + resolution: "@types/connect-history-api-fallback@npm:1.5.1" + dependencies: + "@types/express-serve-static-core": "*" + "@types/node": "*" + checksum: bc5e46663300eba56eaf8ef242156256e2bdadc52bb7d6543f4b37f2945b6a810901c245711f8321fce7d94c7b588b308a86519f3e1f87a80eb87841d808dbdc + languageName: node + linkType: hard + "@types/connect@npm:*": version: 3.4.36 resolution: "@types/connect@npm:3.4.36" @@ -1653,6 +4423,33 @@ __metadata: languageName: node linkType: hard +"@types/eslint-scope@npm:^3.7.3": + version: 3.7.5 + resolution: "@types/eslint-scope@npm:3.7.5" + dependencies: + "@types/eslint": "*" + "@types/estree": "*" + checksum: e91ce335c3791c2cf6084caa0073f90d5b7ae3fcf27785ade8422b7d896159fa14a5a3f1efd31ef03e9ebc1ff04983288280dfe8c9a5579a958539f59df8cc9f + languageName: node + linkType: hard + +"@types/eslint@npm:*": + version: 8.44.4 + resolution: "@types/eslint@npm:8.44.4" + dependencies: + "@types/estree": "*" + "@types/json-schema": "*" + checksum: 15bafdaba800e2995f38d3a2a929d8e9303035315e8d3535523a21cd719b6769a45884afa955f0b845ffa545a4150429b0178e2c44feeedf59ebb285eeae9825 + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:^1.0.0": + version: 1.0.2 + resolution: "@types/estree@npm:1.0.2" + checksum: aeedb1b2fe20cbe06f44b99b562bf9703e360bfcdf5bb3d61d248182ee1dd63500f2474e12f098ffe1f5ac3202b43b3e18ec99902d9328d5374f5512fa077e45 + languageName: node + linkType: hard + "@types/estree@npm:0.0.39": version: 0.0.39 resolution: "@types/estree@npm:0.0.39" @@ -1660,6 +4457,18 @@ __metadata: languageName: node linkType: hard +"@types/express-serve-static-core@npm:*": + version: 4.17.37 + resolution: "@types/express-serve-static-core@npm:4.17.37" + dependencies: + "@types/node": "*" + "@types/qs": "*" + "@types/range-parser": "*" + "@types/send": "*" + checksum: 2dab1380e45eb44e56ecc1be1c42c4b897364d2f2a08e03ca28fbcb1e6866e390217385435813711c046f9acd684424d088855dc32825d5cbecf72c60ecd037f + languageName: node + linkType: hard + "@types/express-serve-static-core@npm:^4.17.33": version: 4.17.36 resolution: "@types/express-serve-static-core@npm:4.17.36" @@ -1684,6 +4493,18 @@ __metadata: languageName: node linkType: hard +"@types/express@npm:^4.17.13": + version: 4.17.19 + resolution: "@types/express@npm:4.17.19" + dependencies: + "@types/body-parser": "*" + "@types/express-serve-static-core": ^4.17.33 + "@types/qs": "*" + "@types/serve-static": "*" + checksum: 3d39d0655eb0825d96fec100985a38737767ddd6da2dbda1e330a3adf36c98a9b7cd8d9539db32876d1fbb47a09343cad7b38c30c8dd7c291271fcb9b85cb21b + languageName: node + linkType: hard + "@types/fs-extra@npm:^9.0.13": version: 9.0.13 resolution: "@types/fs-extra@npm:9.0.13" @@ -1693,6 +4514,29 @@ __metadata: languageName: node linkType: hard +"@types/hast@npm:^2.0.0": + version: 2.3.6 + resolution: "@types/hast@npm:2.3.6" + dependencies: + "@types/unist": ^2 + checksum: c004372f6ab919ec92a2de43e4380707e27b76fe371c7d06ab26547c1e851dfba2a7c740c544218df8c7e0a94443458793c43730ad563a39e3fdc1a48904d7f5 + languageName: node + linkType: hard + +"@types/history@npm:^4.7.11": + version: 4.7.11 + resolution: "@types/history@npm:4.7.11" + checksum: c92e2ba407dcab0581a9afdf98f533aa41b61a71133420a6d92b1ca9839f741ab1f9395b17454ba5b88cb86020b70b22d74a1950ccfbdfd9beeaa5459fdc3464 + languageName: node + linkType: hard + +"@types/html-minifier-terser@npm:^6.0.0": + version: 6.1.0 + resolution: "@types/html-minifier-terser@npm:6.1.0" + checksum: eb843f6a8d662d44fb18ec61041117734c6aae77aa38df1be3b4712e8e50ffaa35f1e1c92fdd0fde14a5675fecf457abcd0d15a01fae7506c91926176967f452 + languageName: node + linkType: hard + "@types/http-assert@npm:*": version: 1.5.3 resolution: "@types/http-assert@npm:1.5.3" @@ -1707,7 +4551,16 @@ __metadata: languageName: node linkType: hard -"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.1, @types/istanbul-lib-coverage@npm:^2.0.3": +"@types/http-proxy@npm:^1.17.8": + version: 1.17.12 + resolution: "@types/http-proxy@npm:1.17.12" + dependencies: + "@types/node": "*" + checksum: 89700c8e3c8f2c59c87c8db8e7a070c97a3b30a4a38223aca6b8b817e6f2ca931f5a500e16ecadc1ebcfed2676cc60e073d8f887e621d84420298728ec6fd000 + languageName: node + linkType: hard + +"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1, @types/istanbul-lib-coverage@npm:^2.0.3": version: 2.0.4 resolution: "@types/istanbul-lib-coverage@npm:2.0.4" checksum: a25d7589ee65c94d31464c16b72a9dc81dfa0bea9d3e105ae03882d616e2a0712a9c101a599ec482d297c3591e16336962878cb3eb1a0a62d5b76d277a890ce7 @@ -1732,13 +4585,20 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:^7.0.12": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": version: 7.0.13 resolution: "@types/json-schema@npm:7.0.13" checksum: 345df21a678fa72fb389f35f33de77833d09d4a142bb2bcb27c18690efa4cf70fc2876e43843cefb3fbdb9fcb12cd3e970a90936df30f53bbee899865ff605ab languageName: node linkType: hard +"@types/katex@npm:^0.11.0": + version: 0.11.1 + resolution: "@types/katex@npm:0.11.1" + checksum: 1e51988b4b386a1b6fa8e22826ab4705bf3e6c9fb03461f2c91d28cb31095232bdeff491069ac9bc74bc4c26110be6a11a41e12ca77a2e4169f3afd8cd349355 + languageName: node + linkType: hard + "@types/keygrip@npm:*": version: 1.0.3 resolution: "@types/keygrip@npm:1.0.3" @@ -1746,6 +4606,15 @@ __metadata: languageName: node linkType: hard +"@types/keyv@npm:^3.1.1": + version: 3.1.4 + resolution: "@types/keyv@npm:3.1.4" + dependencies: + "@types/node": "*" + checksum: e009a2bfb50e90ca9b7c6e8f648f8464067271fd99116f881073fa6fa76dc8d0133181dd65e6614d5fb1220d671d67b0124aef7d97dc02d7e342ab143a47779d + languageName: node + linkType: hard + "@types/koa-compose@npm:*": version: 3.2.6 resolution: "@types/koa-compose@npm:3.2.6" @@ -1778,6 +4647,15 @@ __metadata: languageName: node linkType: hard +"@types/mdast@npm:^3.0.0": + version: 3.0.13 + resolution: "@types/mdast@npm:3.0.13" + dependencies: + "@types/unist": ^2 + checksum: f13fa17a2931ed1492a2f0012a3abd6de3a2d1128145981321909e03fedba80162668f284a4af92aca3732b27e933c5f4772336d96b9ae660bfde696d07abbe6 + languageName: node + linkType: hard + "@types/mime@npm:*": version: 3.0.1 resolution: "@types/mime@npm:3.0.1" @@ -1827,6 +4705,13 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^17.0.5": + version: 17.0.45 + resolution: "@types/node@npm:17.0.45" + checksum: aa04366b9103b7d6cfd6b2ef64182e0eaa7d4462c3f817618486ea0422984c51fc69fd0d436eae6c9e696ddfdbec9ccaa27a917f7c2e8c75c5d57827fe3d95e8 + languageName: node + linkType: hard + "@types/node@npm:^18.7.20": version: 18.17.18 resolution: "@types/node@npm:18.17.18" @@ -1834,6 +4719,20 @@ __metadata: languageName: node linkType: hard +"@types/parse-json@npm:^4.0.0": + version: 4.0.0 + resolution: "@types/parse-json@npm:4.0.0" + checksum: fd6bce2b674b6efc3db4c7c3d336bd70c90838e8439de639b909ce22f3720d21344f52427f1d9e57b265fcb7f6c018699b99e5e0c208a1a4823014269a6bf35b + languageName: node + linkType: hard + +"@types/parse5@npm:^5.0.0": + version: 5.0.3 + resolution: "@types/parse5@npm:5.0.3" + checksum: d6b7495cb1850f9f2e9c5e103ede9f2d30a5320669707b105c403868adc9e4bf8d3a7ff314cc23f67826bbbbbc0e6147346ce9062ab429f099dba7a01f463919 + languageName: node + linkType: hard + "@types/parse5@npm:^6.0.1": version: 6.0.3 resolution: "@types/parse5@npm:6.0.3" @@ -1859,6 +4758,13 @@ __metadata: languageName: node linkType: hard +"@types/prop-types@npm:*": + version: 15.7.8 + resolution: "@types/prop-types@npm:15.7.8" + checksum: 61dfad79da8b1081c450bab83b77935df487ae1cdd4660ec7df6be8e74725c15fa45cf486ce057addc956ca4ae78300b97091e2a25061133d1b9a1440bc896ae + languageName: node + linkType: hard + "@types/ps-tree@npm:^1.1.2": version: 1.1.2 resolution: "@types/ps-tree@npm:1.1.2" @@ -1880,6 +4786,49 @@ __metadata: languageName: node linkType: hard +"@types/react-router-config@npm:*, @types/react-router-config@npm:^5.0.6": + version: 5.0.8 + resolution: "@types/react-router-config@npm:5.0.8" + dependencies: + "@types/history": ^4.7.11 + "@types/react": "*" + "@types/react-router": ^5.1.0 + checksum: afbd96e526fcdd19a3c8604912496a5a7ecfdcd848632a003ef8af69701ca74f14451e4fac93d265b678ca07c82ec4a103126f64c040a4aefa1a8172619be2bd + languageName: node + linkType: hard + +"@types/react-router-dom@npm:*": + version: 5.3.3 + resolution: "@types/react-router-dom@npm:5.3.3" + dependencies: + "@types/history": ^4.7.11 + "@types/react": "*" + "@types/react-router": "*" + checksum: 28c4ea48909803c414bf5a08502acbb8ba414669b4b43bb51297c05fe5addc4df0b8fd00e0a9d1e3535ec4073ef38aaafac2c4a2b95b787167d113bc059beff3 + languageName: node + linkType: hard + +"@types/react-router@npm:*, @types/react-router@npm:^5.1.0": + version: 5.1.20 + resolution: "@types/react-router@npm:5.1.20" + dependencies: + "@types/history": ^4.7.11 + "@types/react": "*" + checksum: 128764143473a5e9457ddc715436b5d49814b1c214dde48939b9bef23f0e77f52ffcdfa97eb8d3cc27e2c229869c0cdd90f637d887b62f2c9f065a87d6425419 + languageName: node + linkType: hard + +"@types/react@npm:*": + version: 18.2.28 + resolution: "@types/react@npm:18.2.28" + dependencies: + "@types/prop-types": "*" + "@types/scheduler": "*" + csstype: ^3.0.2 + checksum: 81381bedeba83278f4c9febb0b83e0bd3f42a25897a50b9cb36ef53651d34b3d50f87ebf11211ea57ea575131f85d31e93e496ce46478a00b0f9bf7b26b5917a + languageName: node + linkType: hard + "@types/readable-stream@npm:^2.3.13": version: 2.3.15 resolution: "@types/readable-stream@npm:2.3.15" @@ -1899,6 +4848,38 @@ __metadata: languageName: node linkType: hard +"@types/responselike@npm:^1.0.0": + version: 1.0.1 + resolution: "@types/responselike@npm:1.0.1" + dependencies: + "@types/node": "*" + checksum: ae8c36c9354aaedfa462dab655aa17613529d545a418acc54ba0214145fc1d0454be2ae107031a1b2c24768f19f2af7e4096a85d1e604010becd0bec2355cb0e + languageName: node + linkType: hard + +"@types/retry@npm:0.12.0": + version: 0.12.0 + resolution: "@types/retry@npm:0.12.0" + checksum: 61a072c7639f6e8126588bf1eb1ce8835f2cb9c2aba795c4491cf6310e013267b0c8488039857c261c387e9728c1b43205099223f160bb6a76b4374f741b5603 + languageName: node + linkType: hard + +"@types/sax@npm:^1.2.1": + version: 1.2.5 + resolution: "@types/sax@npm:1.2.5" + dependencies: + "@types/node": "*" + checksum: a4bf27d7eb1b99030e75dea01fab2fa3959554f5c463b4f577dbbc9d8ed88a5b26b83ac84d045ae5a53e350057f120574db6e1c4e8507c011299dd023e4fa4f2 + languageName: node + linkType: hard + +"@types/scheduler@npm:*": + version: 0.16.4 + resolution: "@types/scheduler@npm:0.16.4" + checksum: a57b0f10da1b021e6bd5eeef8a1917dd3b08a8715bd8029e2ded2096d8f091bb1bb1fef2d66e139588a983c4bfbad29b59e48011141725fa83c76e986e1257d7 + languageName: node + linkType: hard + "@types/secp256k1@npm:^4.0.1": version: 4.0.4 resolution: "@types/secp256k1@npm:4.0.4" @@ -1925,6 +4906,15 @@ __metadata: languageName: node linkType: hard +"@types/serve-index@npm:^1.9.1": + version: 1.9.2 + resolution: "@types/serve-index@npm:1.9.2" + dependencies: + "@types/express": "*" + checksum: 4fd0a8fcdd6e2b2d7704a539b7c1e0d143e9e00be4c3992394fe2ef7e9b67283d74b43db3f92b0e0717d779aa51184168bbae617d30456357cb95ec58aa59ea8 + languageName: node + linkType: hard + "@types/serve-static@npm:*": version: 1.15.2 resolution: "@types/serve-static@npm:1.15.2" @@ -1936,6 +4926,33 @@ __metadata: languageName: node linkType: hard +"@types/serve-static@npm:^1.13.10": + version: 1.15.3 + resolution: "@types/serve-static@npm:1.15.3" + dependencies: + "@types/http-errors": "*" + "@types/mime": "*" + "@types/node": "*" + checksum: afa52252f0ba94cdb5391e80f23e17fd629bdf2a31be8876e2c4490312ed6b0570822dd7de7cea04c9002049e207709563568b7f4ee10bb9f456321db1e83e40 + languageName: node + linkType: hard + +"@types/sockjs@npm:^0.3.33": + version: 0.3.34 + resolution: "@types/sockjs@npm:0.3.34" + dependencies: + "@types/node": "*" + checksum: 1d38b1976a97f5895a6be00cead1b2a59d842f023b6e35450b7eec8a3131c860c447aba3f7ea3c880c066d8277b0c76fae9d080be1aad475811b568ed6079d49 + languageName: node + linkType: hard + +"@types/unist@npm:^2, @types/unist@npm:^2.0.0, @types/unist@npm:^2.0.2, @types/unist@npm:^2.0.3": + version: 2.0.8 + resolution: "@types/unist@npm:2.0.8" + checksum: f4852d10a6752dc70df363917ef74453e5d2fd42824c0f6d09d19d530618e1402193977b1207366af4415aaec81d4e262c64d00345402020c4ca179216e553c7 + languageName: node + linkType: hard + "@types/which@npm:^2.0.1": version: 2.0.2 resolution: "@types/which@npm:2.0.2" @@ -1952,6 +4969,31 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8.5.5": + version: 8.5.7 + resolution: "@types/ws@npm:8.5.7" + dependencies: + "@types/node": "*" + checksum: 4502085c0f7ae6b36d5419c0fc6ce4b9002ee5e997a8708d6ed10b393e97091e1b986e8038ec604945c194f14aac150e74d6596629a2775628d122f552009c35 + languageName: node + linkType: hard + +"@types/yargs-parser@npm:*": + version: 21.0.1 + resolution: "@types/yargs-parser@npm:21.0.1" + checksum: 64e6316c2045e2d460c4fb79572f872f9d2f98fddc6d9d3949c71f0b6ad0ef8a2706cf49db26dfb02a9cb81433abb8f340f015e1d20a9692279abe9477b72c8e + languageName: node + linkType: hard + +"@types/yargs@npm:^17.0.8": + version: 17.0.28 + resolution: "@types/yargs@npm:17.0.28" + dependencies: + "@types/yargs-parser": "*" + checksum: f78c5e5c29903933c0557b4ffcd1d0b8564d66859c8ca4aa51da3714e49109ed7c2644334a1918d033df19028f4cecc91fd2e502651bb8e8451f246c371da847 + languageName: node + linkType: hard + "@types/yauzl@npm:^2.9.1": version: 2.10.0 resolution: "@types/yauzl@npm:2.10.0" @@ -2397,6 +5439,171 @@ __metadata: languageName: node linkType: hard +"@webassemblyjs/ast@npm:1.11.6, @webassemblyjs/ast@npm:^1.11.5": + version: 1.11.6 + resolution: "@webassemblyjs/ast@npm:1.11.6" + dependencies: + "@webassemblyjs/helper-numbers": 1.11.6 + "@webassemblyjs/helper-wasm-bytecode": 1.11.6 + checksum: 38ef1b526ca47c210f30975b06df2faf1a8170b1636ce239fc5738fc231ce28389dd61ecedd1bacfc03cbe95b16d1af848c805652080cb60982836eb4ed2c6cf + languageName: node + linkType: hard + +"@webassemblyjs/floating-point-hex-parser@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.11.6" + checksum: 29b08758841fd8b299c7152eda36b9eb4921e9c584eb4594437b5cd90ed6b920523606eae7316175f89c20628da14326801090167cc7fbffc77af448ac84b7e2 + languageName: node + linkType: hard + +"@webassemblyjs/helper-api-error@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/helper-api-error@npm:1.11.6" + checksum: e8563df85161096343008f9161adb138a6e8f3c2cc338d6a36011aa55eabb32f2fd138ffe63bc278d009ada001cc41d263dadd1c0be01be6c2ed99076103689f + languageName: node + linkType: hard + +"@webassemblyjs/helper-buffer@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/helper-buffer@npm:1.11.6" + checksum: b14d0573bf680d22b2522e8a341ec451fddd645d1f9c6bd9012ccb7e587a2973b86ab7b89fe91e1c79939ba96095f503af04369a3b356c8023c13a5893221644 + languageName: node + linkType: hard + +"@webassemblyjs/helper-numbers@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/helper-numbers@npm:1.11.6" + dependencies: + "@webassemblyjs/floating-point-hex-parser": 1.11.6 + "@webassemblyjs/helper-api-error": 1.11.6 + "@xtuc/long": 4.2.2 + checksum: f4b562fa219f84368528339e0f8d273ad44e047a07641ffcaaec6f93e5b76fd86490a009aa91a294584e1436d74b0a01fa9fde45e333a4c657b58168b04da424 + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-bytecode@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.11.6" + checksum: 3535ef4f1fba38de3475e383b3980f4bbf3de72bbb631c2b6584c7df45be4eccd62c6ff48b5edd3f1bcff275cfd605a37679ec199fc91fd0a7705d7f1e3972dc + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-section@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/helper-wasm-section@npm:1.11.6" + dependencies: + "@webassemblyjs/ast": 1.11.6 + "@webassemblyjs/helper-buffer": 1.11.6 + "@webassemblyjs/helper-wasm-bytecode": 1.11.6 + "@webassemblyjs/wasm-gen": 1.11.6 + checksum: b2cf751bf4552b5b9999d27bbb7692d0aca75260140195cb58ea6374d7b9c2dc69b61e10b211a0e773f66209c3ddd612137ed66097e3684d7816f854997682e9 + languageName: node + linkType: hard + +"@webassemblyjs/ieee754@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/ieee754@npm:1.11.6" + dependencies: + "@xtuc/ieee754": ^1.2.0 + checksum: 13574b8e41f6ca39b700e292d7edf102577db5650fe8add7066a320aa4b7a7c09a5056feccac7a74eb68c10dea9546d4461412af351f13f6b24b5f32379b49de + languageName: node + linkType: hard + +"@webassemblyjs/leb128@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/leb128@npm:1.11.6" + dependencies: + "@xtuc/long": 4.2.2 + checksum: 7ea942dc9777d4b18a5ebfa3a937b30ae9e1d2ce1fee637583ed7f376334dd1d4274f813d2e250056cca803e0952def4b954913f1a3c9068bcd4ab4ee5143bf0 + languageName: node + linkType: hard + +"@webassemblyjs/utf8@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/utf8@npm:1.11.6" + checksum: 807fe5b5ce10c390cfdd93e0fb92abda8aebabb5199980681e7c3743ee3306a75729bcd1e56a3903980e96c885ee53ef901fcbaac8efdfa480f9c0dae1d08713 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-edit@npm:^1.11.5": + version: 1.11.6 + resolution: "@webassemblyjs/wasm-edit@npm:1.11.6" + dependencies: + "@webassemblyjs/ast": 1.11.6 + "@webassemblyjs/helper-buffer": 1.11.6 + "@webassemblyjs/helper-wasm-bytecode": 1.11.6 + "@webassemblyjs/helper-wasm-section": 1.11.6 + "@webassemblyjs/wasm-gen": 1.11.6 + "@webassemblyjs/wasm-opt": 1.11.6 + "@webassemblyjs/wasm-parser": 1.11.6 + "@webassemblyjs/wast-printer": 1.11.6 + checksum: 29ce75870496d6fad864d815ebb072395a8a3a04dc9c3f4e1ffdc63fc5fa58b1f34304a1117296d8240054cfdbc38aca88e71fb51483cf29ffab0a61ef27b481 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-gen@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/wasm-gen@npm:1.11.6" + dependencies: + "@webassemblyjs/ast": 1.11.6 + "@webassemblyjs/helper-wasm-bytecode": 1.11.6 + "@webassemblyjs/ieee754": 1.11.6 + "@webassemblyjs/leb128": 1.11.6 + "@webassemblyjs/utf8": 1.11.6 + checksum: a645a2eecbea24833c3260a249704a7f554ef4a94c6000984728e94bb2bc9140a68dfd6fd21d5e0bbb09f6dfc98e083a45760a83ae0417b41a0196ff6d45a23a + languageName: node + linkType: hard + +"@webassemblyjs/wasm-opt@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/wasm-opt@npm:1.11.6" + dependencies: + "@webassemblyjs/ast": 1.11.6 + "@webassemblyjs/helper-buffer": 1.11.6 + "@webassemblyjs/wasm-gen": 1.11.6 + "@webassemblyjs/wasm-parser": 1.11.6 + checksum: b4557f195487f8e97336ddf79f7bef40d788239169aac707f6eaa2fa5fe243557c2d74e550a8e57f2788e70c7ae4e7d32f7be16101afe183d597b747a3bdd528 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-parser@npm:1.11.6, @webassemblyjs/wasm-parser@npm:^1.11.5": + version: 1.11.6 + resolution: "@webassemblyjs/wasm-parser@npm:1.11.6" + dependencies: + "@webassemblyjs/ast": 1.11.6 + "@webassemblyjs/helper-api-error": 1.11.6 + "@webassemblyjs/helper-wasm-bytecode": 1.11.6 + "@webassemblyjs/ieee754": 1.11.6 + "@webassemblyjs/leb128": 1.11.6 + "@webassemblyjs/utf8": 1.11.6 + checksum: 8200a8d77c15621724a23fdabe58d5571415cda98a7058f542e670ea965dd75499f5e34a48675184947c66f3df23adf55df060312e6d72d57908e3f049620d8a + languageName: node + linkType: hard + +"@webassemblyjs/wast-printer@npm:1.11.6": + version: 1.11.6 + resolution: "@webassemblyjs/wast-printer@npm:1.11.6" + dependencies: + "@webassemblyjs/ast": 1.11.6 + "@xtuc/long": 4.2.2 + checksum: d2fa6a4c427325ec81463e9c809aa6572af6d47f619f3091bf4c4a6fc34f1da3df7caddaac50b8e7a457f8784c62cd58c6311b6cb69b0162ccd8d4c072f79cf8 + languageName: node + linkType: hard + +"@xtuc/ieee754@npm:^1.2.0": + version: 1.2.0 + resolution: "@xtuc/ieee754@npm:1.2.0" + checksum: ac56d4ca6e17790f1b1677f978c0c6808b1900a5b138885d3da21732f62e30e8f0d9120fcf8f6edfff5100ca902b46f8dd7c1e3f903728634523981e80e2885a + languageName: node + linkType: hard + +"@xtuc/long@npm:4.2.2": + version: 4.2.2 + resolution: "@xtuc/long@npm:4.2.2" + checksum: 8ed0d477ce3bc9c6fe2bf6a6a2cc316bb9c4127c5a7827bae947fa8ec34c7092395c5a283cc300c05b5fa01cbbfa1f938f410a7bf75db7c7846fea41949989ec + languageName: node + linkType: hard + "abbrev@npm:^1.0.0": version: 1.1.1 resolution: "abbrev@npm:1.1.1" @@ -2419,7 +5626,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^1.3.5": +"accepts@npm:^1.3.5, accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -2429,6 +5636,15 @@ __metadata: languageName: node linkType: hard +"acorn-import-assertions@npm:^1.9.0": + version: 1.9.0 + resolution: "acorn-import-assertions@npm:1.9.0" + peerDependencies: + acorn: ^8 + checksum: 944fb2659d0845c467066bdcda2e20c05abe3aaf11972116df457ce2627628a81764d800dd55031ba19de513ee0d43bb771bc679cc0eda66dc8b4fade143bc0c + languageName: node + linkType: hard + "acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -2438,14 +5654,14 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.2.0": +"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.2.0": version: 8.2.0 resolution: "acorn-walk@npm:8.2.0" checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 languageName: node linkType: hard -"acorn@npm:^8.4.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": +"acorn@npm:^8.0.4, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": version: 8.10.0 resolution: "acorn@npm:8.10.0" bin: @@ -2454,6 +5670,13 @@ __metadata: languageName: node linkType: hard +"address@npm:^1.0.1, address@npm:^1.1.2": + version: 1.2.2 + resolution: "address@npm:1.2.2" + checksum: ace439960c1e3564d8f523aff23a841904bf33a2a7c2e064f7f60a064194075758b9690e65bd9785692a4ef698a998c57eb74d145881a1cecab8ba658ddb1607 + languageName: node + linkType: hard + "adm-zip@npm:^0.4.16": version: 0.4.16 resolution: "adm-zip@npm:0.4.16" @@ -2484,44 +5707,132 @@ __metadata: languageName: node linkType: hard -"agentkeepalive@npm:^4.2.1": - version: 4.5.0 - resolution: "agentkeepalive@npm:4.5.0" +"agentkeepalive@npm:^4.2.1": + version: 4.5.0 + resolution: "agentkeepalive@npm:4.5.0" + dependencies: + humanize-ms: ^1.2.1 + checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481 + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: ^2.0.0 + indent-string: ^4.0.0 + checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + languageName: node + linkType: hard + +"aggregate-error@npm:^4.0.0": + version: 4.0.1 + resolution: "aggregate-error@npm:4.0.1" + dependencies: + clean-stack: ^4.0.0 + indent-string: ^5.0.0 + checksum: bb3ffdfd13447800fff237c2cba752c59868ee669104bb995dfbbe0b8320e967d679e683dabb640feb32e4882d60258165cde0baafc4cd467cc7d275a13ad6b5 + languageName: node + linkType: hard + +"ajv-formats@npm:^2.1.1": + version: 2.1.1 + resolution: "ajv-formats@npm:2.1.1" + dependencies: + ajv: ^8.0.0 + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 4a287d937f1ebaad4683249a4c40c0fa3beed30d9ddc0adba04859026a622da0d317851316ea64b3680dc60f5c3c708105ddd5d5db8fe595d9d0207fd19f90b7 + languageName: node + linkType: hard + +"ajv-keywords@npm:^3.4.1, ajv-keywords@npm:^3.5.2": + version: 3.5.2 + resolution: "ajv-keywords@npm:3.5.2" + peerDependencies: + ajv: ^6.9.1 + checksum: 7dc5e5931677a680589050f79dcbe1fefbb8fea38a955af03724229139175b433c63c68f7ae5f86cf8f65d55eb7c25f75a046723e2e58296707617ca690feae9 + languageName: node + linkType: hard + +"ajv-keywords@npm:^5.1.0": + version: 5.1.0 + resolution: "ajv-keywords@npm:5.1.0" + dependencies: + fast-deep-equal: ^3.1.3 + peerDependencies: + ajv: ^8.8.2 + checksum: c35193940b853119242c6757787f09ecf89a2c19bcd36d03ed1a615e710d19d450cb448bfda407b939aba54b002368c8bff30529cc50a0536a8e10bcce300421 + languageName: node + linkType: hard + +"ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5": + version: 6.12.6 + resolution: "ajv@npm:6.12.6" + dependencies: + fast-deep-equal: ^3.1.1 + fast-json-stable-stringify: ^2.0.0 + json-schema-traverse: ^0.4.1 + uri-js: ^4.2.2 + checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 + languageName: node + linkType: hard + +"ajv@npm:^8.0.0, ajv@npm:^8.9.0": + version: 8.12.0 + resolution: "ajv@npm:8.12.0" dependencies: - humanize-ms: ^1.2.1 - checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481 + fast-deep-equal: ^3.1.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + uri-js: ^4.2.2 + checksum: 4dc13714e316e67537c8b31bc063f99a1d9d9a497eb4bbd55191ac0dcd5e4985bbb71570352ad6f1e76684fb6d790928f96ba3b2d4fd6e10024be9612fe3f001 languageName: node linkType: hard -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" +"algoliasearch-helper@npm:^3.10.0": + version: 3.14.2 + resolution: "algoliasearch-helper@npm:3.14.2" dependencies: - clean-stack: ^2.0.0 - indent-string: ^4.0.0 - checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + "@algolia/events": ^4.0.1 + peerDependencies: + algoliasearch: ">= 3.1 < 6" + checksum: d66444b25fe8ee64675bb660ff1980870751818cb4a29c57bda6ca410372f2bfa031a455dcd5981941736db89d8294187c5b3bc1ce2a2567c6e43657ccd208b8 languageName: node linkType: hard -"aggregate-error@npm:^4.0.0": - version: 4.0.1 - resolution: "aggregate-error@npm:4.0.1" +"algoliasearch@npm:^4.13.1, algoliasearch@npm:^4.19.1": + version: 4.20.0 + resolution: "algoliasearch@npm:4.20.0" dependencies: - clean-stack: ^4.0.0 - indent-string: ^5.0.0 - checksum: bb3ffdfd13447800fff237c2cba752c59868ee669104bb995dfbbe0b8320e967d679e683dabb640feb32e4882d60258165cde0baafc4cd467cc7d275a13ad6b5 + "@algolia/cache-browser-local-storage": 4.20.0 + "@algolia/cache-common": 4.20.0 + "@algolia/cache-in-memory": 4.20.0 + "@algolia/client-account": 4.20.0 + "@algolia/client-analytics": 4.20.0 + "@algolia/client-common": 4.20.0 + "@algolia/client-personalization": 4.20.0 + "@algolia/client-search": 4.20.0 + "@algolia/logger-common": 4.20.0 + "@algolia/logger-console": 4.20.0 + "@algolia/requester-browser-xhr": 4.20.0 + "@algolia/requester-common": 4.20.0 + "@algolia/requester-node-http": 4.20.0 + "@algolia/transporter": 4.20.0 + checksum: 078954944452f57d2e3b47c6ed4905caf797814324a4d5068a8b6685d434a885977a3e607714c5fb6eb29c7c3e717b3ee9cb01c8b2320e2c7bd73bcd8d42e70f languageName: node linkType: hard -"ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" +"ansi-align@npm:^3.0.0, ansi-align@npm:^3.0.1": + version: 3.0.1 + resolution: "ansi-align@npm:3.0.1" dependencies: - fast-deep-equal: ^3.1.1 - fast-json-stable-stringify: ^2.0.0 - json-schema-traverse: ^0.4.1 - uri-js: ^4.2.2 - checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 + string-width: ^4.1.0 + checksum: 6abfa08f2141d231c257162b15292467081fa49a208593e055c866aa0455b57f3a86b5a678c190c618faa79b4c59e254493099cb700dd9cf2293c6be2c8f5d8d languageName: node linkType: hard @@ -2548,6 +5859,15 @@ __metadata: languageName: node linkType: hard +"ansi-html-community@npm:^0.0.8": + version: 0.0.8 + resolution: "ansi-html-community@npm:0.0.8" + bin: + ansi-html: bin/ansi-html + checksum: 04c568e8348a636963f915e48eaa3e01218322e1169acafdd79c384f22e5558c003f79bbc480c1563865497482817c7eed025f0653ebc17642fededa5cb42089 + languageName: node + linkType: hard + "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -2621,6 +5941,13 @@ __metadata: languageName: node linkType: hard +"arg@npm:^5.0.0": + version: 5.0.2 + resolution: "arg@npm:5.0.2" + checksum: 6c69ada1a9943d332d9e5382393e897c500908d91d5cb735a01120d5f71daf1b339b7b8980cbeaba8fd1afc68e658a739746179e4315a26e8a28951ff9930078 + languageName: node + linkType: hard + "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -2658,6 +5985,20 @@ __metadata: languageName: node linkType: hard +"array-flatten@npm:1.1.1": + version: 1.1.1 + resolution: "array-flatten@npm:1.1.1" + checksum: a9925bf3512d9dce202112965de90c222cd59a4fbfce68a0951d25d965cf44642931f40aac72309c41f12df19afa010ecadceb07cfff9ccc1621e99d89ab5f3b + languageName: node + linkType: hard + +"array-flatten@npm:^2.1.2": + version: 2.1.2 + resolution: "array-flatten@npm:2.1.2" + checksum: e8988aac1fbfcdaae343d08c9a06a6fddd2c6141721eeeea45c3cf523bf4431d29a46602929455ed548c7a3e0769928cdc630405427297e7081bd118fdec9262 + languageName: node + linkType: hard + "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" @@ -2679,6 +6020,13 @@ __metadata: languageName: node linkType: hard +"asap@npm:~2.0.3": + version: 2.0.6 + resolution: "asap@npm:2.0.6" + checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d + languageName: node + linkType: hard + "assertion-error@npm:^1.1.0": version: 1.1.0 resolution: "assertion-error@npm:1.1.0" @@ -2702,6 +6050,38 @@ __metadata: languageName: node linkType: hard +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be + languageName: node + linkType: hard + +"at-least-node@npm:^1.0.0": + version: 1.0.0 + resolution: "at-least-node@npm:1.0.0" + checksum: 463e2f8e43384f1afb54bc68485c436d7622acec08b6fad269b421cb1d29cebb5af751426793d0961ed243146fe4dc983402f6d5a51b720b277818dbf6f2e49e + languageName: node + linkType: hard + +"autoprefixer@npm:^10.4.12, autoprefixer@npm:^10.4.7": + version: 10.4.16 + resolution: "autoprefixer@npm:10.4.16" + dependencies: + browserslist: ^4.21.10 + caniuse-lite: ^1.0.30001538 + fraction.js: ^4.3.6 + normalize-range: ^0.1.2 + picocolors: ^1.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.1.0 + bin: + autoprefixer: bin/autoprefixer + checksum: 45fad7086495048dacb14bb7b00313e70e135b5d8e8751dcc60548889400763705ab16fc2d99ea628b44c3472698fb0e39598f595ba28409c965ab159035afde + languageName: node + linkType: hard + "ava@npm:^5.2.0": version: 5.3.1 resolution: "ava@npm:5.3.1" @@ -2760,6 +6140,114 @@ __metadata: languageName: node linkType: hard +"axios@npm:^0.25.0": + version: 0.25.0 + resolution: "axios@npm:0.25.0" + dependencies: + follow-redirects: ^1.14.7 + checksum: 2a8a3787c05f2a0c9c3878f49782357e2a9f38945b93018fb0c4fd788171c43dceefbb577988628e09fea53952744d1ecebde234b561f1e703aa43e0a598a3ad + languageName: node + linkType: hard + +"axios@npm:^1.4.0": + version: 1.5.1 + resolution: "axios@npm:1.5.1" + dependencies: + follow-redirects: ^1.15.0 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: 4444f06601f4ede154183767863d2b8e472b4a6bfc5253597ed6d21899887e1fd0ee2b3de792ac4f8459fe2e359d2aa07c216e45fd8b9e4e0688a6ebf48a5a8d + languageName: node + linkType: hard + +"babel-loader@npm:^8.2.5": + version: 8.3.0 + resolution: "babel-loader@npm:8.3.0" + dependencies: + find-cache-dir: ^3.3.1 + loader-utils: ^2.0.0 + make-dir: ^3.1.0 + schema-utils: ^2.6.5 + peerDependencies: + "@babel/core": ^7.0.0 + webpack: ">=2" + checksum: d48bcf9e030e598656ad3ff5fb85967db2eaaf38af5b4a4b99d25618a2057f9f100e6b231af2a46c1913206db506115ca7a8cbdf52c9c73d767070dae4352ab5 + languageName: node + linkType: hard + +"babel-plugin-apply-mdx-type-prop@npm:1.6.22": + version: 1.6.22 + resolution: "babel-plugin-apply-mdx-type-prop@npm:1.6.22" + dependencies: + "@babel/helper-plugin-utils": 7.10.4 + "@mdx-js/util": 1.6.22 + peerDependencies: + "@babel/core": ^7.11.6 + checksum: 43e2100164a8f3e46fddd76afcbfb1f02cbebd5612cfe63f3d344a740b0afbdc4d2bf5659cffe9323dd2554c7b86b23ebedae9dadcec353b6594f4292a1a28e2 + languageName: node + linkType: hard + +"babel-plugin-dynamic-import-node@npm:^2.3.3": + version: 2.3.3 + resolution: "babel-plugin-dynamic-import-node@npm:2.3.3" + dependencies: + object.assign: ^4.1.0 + checksum: c9d24415bcc608d0db7d4c8540d8002ac2f94e2573d2eadced137a29d9eab7e25d2cbb4bc6b9db65cf6ee7430f7dd011d19c911a9a778f0533b4a05ce8292c9b + languageName: node + linkType: hard + +"babel-plugin-extract-import-names@npm:1.6.22": + version: 1.6.22 + resolution: "babel-plugin-extract-import-names@npm:1.6.22" + dependencies: + "@babel/helper-plugin-utils": 7.10.4 + checksum: 145ccf09c96d36411d340e78086555f8d4d5924ea39fcb0eca461c066cfa98bc4344982bb35eb85d054ef88f8d4dfc0205ba27370c1d8fcc78191b02908d044d + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs2@npm:^0.4.6": + version: 0.4.6 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.6" + dependencies: + "@babel/compat-data": ^7.22.6 + "@babel/helper-define-polyfill-provider": ^0.4.3 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 08896811df31530be6a9bcdd630cb9fd4b5ae5181039d18db3796efbc54e38d57a42af460845c10a04434e1bc45c0d47743c7e6c860383cc6b141083cde22030 + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs3@npm:^0.8.5": + version: 0.8.5 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.5" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.4.3 + core-js-compat: ^3.32.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 54ff3956c4f88e483d38b27ceec6199b9e73fceac10ebf969469d215e6a62929384e4433f85335c9a6ba809329636e27f9bdae2f54075f833e7a745341c07d84 + languageName: node + linkType: hard + +"babel-plugin-polyfill-regenerator@npm:^0.5.3": + version: 0.5.3 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.3" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.4.3 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 2bb546582cda1870d19e646a7183baeb2cccd56e0ef3e4eaeabd28e120daf17cb87399194a9ccdcf32506bcaa68d23e73440fc8ab990a7a0f8c5a77c12d5d4bc + languageName: node + linkType: hard + +"bail@npm:^1.0.0": + version: 1.0.5 + resolution: "bail@npm:1.0.5" + checksum: 6c334940d7eaa4e656a12fb12407b6555649b6deb6df04270fa806e0da82684ebe4a4e47815b271c794b40f8d6fa286e0c248b14ddbabb324a917fab09b7301a + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -2776,6 +6264,13 @@ __metadata: languageName: node linkType: hard +"base16@npm:^1.0.0": + version: 1.0.0 + resolution: "base16@npm:1.0.0" + checksum: 0cd449a2db0f0f957e4b6b57e33bc43c9e20d4f1dd744065db94b5da35e8e71fa4dc4bc7a901e59a84d5f8b6936e3c520e2471787f667fc155fb0f50d8540f5d + languageName: node + linkType: hard + "base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" @@ -2783,6 +6278,13 @@ __metadata: languageName: node linkType: hard +"batch@npm:0.6.1": + version: 0.6.1 + resolution: "batch@npm:0.6.1" + checksum: 61f9934c7378a51dce61b915586191078ef7f1c3eca707fdd58b96ff2ff56d9e0af2bdab66b1462301a73c73374239e6542d9821c0af787f3209a23365d07e7f + languageName: node + linkType: hard + "bech32@npm:1.1.4": version: 1.1.4 resolution: "bech32@npm:1.1.4" @@ -2797,6 +6299,13 @@ __metadata: languageName: node linkType: hard +"big.js@npm:^5.2.2": + version: 5.2.2 + resolution: "big.js@npm:5.2.2" + checksum: b89b6e8419b097a8fb4ed2399a1931a68c612bce3cfd5ca8c214b2d017531191070f990598de2fc6f3f993d91c0f08aa82697717f6b3b8732c9731866d233c9e + languageName: node + linkType: hard + "bigint-crypto-utils@npm:^3.0.23": version: 3.3.0 resolution: "bigint-crypto-utils@npm:3.3.0" @@ -2850,6 +6359,77 @@ __metadata: languageName: node linkType: hard +"body-parser@npm:1.20.1": + version: 1.20.1 + resolution: "body-parser@npm:1.20.1" + dependencies: + bytes: 3.1.2 + content-type: ~1.0.4 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: ~1.6.18 + unpipe: 1.0.0 + checksum: f1050dbac3bede6a78f0b87947a8d548ce43f91ccc718a50dd774f3c81f2d8b04693e52acf62659fad23101827dd318da1fb1363444ff9a8482b886a3e4a5266 + languageName: node + linkType: hard + +"bonjour-service@npm:^1.0.11": + version: 1.1.1 + resolution: "bonjour-service@npm:1.1.1" + dependencies: + array-flatten: ^2.1.2 + dns-equal: ^1.0.0 + fast-deep-equal: ^3.1.3 + multicast-dns: ^7.2.5 + checksum: 832d0cf78b91368fac8bb11fd7a714e46f4c4fb1bb14d7283bce614a6fb3aae2f3fe209aba5b4fa051811c1cab6921d073a83db8432fb23292f27dd4161fb0f1 + languageName: node + linkType: hard + +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 + languageName: node + linkType: hard + +"boxen@npm:^5.0.0": + version: 5.1.2 + resolution: "boxen@npm:5.1.2" + dependencies: + ansi-align: ^3.0.0 + camelcase: ^6.2.0 + chalk: ^4.1.0 + cli-boxes: ^2.2.1 + string-width: ^4.2.2 + type-fest: ^0.20.2 + widest-line: ^3.1.0 + wrap-ansi: ^7.0.0 + checksum: 82d03e42a72576ff235123f17b7c505372fe05c83f75f61e7d4fa4bcb393897ec95ce766fecb8f26b915f0f7a7227d66e5ec7cef43f5b2bd9d3aeed47ec55877 + languageName: node + linkType: hard + +"boxen@npm:^6.2.1": + version: 6.2.1 + resolution: "boxen@npm:6.2.1" + dependencies: + ansi-align: ^3.0.1 + camelcase: ^6.2.0 + chalk: ^4.1.2 + cli-boxes: ^3.0.0 + string-width: ^5.0.1 + type-fest: ^2.5.0 + widest-line: ^4.0.1 + wrap-ansi: ^8.0.1 + checksum: 2b3226092f1ff8e149c02979098c976552afa15f9e0231c9ed2dfcaaf84604494d16a6f13b647f718439f64d3140a088e822d47c7db00d2266e9ffc8d7321774 + languageName: node + linkType: hard + "bplist-parser@npm:^0.2.0": version: 0.2.0 resolution: "bplist-parser@npm:0.2.0" @@ -2927,6 +6507,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.21.9, browserslist@npm:^4.22.1": + version: 4.22.1 + resolution: "browserslist@npm:4.22.1" + dependencies: + caniuse-lite: ^1.0.30001541 + electron-to-chromium: ^1.4.535 + node-releases: ^2.0.13 + update-browserslist-db: ^1.0.13 + bin: + browserslist: cli.js + checksum: 7e6b10c53f7dd5d83fd2b95b00518889096382539fed6403829d447e05df4744088de46a571071afb447046abc3c66ad06fbc790e70234ec2517452e32ffd862 + languageName: node + linkType: hard + "bs58@npm:^4.0.0": version: 4.0.1 resolution: "bs58@npm:4.0.1" @@ -3004,6 +6598,13 @@ __metadata: languageName: node linkType: hard +"bytes@npm:3.0.0": + version: 3.0.0 + resolution: "bytes@npm:3.0.0" + checksum: a2b386dd8188849a5325f58eef69c3b73c51801c08ffc6963eddc9be244089ba32d19347caf6d145c86f315ae1b1fc7061a32b0c1aa6379e6a719090287ed101 + languageName: node + linkType: hard + "bytes@npm:3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" @@ -3041,7 +6642,22 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.0": +"cacheable-request@npm:^6.0.0": + version: 6.1.0 + resolution: "cacheable-request@npm:6.1.0" + dependencies: + clone-response: ^1.0.2 + get-stream: ^5.1.0 + http-cache-semantics: ^4.0.0 + keyv: ^3.0.0 + lowercase-keys: ^2.0.0 + normalize-url: ^4.1.0 + responselike: ^1.0.2 + checksum: b510b237b18d17e89942e9ee2d2a077cb38db03f12167fd100932dfa8fc963424bfae0bfa1598df4ae16c944a5484e43e03df8f32105b04395ee9495e9e4e9f1 + languageName: node + linkType: hard + +"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": version: 1.0.2 resolution: "call-bind@npm:1.0.2" dependencies: @@ -3065,6 +6681,23 @@ __metadata: languageName: node linkType: hard +"camel-case@npm:^4.1.2": + version: 4.1.2 + resolution: "camel-case@npm:4.1.2" + dependencies: + pascal-case: ^3.1.2 + tslib: ^2.0.3 + checksum: bcbd25cd253b3cbc69be3f535750137dbf2beb70f093bdc575f73f800acc8443d34fd52ab8f0a2413c34f1e8203139ffc88428d8863e4dfe530cfb257a379ad6 + languageName: node + linkType: hard + +"camelcase-css@npm:2.0.1": + version: 2.0.1 + resolution: "camelcase-css@npm:2.0.1" + checksum: 1cec2b3b3dcb5026688a470b00299a8db7d904c4802845c353dbd12d9d248d3346949a814d83bfd988d4d2e5b9904c07efe76fecd195a1d4f05b543e7c0b56b1 + languageName: node + linkType: hard + "camelcase@npm:^6.0.0, camelcase@npm:^6.2.0": version: 6.3.0 resolution: "camelcase@npm:6.3.0" @@ -3072,6 +6705,25 @@ __metadata: languageName: node linkType: hard +"caniuse-api@npm:^3.0.0": + version: 3.0.0 + resolution: "caniuse-api@npm:3.0.0" + dependencies: + browserslist: ^4.0.0 + caniuse-lite: ^1.0.0 + lodash.memoize: ^4.1.2 + lodash.uniq: ^4.5.0 + checksum: db2a229383b20d0529b6b589dde99d7b6cb56ba371366f58cbbfa2929c9f42c01f873e2b6ef641d4eda9f0b4118de77dbb2805814670bdad4234bf08e720b0b4 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001541": + version: 1.0.30001549 + resolution: "caniuse-lite@npm:1.0.30001549" + checksum: 7f2abeedc8cf8b92cc0613855d71b995ce436068c0bcdd798c5af7d297ccf9f52496b00181beda42d82d25079dd4b6e389c67486156d40d8854e5707a25cb054 + languageName: node + linkType: hard + "case@npm:^1.6.3": version: 1.6.3 resolution: "case@npm:1.6.3" @@ -3095,6 +6747,13 @@ __metadata: languageName: node linkType: hard +"ccount@npm:^1.0.0": + version: 1.1.0 + resolution: "ccount@npm:1.1.0" + checksum: b335a79d0aa4308919cf7507babcfa04ac63d389ebed49dbf26990d4607c8a4713cde93cc83e707d84571ddfe1e7615dad248be9bc422ae4c188210f71b08b78 + languageName: node + linkType: hard + "chai-as-promised@npm:^7.1.1": version: 7.1.1 resolution: "chai-as-promised@npm:7.1.1" @@ -3158,6 +6817,27 @@ __metadata: languageName: node linkType: hard +"character-entities-legacy@npm:^1.0.0": + version: 1.1.4 + resolution: "character-entities-legacy@npm:1.1.4" + checksum: fe03a82c154414da3a0c8ab3188e4237ec68006cbcd681cf23c7cfb9502a0e76cd30ab69a2e50857ca10d984d57de3b307680fff5328ccd427f400e559c3a811 + languageName: node + linkType: hard + +"character-entities@npm:^1.0.0": + version: 1.2.4 + resolution: "character-entities@npm:1.2.4" + checksum: e1545716571ead57beac008433c1ff69517cd8ca5b336889321c5b8ff4a99c29b65589a701e9c086cda8a5e346a67295e2684f6c7ea96819fe85cbf49bf8686d + languageName: node + linkType: hard + +"character-reference-invalid@npm:^1.0.0": + version: 1.1.4 + resolution: "character-reference-invalid@npm:1.1.4" + checksum: 20274574c70e05e2f81135f3b93285536bc8ff70f37f0809b0d17791a832838f1e49938382899ed4cb444e5bbd4314ca1415231344ba29f4222ce2ccf24fea0b + languageName: node + linkType: hard + "check-error@npm:^1.0.2": version: 1.0.2 resolution: "check-error@npm:1.0.2" @@ -3165,7 +6845,36 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:3.5.3, chokidar@npm:^3.4.0, chokidar@npm:^3.4.3, chokidar@npm:^3.5.3": +"cheerio-select@npm:^2.1.0": + version: 2.1.0 + resolution: "cheerio-select@npm:2.1.0" + dependencies: + boolbase: ^1.0.0 + css-select: ^5.1.0 + css-what: ^6.1.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + checksum: 843d6d479922f28a6c5342c935aff1347491156814de63c585a6eb73baf7bb4185c1b4383a1195dca0f12e3946d737c7763bcef0b9544c515d905c5c44c5308b + languageName: node + linkType: hard + +"cheerio@npm:^1.0.0-rc.12, cheerio@npm:^1.0.0-rc.3": + version: 1.0.0-rc.12 + resolution: "cheerio@npm:1.0.0-rc.12" + dependencies: + cheerio-select: ^2.1.0 + dom-serializer: ^2.0.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + htmlparser2: ^8.0.1 + parse5: ^7.0.0 + parse5-htmlparser2-tree-adapter: ^7.0.0 + checksum: 5d4c1b7a53cf22d3a2eddc0aff70cf23cbb30d01a4c79013e703a012475c02461aa1fcd99127e8d83a02216386ed6942b2c8103845fd0812300dd199e6e7e054 + languageName: node + linkType: hard + +"chokidar@npm:3.5.3, chokidar@npm:^3.4.0, chokidar@npm:^3.4.2, chokidar@npm:^3.4.3, chokidar@npm:^3.5.3": version: 3.5.3 resolution: "chokidar@npm:3.5.3" dependencies: @@ -3212,6 +6921,13 @@ __metadata: languageName: node linkType: hard +"chrome-trace-event@npm:^1.0.2": + version: 1.0.3 + resolution: "chrome-trace-event@npm:1.0.3" + checksum: cb8b1fc7e881aaef973bd0c4a43cd353c2ad8323fb471a041e64f7c2dd849cde4aad15f8b753331a32dda45c973f032c8a03b8177fc85d60eaa75e91e08bfb97 + languageName: node + linkType: hard + "chromium-bidi@npm:0.4.7": version: 0.4.7 resolution: "chromium-bidi@npm:0.4.7" @@ -3237,6 +6953,13 @@ __metadata: languageName: node linkType: hard +"ci-info@npm:^3.2.0": + version: 3.9.0 + resolution: "ci-info@npm:3.9.0" + checksum: 6b19dc9b2966d1f8c2041a838217299718f15d6c4b63ae36e4674edd2bee48f780e94761286a56aa59eb305a85fbea4ddffb7630ec063e7ec7e7e5ad42549a87 + languageName: node + linkType: hard + "ci-info@npm:^3.8.0": version: 3.8.0 resolution: "ci-info@npm:3.8.0" @@ -3275,6 +6998,15 @@ __metadata: languageName: node linkType: hard +"clean-css@npm:^5.2.2, clean-css@npm:^5.3.0": + version: 5.3.2 + resolution: "clean-css@npm:5.3.2" + dependencies: + source-map: ~0.6.0 + checksum: 8787b281acc9878f309b5f835d410085deedfd4e126472666773040a6a8a72f472a1d24185947d23b87b1c419bf2c5ed429395d5c5ff8279c98b05d8011e9758 + languageName: node + linkType: hard + "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -3298,6 +7030,20 @@ __metadata: languageName: node linkType: hard +"cli-boxes@npm:^2.2.1": + version: 2.2.1 + resolution: "cli-boxes@npm:2.2.1" + checksum: be79f8ec23a558b49e01311b39a1ea01243ecee30539c880cf14bf518a12e223ef40c57ead0cb44f509bffdffc5c129c746cd50d863ab879385370112af4f585 + languageName: node + linkType: hard + +"cli-boxes@npm:^3.0.0": + version: 3.0.0 + resolution: "cli-boxes@npm:3.0.0" + checksum: 637d84419d293a9eac40a1c8c96a2859e7d98b24a1a317788e13c8f441be052fc899480c6acab3acc82eaf1bccda6b7542d7cdcf5c9c3cc39227175dc098d5b2 + languageName: node + linkType: hard + "cli-cursor@npm:^3.1.0": version: 3.1.0 resolution: "cli-cursor@npm:3.1.0" @@ -3307,6 +7053,19 @@ __metadata: languageName: node linkType: hard +"cli-table3@npm:^0.6.2": + version: 0.6.3 + resolution: "cli-table3@npm:0.6.3" + dependencies: + "@colors/colors": 1.5.0 + string-width: ^4.2.0 + dependenciesMeta: + "@colors/colors": + optional: true + checksum: 09897f68467973f827c04e7eaadf13b55f8aec49ecd6647cc276386ea660059322e2dd8020a8b6b84d422dbdd619597046fa89cbbbdc95b2cea149a2df7c096c + languageName: node + linkType: hard + "cli-truncate@npm:^3.1.0": version: 3.1.0 resolution: "cli-truncate@npm:3.1.0" @@ -3339,6 +7098,26 @@ __metadata: languageName: node linkType: hard +"clone-deep@npm:^4.0.1": + version: 4.0.1 + resolution: "clone-deep@npm:4.0.1" + dependencies: + is-plain-object: ^2.0.4 + kind-of: ^6.0.2 + shallow-clone: ^3.0.0 + checksum: 770f912fe4e6f21873c8e8fbb1e99134db3b93da32df271d00589ea4a29dbe83a9808a322c93f3bcaf8584b8b4fa6fc269fc8032efbaa6728e0c9886c74467d2 + languageName: node + linkType: hard + +"clone-response@npm:^1.0.2": + version: 1.0.3 + resolution: "clone-response@npm:1.0.3" + dependencies: + mimic-response: ^1.0.0 + checksum: 4e671cac39b11c60aa8ba0a450657194a5d6504df51bca3fac5b3bd0145c4f8e8464898f87c8406b83232e3bc5cca555f51c1f9c8ac023969ebfbf7f6bdabb2e + languageName: node + linkType: hard + "clone@npm:^2.1.2": version: 2.1.2 resolution: "clone@npm:2.1.2" @@ -3346,6 +7125,13 @@ __metadata: languageName: node linkType: hard +"clsx@npm:^1.1.1, clsx@npm:^1.2.1": + version: 1.2.1 + resolution: "clsx@npm:1.2.1" + checksum: 30befca8019b2eb7dbad38cff6266cf543091dae2825c856a62a8ccf2c3ab9c2907c4d12b288b73101196767f66812365400a227581484a05f968b0307cfaf12 + languageName: node + linkType: hard + "co-body@npm:^6.1.0": version: 6.1.0 resolution: "co-body@npm:6.1.0" @@ -3374,6 +7160,13 @@ __metadata: languageName: node linkType: hard +"collapse-white-space@npm:^1.0.2": + version: 1.0.6 + resolution: "collapse-white-space@npm:1.0.6" + checksum: 9673fb797952c5c888341435596c69388b22cd5560c8cd3f40edb72734a9c820f56a7c9525166bcb7068b5d5805372e6fd0c4b9f2869782ad070cb5d3faf26e7 + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -3415,6 +7208,36 @@ __metadata: languageName: node linkType: hard +"colord@npm:^2.9.1": + version: 2.9.3 + resolution: "colord@npm:2.9.3" + checksum: 95d909bfbcfd8d5605cbb5af56f2d1ce2b323990258fd7c0d2eb0e6d3bb177254d7fb8213758db56bb4ede708964f78c6b992b326615f81a18a6aaf11d64c650 + languageName: node + linkType: hard + +"colorette@npm:^2.0.10": + version: 2.0.20 + resolution: "colorette@npm:2.0.20" + checksum: 0c016fea2b91b733eb9f4bcdb580018f52c0bc0979443dad930e5037a968237ac53d9beb98e218d2e9235834f8eebce7f8e080422d6194e957454255bde71d3d + languageName: node + linkType: hard + +"combine-promises@npm:^1.1.0": + version: 1.2.0 + resolution: "combine-promises@npm:1.2.0" + checksum: ddce91436e24da03d5dc360c59cd55abfc9da5e949a26255aa42761925c574797c43138f0aabfc364e184e738e5e218a94ac6e88ebc459045bcf048ac7fe5f07 + languageName: node + linkType: hard + +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: ~1.0.0 + checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c + languageName: node + linkType: hard + "comlink@npm:^4.4.1": version: 4.4.1 resolution: "comlink@npm:4.4.1" @@ -3422,6 +7245,13 @@ __metadata: languageName: node linkType: hard +"comma-separated-tokens@npm:^1.0.0": + version: 1.0.8 + resolution: "comma-separated-tokens@npm:1.0.8" + checksum: 0adcb07174fa4d08cf0f5c8e3aec40a36b5ff0c2c720e5e23f50fe02e6789d1d00a67036c80e0c1e1539f41d3e7f0101b074039dd833b4e4a59031b659d6ca0d + languageName: node + linkType: hard + "command-exists@npm:^1.2.8": version: 1.2.9 resolution: "command-exists@npm:1.2.9" @@ -3467,6 +7297,34 @@ __metadata: languageName: node linkType: hard +"commander@npm:^2.20.0": + version: 2.20.3 + resolution: "commander@npm:2.20.3" + checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e + languageName: node + linkType: hard + +"commander@npm:^5.1.0": + version: 5.1.0 + resolution: "commander@npm:5.1.0" + checksum: 0b7fec1712fbcc6230fcb161d8d73b4730fa91a21dc089515489402ad78810547683f058e2a9835929c212fead1d6a6ade70db28bbb03edbc2829a9ab7d69447 + languageName: node + linkType: hard + +"commander@npm:^7.2.0": + version: 7.2.0 + resolution: "commander@npm:7.2.0" + checksum: 53501cbeee61d5157546c0bef0fedb6cdfc763a882136284bed9a07225f09a14b82d2a84e7637edfd1a679fb35ed9502fd58ef1d091e6287f60d790147f68ddc + languageName: node + linkType: hard + +"commander@npm:^8.0.0, commander@npm:^8.3.0": + version: 8.3.0 + resolution: "commander@npm:8.3.0" + checksum: 0f82321821fc27b83bd409510bb9deeebcfa799ff0bf5d102128b500b7af22872c0c92cb6a0ebc5a4cf19c6b550fba9cedfa7329d18c6442a625f851377bacf0 + languageName: node + linkType: hard + "common-path-prefix@npm:^3.0.0": version: 3.0.0 resolution: "common-path-prefix@npm:3.0.0" @@ -3474,6 +7332,37 @@ __metadata: languageName: node linkType: hard +"commondir@npm:^1.0.1": + version: 1.0.1 + resolution: "commondir@npm:1.0.1" + checksum: 59715f2fc456a73f68826285718503340b9f0dd89bfffc42749906c5cf3d4277ef11ef1cca0350d0e79204f00f1f6d83851ececc9095dc88512a697ac0b9bdcb + languageName: node + linkType: hard + +"compressible@npm:~2.0.16": + version: 2.0.18 + resolution: "compressible@npm:2.0.18" + dependencies: + mime-db: ">= 1.43.0 < 2" + checksum: 58321a85b375d39230405654721353f709d0c1442129e9a17081771b816302a012471a9b8f4864c7dbe02eef7f2aaac3c614795197092262e94b409c9be108f0 + languageName: node + linkType: hard + +"compression@npm:^1.7.4": + version: 1.7.4 + resolution: "compression@npm:1.7.4" + dependencies: + accepts: ~1.3.5 + bytes: 3.0.0 + compressible: ~2.0.16 + debug: 2.6.9 + on-headers: ~1.0.2 + safe-buffer: 5.1.2 + vary: ~1.1.2 + checksum: 35c0f2eb1f28418978615dc1bc02075b34b1568f7f56c62d60f4214d4b7cc00d0f6d282b5f8a954f59872396bd770b6b15ffd8aa94c67d4bce9b8887b906999b + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -3497,6 +7386,34 @@ __metadata: languageName: node linkType: hard +"configstore@npm:^5.0.1": + version: 5.0.1 + resolution: "configstore@npm:5.0.1" + dependencies: + dot-prop: ^5.2.0 + graceful-fs: ^4.1.2 + make-dir: ^3.0.0 + unique-string: ^2.0.0 + write-file-atomic: ^3.0.0 + xdg-basedir: ^4.0.0 + checksum: 60ef65d493b63f96e14b11ba7ec072fdbf3d40110a94fb7199d1c287761bdea5c5244e76b2596325f30c1b652213aa75de96ea20afd4a5f82065e61ea090988e + languageName: node + linkType: hard + +"connect-history-api-fallback@npm:^2.0.0": + version: 2.0.0 + resolution: "connect-history-api-fallback@npm:2.0.0" + checksum: dc5368690f4a5c413889792f8df70d5941ca9da44523cde3f87af0745faee5ee16afb8195434550f0504726642734f2683d6c07f8b460f828a12c45fbd4c9a68 + languageName: node + linkType: hard + +"consola@npm:^2.15.3": + version: 2.15.3 + resolution: "consola@npm:2.15.3" + checksum: 8ef7a09b703ec67ac5c389a372a33b6dc97eda6c9876443a60d76a3076eea0259e7f67a4e54fd5a52f97df73690822d090cf8b7e102b5761348afef7c6d03e28 + languageName: node + linkType: hard + "console-control-strings@npm:^1.1.0": version: 1.1.0 resolution: "console-control-strings@npm:1.1.0" @@ -3504,7 +7421,14 @@ __metadata: languageName: node linkType: hard -"content-disposition@npm:~0.5.2": +"content-disposition@npm:0.5.2": + version: 0.5.2 + resolution: "content-disposition@npm:0.5.2" + checksum: 298d7da63255a38f7858ee19c7b6aae32b167e911293174b4c1349955e97e78e1d0b0d06c10e229405987275b417cf36ff65cbd4821a98bc9df4e41e9372cde7 + languageName: node + linkType: hard + +"content-disposition@npm:0.5.4, content-disposition@npm:~0.5.2": version: 0.5.4 resolution: "content-disposition@npm:0.5.4" dependencies: @@ -3513,14 +7437,14 @@ __metadata: languageName: node linkType: hard -"content-type@npm:^1.0.4": +"content-type@npm:^1.0.4, content-type@npm:~1.0.4": version: 1.0.5 resolution: "content-type@npm:1.0.5" checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 languageName: node linkType: hard -"convert-source-map@npm:^1.6.0": +"convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 @@ -3541,6 +7465,20 @@ __metadata: languageName: node linkType: hard +"cookie-signature@npm:1.0.6": + version: 1.0.6 + resolution: "cookie-signature@npm:1.0.6" + checksum: f4e1b0a98a27a0e6e66fd7ea4e4e9d8e038f624058371bf4499cfcd8f3980be9a121486995202ba3fca74fbed93a407d6d54d43a43f96fd28d0bd7a06761591a + languageName: node + linkType: hard + +"cookie@npm:0.5.0": + version: 0.5.0 + resolution: "cookie@npm:0.5.0" + checksum: 1f4bd2ca5765f8c9689a7e8954183f5332139eb72b6ff783d8947032ec1fdf43109852c178e21a953a30c0dd42257828185be01b49d1eb1a67fd054ca588a180 + languageName: node + linkType: hard + "cookie@npm:^0.4.1": version: 0.4.2 resolution: "cookie@npm:0.4.2" @@ -3558,6 +7496,102 @@ __metadata: languageName: node linkType: hard +"copy-text-to-clipboard@npm:^3.0.1": + version: 3.2.0 + resolution: "copy-text-to-clipboard@npm:3.2.0" + checksum: df7115c197a166d51f59e4e20ab2a68a855ae8746d25ff149b5465c694d9a405c7e6684b73a9f87ba8d653070164e229c15dfdb9fd77c30be1ff0da569661060 + languageName: node + linkType: hard + +"copy-webpack-plugin@npm:^11.0.0": + version: 11.0.0 + resolution: "copy-webpack-plugin@npm:11.0.0" + dependencies: + fast-glob: ^3.2.11 + glob-parent: ^6.0.1 + globby: ^13.1.1 + normalize-path: ^3.0.0 + schema-utils: ^4.0.0 + serialize-javascript: ^6.0.0 + peerDependencies: + webpack: ^5.1.0 + checksum: df4f8743f003a29ee7dd3d9b1789998a3a99051c92afb2ba2203d3dacfa696f4e757b275560fafb8f206e520a0aa78af34b990324a0e36c2326cefdeef3ca82e + languageName: node + linkType: hard + +"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.32.2": + version: 3.33.0 + resolution: "core-js-compat@npm:3.33.0" + dependencies: + browserslist: ^4.22.1 + checksum: 83ae54008c09b8e0ae3c59457039866c342c7e28b0d30eebb638a5b51c01432e63fe97695c90645cbc6a8b073a4f9a8b0e75f0818bbf8b4b054e01f4c17d3181 + languageName: node + linkType: hard + +"core-js-pure@npm:^3.30.2": + version: 3.33.0 + resolution: "core-js-pure@npm:3.33.0" + checksum: d47084a4de9a0cef9779eccd3ac9f435cf9fd7aa71794150cd4c6b305036bcc392d94766d4a7b6456bdd08faba7752d55c2ec40185bda161c3563081c9fa1e17 + languageName: node + linkType: hard + +"core-js@npm:^3.23.3": + version: 3.33.0 + resolution: "core-js@npm:3.33.0" + checksum: dd62217935ac281faf6f833bb306fb891162919fcf9c1f0c975b1b91e82ac09a940f5deb5950bbb582739ceef716e8bd7e4f9eab8328932fb029d3bc2ecb2881 + languageName: node + linkType: hard + +"core-util-is@npm:~1.0.0": + version: 1.0.3 + resolution: "core-util-is@npm:1.0.3" + checksum: 9de8597363a8e9b9952491ebe18167e3b36e7707569eed0ebf14f8bba773611376466ae34575bca8cfe3c767890c859c74056084738f09d4e4a6f902b2ad7d99 + languageName: node + linkType: hard + +"cosmiconfig@npm:^6.0.0": + version: 6.0.0 + resolution: "cosmiconfig@npm:6.0.0" + dependencies: + "@types/parse-json": ^4.0.0 + import-fresh: ^3.1.0 + parse-json: ^5.0.0 + path-type: ^4.0.0 + yaml: ^1.7.2 + checksum: 8eed7c854b91643ecb820767d0deb038b50780ecc3d53b0b19e03ed8aabed4ae77271198d1ae3d49c3b110867edf679f5faad924820a8d1774144a87cb6f98fc + languageName: node + linkType: hard + +"cosmiconfig@npm:^7.0.1": + version: 7.1.0 + resolution: "cosmiconfig@npm:7.1.0" + dependencies: + "@types/parse-json": ^4.0.0 + import-fresh: ^3.2.1 + parse-json: ^5.0.0 + path-type: ^4.0.0 + yaml: ^1.10.0 + checksum: c53bf7befc1591b2651a22414a5e786cd5f2eeaa87f3678a3d49d6069835a9d8d1aef223728e98aa8fec9a95bf831120d245096db12abe019fecb51f5696c96f + languageName: node + linkType: hard + +"cosmiconfig@npm:^8.2.0": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: ^3.3.0 + js-yaml: ^4.1.0 + parse-json: ^5.2.0 + path-type: ^4.0.0 + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: dc339ebea427898c9e03bf01b56ba7afbac07fc7d2a2d5a15d6e9c14de98275a9565da949375aee1809591c152c0a3877bb86dbeaf74d5bd5aaa79955ad9e7a0 + languageName: node + linkType: hard + "crc-32@npm:^1.2.0": version: 1.2.2 resolution: "crc-32@npm:1.2.2" @@ -3610,6 +7644,15 @@ __metadata: languageName: node linkType: hard +"cross-fetch@npm:^3.1.5": + version: 3.1.8 + resolution: "cross-fetch@npm:3.1.8" + dependencies: + node-fetch: ^2.6.12 + checksum: 78f993fa099eaaa041122ab037fe9503ecbbcb9daef234d1d2e0b9230a983f64d645d088c464e21a247b825a08dc444a6e7064adfa93536d3a9454b4745b3632 + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -3621,6 +7664,214 @@ __metadata: languageName: node linkType: hard +"crypto-random-string@npm:^2.0.0": + version: 2.0.0 + resolution: "crypto-random-string@npm:2.0.0" + checksum: 0283879f55e7c16fdceacc181f87a0a65c53bc16ffe1d58b9d19a6277adcd71900d02bb2c4843dd55e78c51e30e89b0fec618a7f170ebcc95b33182c28f05fd6 + languageName: node + linkType: hard + +"css-declaration-sorter@npm:^6.3.1": + version: 6.4.1 + resolution: "css-declaration-sorter@npm:6.4.1" + peerDependencies: + postcss: ^8.0.9 + checksum: cbdc9e0d481011b1a28fd5b60d4eb55fe204391d31a0b1b490b2cecf4baa85810f9b8c48adab4df644f4718104ed3ed72c64a9745e3216173767bf4aeca7f9b8 + languageName: node + linkType: hard + +"css-loader@npm:^6.7.1": + version: 6.8.1 + resolution: "css-loader@npm:6.8.1" + dependencies: + icss-utils: ^5.1.0 + postcss: ^8.4.21 + postcss-modules-extract-imports: ^3.0.0 + postcss-modules-local-by-default: ^4.0.3 + postcss-modules-scope: ^3.0.0 + postcss-modules-values: ^4.0.0 + postcss-value-parser: ^4.2.0 + semver: ^7.3.8 + peerDependencies: + webpack: ^5.0.0 + checksum: 7c1784247bdbe76dc5c55fb1ac84f1d4177a74c47259942c9cfdb7a8e6baef11967a0bc85ac285f26bd26d5059decb848af8154a03fdb4f4894f41212f45eef3 + languageName: node + linkType: hard + +"css-minimizer-webpack-plugin@npm:^4.0.0": + version: 4.2.2 + resolution: "css-minimizer-webpack-plugin@npm:4.2.2" + dependencies: + cssnano: ^5.1.8 + jest-worker: ^29.1.2 + postcss: ^8.4.17 + schema-utils: ^4.0.0 + serialize-javascript: ^6.0.0 + source-map: ^0.6.1 + peerDependencies: + webpack: ^5.0.0 + peerDependenciesMeta: + "@parcel/css": + optional: true + "@swc/css": + optional: true + clean-css: + optional: true + csso: + optional: true + esbuild: + optional: true + lightningcss: + optional: true + checksum: 5417e76a445f35832aa96807c835b8e92834a6cd285b1b788dfe3ca0fa90fec7eb2dd6efa9d3649f9d8244b99b7da2d065951603b94918e8f6a366a5049cacdd + languageName: node + linkType: hard + +"css-select@npm:^4.1.3": + version: 4.3.0 + resolution: "css-select@npm:4.3.0" + dependencies: + boolbase: ^1.0.0 + css-what: ^6.0.1 + domhandler: ^4.3.1 + domutils: ^2.8.0 + nth-check: ^2.0.1 + checksum: d6202736839194dd7f910320032e7cfc40372f025e4bf21ca5bf6eb0a33264f322f50ba9c0adc35dadd342d3d6fae5ca244779a4873afbfa76561e343f2058e0 + languageName: node + linkType: hard + +"css-select@npm:^5.1.0": + version: 5.1.0 + resolution: "css-select@npm:5.1.0" + dependencies: + boolbase: ^1.0.0 + css-what: ^6.1.0 + domhandler: ^5.0.2 + domutils: ^3.0.1 + nth-check: ^2.0.1 + checksum: 2772c049b188d3b8a8159907192e926e11824aea525b8282981f72ba3f349cf9ecd523fdf7734875ee2cb772246c22117fc062da105b6d59afe8dcd5c99c9bda + languageName: node + linkType: hard + +"css-tree@npm:^1.1.2, css-tree@npm:^1.1.3": + version: 1.1.3 + resolution: "css-tree@npm:1.1.3" + dependencies: + mdn-data: 2.0.14 + source-map: ^0.6.1 + checksum: 79f9b81803991b6977b7fcb1588799270438274d89066ce08f117f5cdb5e20019b446d766c61506dd772c839df84caa16042d6076f20c97187f5abe3b50e7d1f + languageName: node + linkType: hard + +"css-what@npm:^6.0.1, css-what@npm:^6.1.0": + version: 6.1.0 + resolution: "css-what@npm:6.1.0" + checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe + languageName: node + linkType: hard + +"cssesc@npm:^3.0.0": + version: 3.0.0 + resolution: "cssesc@npm:3.0.0" + bin: + cssesc: bin/cssesc + checksum: f8c4ababffbc5e2ddf2fa9957dda1ee4af6048e22aeda1869d0d00843223c1b13ad3f5d88b51caa46c994225eacb636b764eb807a8883e2fb6f99b4f4e8c48b2 + languageName: node + linkType: hard + +"cssnano-preset-advanced@npm:^5.3.8": + version: 5.3.10 + resolution: "cssnano-preset-advanced@npm:5.3.10" + dependencies: + autoprefixer: ^10.4.12 + cssnano-preset-default: ^5.2.14 + postcss-discard-unused: ^5.1.0 + postcss-merge-idents: ^5.1.1 + postcss-reduce-idents: ^5.2.0 + postcss-zindex: ^5.1.0 + peerDependencies: + postcss: ^8.2.15 + checksum: d21cb382aea2f35c9eaa50686280bbd5158260edf73020731364b03bae0d887292da51ed0b20b369f51d2573ee8c02c695f604647b839a9ca746be8a44c3bb5b + languageName: node + linkType: hard + +"cssnano-preset-default@npm:^5.2.14": + version: 5.2.14 + resolution: "cssnano-preset-default@npm:5.2.14" + dependencies: + css-declaration-sorter: ^6.3.1 + cssnano-utils: ^3.1.0 + postcss-calc: ^8.2.3 + postcss-colormin: ^5.3.1 + postcss-convert-values: ^5.1.3 + postcss-discard-comments: ^5.1.2 + postcss-discard-duplicates: ^5.1.0 + postcss-discard-empty: ^5.1.1 + postcss-discard-overridden: ^5.1.0 + postcss-merge-longhand: ^5.1.7 + postcss-merge-rules: ^5.1.4 + postcss-minify-font-values: ^5.1.0 + postcss-minify-gradients: ^5.1.1 + postcss-minify-params: ^5.1.4 + postcss-minify-selectors: ^5.2.1 + postcss-normalize-charset: ^5.1.0 + postcss-normalize-display-values: ^5.1.0 + postcss-normalize-positions: ^5.1.1 + postcss-normalize-repeat-style: ^5.1.1 + postcss-normalize-string: ^5.1.0 + postcss-normalize-timing-functions: ^5.1.0 + postcss-normalize-unicode: ^5.1.1 + postcss-normalize-url: ^5.1.0 + postcss-normalize-whitespace: ^5.1.1 + postcss-ordered-values: ^5.1.3 + postcss-reduce-initial: ^5.1.2 + postcss-reduce-transforms: ^5.1.0 + postcss-svgo: ^5.1.0 + postcss-unique-selectors: ^5.1.1 + peerDependencies: + postcss: ^8.2.15 + checksum: d3bbbe3d50c6174afb28d0bdb65b511fdab33952ec84810aef58b87189f3891c34aaa8b6a6101acd5314f8acded839b43513e39a75f91a698ddc985a1b1d9e95 + languageName: node + linkType: hard + +"cssnano-utils@npm:^3.1.0": + version: 3.1.0 + resolution: "cssnano-utils@npm:3.1.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 975c84ce9174cf23bb1da1e9faed8421954607e9ea76440cd3bb0c1bea7e17e490d800fca5ae2812d1d9e9d5524eef23ede0a3f52497d7ccc628e5d7321536f2 + languageName: node + linkType: hard + +"cssnano@npm:^5.1.12, cssnano@npm:^5.1.8": + version: 5.1.15 + resolution: "cssnano@npm:5.1.15" + dependencies: + cssnano-preset-default: ^5.2.14 + lilconfig: ^2.0.3 + yaml: ^1.10.2 + peerDependencies: + postcss: ^8.2.15 + checksum: ca9e1922178617c66c2f1548824b2c7af2ecf69cc3a187fc96bf8d29251c2e84d9e4966c69cf64a2a6a057a37dff7d6d057bc8a2a0957e6ea382e452ae9d0bbb + languageName: node + linkType: hard + +"csso@npm:^4.2.0": + version: 4.2.0 + resolution: "csso@npm:4.2.0" + dependencies: + css-tree: ^1.1.2 + checksum: 380ba9663da3bcea58dee358a0d8c4468bb6539be3c439dc266ac41c047217f52fd698fb7e4b6b6ccdfb8cf53ef4ceed8cc8ceccb8dfca2aa628319826b5b998 + languageName: node + linkType: hard + +"csstype@npm:^3.0.2": + version: 3.1.2 + resolution: "csstype@npm:3.1.2" + checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5 + languageName: node + linkType: hard + "currently-unhandled@npm:^0.4.1": version: 0.4.1 resolution: "currently-unhandled@npm:0.4.1" @@ -3653,7 +7904,16 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": +"debug@npm:2.6.9, debug@npm:^2.6.0, debug@npm:^2.6.9": + version: 2.6.9 + resolution: "debug@npm:2.6.9" + dependencies: + ms: 2.0.0 + checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.2.0, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -3665,15 +7925,6 @@ __metadata: languageName: node linkType: hard -"debug@npm:^2.6.9": - version: 2.6.9 - resolution: "debug@npm:2.6.9" - dependencies: - ms: 2.0.0 - checksum: d2f51589ca66df60bf36e1fa6e4386b318c3f1e06772280eea5b1ae9fd3d05e9c2b7fd8a7d862457d00853c75b00451aa2d7459b924629ee385287a650f58fe6 - languageName: node - linkType: hard - "debug@npm:^3.1.0, debug@npm:^3.2.7": version: 3.2.7 resolution: "debug@npm:3.2.7" @@ -3690,6 +7941,15 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^3.3.0": + version: 3.3.0 + resolution: "decompress-response@npm:3.3.0" + dependencies: + mimic-response: ^1.0.0 + checksum: 952552ac3bd7de2fc18015086b09468645c9638d98a551305e485230ada278c039c91116e946d07894b39ee53c0f0d5b6473f25a224029344354513b412d7380 + languageName: node + linkType: hard + "deep-eql@npm:^4.0.1, deep-eql@npm:^4.1.2": version: 4.1.3 resolution: "deep-eql@npm:4.1.3" @@ -3706,6 +7966,13 @@ __metadata: languageName: node linkType: hard +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 7be7e5a8d468d6b10e6a67c3de828f55001b6eb515d014f7aeb9066ce36bd5717161eb47d6a0f7bed8a9083935b465bc163ee2581c8b128d29bf61092fdf57a7 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -3742,6 +8009,33 @@ __metadata: languageName: node linkType: hard +"default-gateway@npm:^6.0.3": + version: 6.0.3 + resolution: "default-gateway@npm:6.0.3" + dependencies: + execa: ^5.0.0 + checksum: 126f8273ecac8ee9ff91ea778e8784f6cd732d77c3157e8c5bdd6ed03651b5291f71446d05bc02d04073b1e67583604db5394ea3cf992ede0088c70ea15b7378 + languageName: node + linkType: hard + +"defer-to-connect@npm:^1.0.1": + version: 1.1.3 + resolution: "defer-to-connect@npm:1.1.3" + checksum: 9491b301dcfa04956f989481ba7a43c2231044206269eb4ab64a52d6639ee15b1252262a789eb4239fb46ab63e44d4e408641bae8e0793d640aee55398cb3930 + languageName: node + linkType: hard + +"define-data-property@npm:^1.0.1": + version: 1.1.1 + resolution: "define-data-property@npm:1.1.1" + dependencies: + get-intrinsic: ^1.2.1 + gopd: ^1.0.1 + has-property-descriptors: ^1.0.0 + checksum: a29855ad3f0630ea82e3c5012c812efa6ca3078d5c2aa8df06b5f597c1cde6f7254692df41945851d903e05a1668607b6d34e778f402b9ff9ffb38111f1a3f0d + languageName: node + linkType: hard + "define-lazy-prop@npm:^2.0.0": version: 2.0.0 resolution: "define-lazy-prop@npm:2.0.0" @@ -3749,10 +8043,44 @@ __metadata: languageName: node linkType: hard -"define-lazy-prop@npm:^3.0.0": - version: 3.0.0 - resolution: "define-lazy-prop@npm:3.0.0" - checksum: 54884f94caac0791bf6395a3ec530ce901cf71c47b0196b8754f3fd17edb6c0e80149c1214429d851873bb0d689dbe08dcedbb2306dc45c8534a5934723851b6 +"define-lazy-prop@npm:^3.0.0": + version: 3.0.0 + resolution: "define-lazy-prop@npm:3.0.0" + checksum: 54884f94caac0791bf6395a3ec530ce901cf71c47b0196b8754f3fd17edb6c0e80149c1214429d851873bb0d689dbe08dcedbb2306dc45c8534a5934723851b6 + languageName: node + linkType: hard + +"define-properties@npm:^1.1.4": + version: 1.2.1 + resolution: "define-properties@npm:1.2.1" + dependencies: + define-data-property: ^1.0.1 + has-property-descriptors: ^1.0.0 + object-keys: ^1.1.1 + checksum: b4ccd00597dd46cb2d4a379398f5b19fca84a16f3374e2249201992f36b30f6835949a9429669ee6b41b6e837205a163eadd745e472069e70dfc10f03e5fcc12 + languageName: node + linkType: hard + +"del@npm:^6.1.1": + version: 6.1.1 + resolution: "del@npm:6.1.1" + dependencies: + globby: ^11.0.1 + graceful-fs: ^4.2.4 + is-glob: ^4.0.1 + is-path-cwd: ^2.2.0 + is-path-inside: ^3.0.2 + p-map: ^4.0.0 + rimraf: ^3.0.2 + slash: ^3.0.0 + checksum: 563288b73b8b19a7261c47fd21a330eeab6e2acd7c6208c49790dfd369127120dd7836cdf0c1eca216b77c94782a81507eac6b4734252d3bef2795cb366996b6 + languageName: node + linkType: hard + +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 languageName: node linkType: hard @@ -3791,13 +8119,55 @@ __metadata: languageName: node linkType: hard -"destroy@npm:^1.0.4": +"destroy@npm:1.2.0, destroy@npm:^1.0.4": version: 1.2.0 resolution: "destroy@npm:1.2.0" checksum: 0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 languageName: node linkType: hard +"detab@npm:2.0.4": + version: 2.0.4 + resolution: "detab@npm:2.0.4" + dependencies: + repeat-string: ^1.5.4 + checksum: 34b077521ecd4c6357d32ff7923be644d34aa6f6b7d717d40ec4a9168243eefaea2b512a75a460a6f70c31b0bbc31ff90f820a891803b4ddaf99e9d04d0d389d + languageName: node + linkType: hard + +"detect-node@npm:^2.0.4": + version: 2.1.0 + resolution: "detect-node@npm:2.1.0" + checksum: 832184ec458353e41533ac9c622f16c19f7c02d8b10c303dfd3a756f56be93e903616c0bb2d4226183c9351c15fc0b3dba41a17a2308262afabcfa3776e6ae6e + languageName: node + linkType: hard + +"detect-port-alt@npm:^1.1.6": + version: 1.1.6 + resolution: "detect-port-alt@npm:1.1.6" + dependencies: + address: ^1.0.1 + debug: ^2.6.0 + bin: + detect: ./bin/detect-port + detect-port: ./bin/detect-port + checksum: 9dc37b1fa4a9dd6d4889e1045849b8d841232b598d1ca888bf712f4035b07a17cf6d537465a0d7323250048d3a5a0540e3b7cf89457efc222f96f77e2c40d16a + languageName: node + linkType: hard + +"detect-port@npm:^1.3.0": + version: 1.5.1 + resolution: "detect-port@npm:1.5.1" + dependencies: + address: ^1.0.1 + debug: 4 + bin: + detect: bin/detect-port.js + detect-port: bin/detect-port.js + checksum: b48da9340481742547263d5d985e65d078592557863402ecf538511735e83575867e94f91fe74405ea19b61351feb99efccae7e55de9a151d5654e3417cea05b + languageName: node + linkType: hard + "devtools-protocol@npm:0.0.1107588": version: 0.0.1107588 resolution: "devtools-protocol@npm:0.0.1107588" @@ -3835,6 +8205,43 @@ __metadata: languageName: node linkType: hard +"dns-equal@npm:^1.0.0": + version: 1.0.0 + resolution: "dns-equal@npm:1.0.0" + checksum: a8471ac849c7c13824f053babea1bc26e2f359394dd5a460f8340d8abd13434be01e3327a5c59d212f8c8997817450efd3f3ac77bec709b21979cf0235644524 + languageName: node + linkType: hard + +"dns-packet@npm:^5.2.2": + version: 5.6.1 + resolution: "dns-packet@npm:5.6.1" + dependencies: + "@leichtgewicht/ip-codec": ^2.0.1 + checksum: 64c06457f0c6e143f7a0946e0aeb8de1c5f752217cfa143ef527467c00a6d78db1835cfdb6bb68333d9f9a4963cf23f410439b5262a8935cce1236f45e344b81 + languageName: node + linkType: hard + +"docs@workspace:docs": + version: 0.0.0-use.local + resolution: "docs@workspace:docs" + dependencies: + "@docusaurus/core": ^2.4.0 + "@docusaurus/module-type-aliases": ^2.4.0 + "@docusaurus/plugin-google-gtag": ^2.4.0 + "@docusaurus/preset-classic": ^2.4.0 + "@easyops-cn/docusaurus-search-local": ^0.35.0 + "@mdx-js/react": ^1.6.22 + axios: ^1.4.0 + clsx: ^1.2.1 + hast-util-is-element: ^1.1.0 + prism-react-renderer: ^1.3.5 + react: ^17.0.2 + react-dom: ^17.0.2 + rehype-katex: ^5.0.0 + remark-math: ^3.0.1 + languageName: unknown + linkType: soft + "doctrine@npm:^3.0.0": version: 3.0.0 resolution: "doctrine@npm:3.0.0" @@ -3844,7 +8251,111 @@ __metadata: languageName: node linkType: hard -"duplexer@npm:~0.1.1": +"dom-converter@npm:^0.2.0": + version: 0.2.0 + resolution: "dom-converter@npm:0.2.0" + dependencies: + utila: ~0.4 + checksum: ea52fe303f5392e48dea563abef0e6fb3a478b8dbe3c599e99bb5d53981c6c38fc4944e56bb92a8ead6bb989d10b7914722ae11febbd2fd0910e33b9fc4aaa77 + languageName: node + linkType: hard + +"dom-serializer@npm:^1.0.1": + version: 1.4.1 + resolution: "dom-serializer@npm:1.4.1" + dependencies: + domelementtype: ^2.0.1 + domhandler: ^4.2.0 + entities: ^2.0.0 + checksum: fbb0b01f87a8a2d18e6e5a388ad0f7ec4a5c05c06d219377da1abc7bb0f674d804f4a8a94e3f71ff15f6cb7dcfc75704a54b261db672b9b3ab03da6b758b0b22 + languageName: node + linkType: hard + +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.2 + entities: ^4.2.0 + checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 + languageName: node + linkType: hard + +"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 + languageName: node + linkType: hard + +"domhandler@npm:^4.0.0, domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": + version: 4.3.1 + resolution: "domhandler@npm:4.3.1" + dependencies: + domelementtype: ^2.2.0 + checksum: 4c665ceed016e1911bf7d1dadc09dc888090b64dee7851cccd2fcf5442747ec39c647bb1cb8c8919f8bbdd0f0c625a6bafeeed4b2d656bbecdbae893f43ffaaa + languageName: node + linkType: hard + +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: ^2.3.0 + checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c + languageName: node + linkType: hard + +"domutils@npm:^2.5.2, domutils@npm:^2.8.0": + version: 2.8.0 + resolution: "domutils@npm:2.8.0" + dependencies: + dom-serializer: ^1.0.1 + domelementtype: ^2.2.0 + domhandler: ^4.2.0 + checksum: abf7434315283e9aadc2a24bac0e00eab07ae4313b40cc239f89d84d7315ebdfd2fb1b5bf750a96bc1b4403d7237c7b2ebf60459be394d625ead4ca89b934391 + languageName: node + linkType: hard + +"domutils@npm:^3.0.1": + version: 3.1.0 + resolution: "domutils@npm:3.1.0" + dependencies: + dom-serializer: ^2.0.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + checksum: e5757456ddd173caa411cfc02c2bb64133c65546d2c4081381a3bafc8a57411a41eed70494551aa58030be9e58574fcc489828bebd673863d39924fb4878f416 + languageName: node + linkType: hard + +"dot-case@npm:^3.0.4": + version: 3.0.4 + resolution: "dot-case@npm:3.0.4" + dependencies: + no-case: ^3.0.4 + tslib: ^2.0.3 + checksum: a65e3519414856df0228b9f645332f974f2bf5433370f544a681122eab59e66038fc3349b4be1cdc47152779dac71a5864f1ccda2f745e767c46e9c6543b1169 + languageName: node + linkType: hard + +"dot-prop@npm:^5.2.0": + version: 5.3.0 + resolution: "dot-prop@npm:5.3.0" + dependencies: + is-obj: ^2.0.0 + checksum: d5775790093c234ef4bfd5fbe40884ff7e6c87573e5339432870616331189f7f5d86575c5b5af2dcf0f61172990f4f734d07844b1f23482fff09e3c4bead05ea + languageName: node + linkType: hard + +"duplexer3@npm:^0.1.4": + version: 0.1.5 + resolution: "duplexer3@npm:0.1.5" + checksum: e677cb4c48f031ca728601d6a20bf6aed4c629d69ef9643cb89c67583d673c4ec9317cc6427501f38bd8c368d3a18f173987cc02bd99d8cf8fe3d94259a22a20 + languageName: node + linkType: hard + +"duplexer@npm:^0.1.2, duplexer@npm:~0.1.1": version: 0.1.2 resolution: "duplexer@npm:0.1.2" checksum: 62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 @@ -3865,6 +8376,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.4.535": + version: 1.4.554 + resolution: "electron-to-chromium@npm:1.4.554" + checksum: cbac43c50b43777327f4a7bf149ee3088c1da8b91bbcd80f78d2cc77bc52763f6d0941574499239d9caefd3430d3093f865e5f1093371418f7d6b70301eeae9b + languageName: node + linkType: hard + "elliptic@npm:6.5.4, elliptic@npm:^6.5.2, elliptic@npm:^6.5.4": version: 6.5.4 resolution: "elliptic@npm:6.5.4" @@ -3901,7 +8419,21 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:^1.0.2": +"emojis-list@npm:^3.0.0": + version: 3.0.0 + resolution: "emojis-list@npm:3.0.0" + checksum: ddaaa02542e1e9436c03970eeed445f4ed29a5337dfba0fe0c38dfdd2af5da2429c2a0821304e8a8d1cadf27fdd5b22ff793571fa803ae16852a6975c65e8e70 + languageName: node + linkType: hard + +"emoticon@npm:^3.2.0": + version: 3.2.0 + resolution: "emoticon@npm:3.2.0" + checksum: f30649d18b672ab3139e95cb04f77b2442feb95c99dc59372ff80fbfd639b2bf4018bc68ab0b549bd765aecf8230d7899c43f86cfcc7b6370c06c3232783e24f + languageName: node + linkType: hard + +"encodeurl@npm:^1.0.2, encodeurl@npm:~1.0.2": version: 1.0.2 resolution: "encodeurl@npm:1.0.2" checksum: e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c @@ -3926,6 +8458,16 @@ __metadata: languageName: node linkType: hard +"enhanced-resolve@npm:^5.15.0": + version: 5.15.0 + resolution: "enhanced-resolve@npm:5.15.0" + dependencies: + graceful-fs: ^4.2.4 + tapable: ^2.2.0 + checksum: fbd8cdc9263be71cc737aa8a7d6c57b43d6aa38f6cc75dde6fcd3598a130cc465f979d2f4d01bb3bf475acb43817749c79f8eef9be048683602ca91ab52e4f11 + languageName: node + linkType: hard + "enquirer@npm:^2.3.0": version: 2.4.1 resolution: "enquirer@npm:2.4.1" @@ -3936,6 +8478,20 @@ __metadata: languageName: node linkType: hard +"entities@npm:^2.0.0": + version: 2.2.0 + resolution: "entities@npm:2.2.0" + checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 + languageName: node + linkType: hard + +"entities@npm:^4.2.0, entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -3950,6 +8506,15 @@ __metadata: languageName: node linkType: hard +"error-ex@npm:^1.3.1": + version: 1.3.2 + resolution: "error-ex@npm:1.3.2" + dependencies: + is-arrayish: ^0.2.1 + checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 + languageName: node + linkType: hard + "errorstacks@npm:^2.2.0": version: 2.4.0 resolution: "errorstacks@npm:2.4.0" @@ -3957,7 +8522,7 @@ __metadata: languageName: node linkType: hard -"es-module-lexer@npm:^1.0.0": +"es-module-lexer@npm:^1.0.0, es-module-lexer@npm:^1.2.1": version: 1.3.1 resolution: "es-module-lexer@npm:1.3.1" checksum: 3beafa7e171eb1e8cc45695edf8d51638488dddf65294d7911f8d6a96249da6a9838c87529262cc6ea53988d8272cec0f4bff93f476ed031a54ba3afb51a0ed3 @@ -4048,7 +8613,14 @@ __metadata: languageName: node linkType: hard -"escape-html@npm:^1.0.3": +"escape-goat@npm:^2.0.0": + version: 2.1.1 + resolution: "escape-goat@npm:2.1.1" + checksum: ce05c70c20dd7007b60d2d644b625da5412325fdb57acf671ba06cb2ab3cd6789e2087026921a05b665b0a03fadee2955e7fc0b9a67da15a6551a980b260eba7 + languageName: node + linkType: hard + +"escape-html@npm:^1.0.3, escape-html@npm:~1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" checksum: 6213ca9ae00d0ab8bccb6d8d4e0a98e76237b2410302cf7df70aaa6591d509a2a37ce8998008cbecae8fc8ffaadf3fb0229535e6a145f3ce0b211d060decbb24 @@ -4102,6 +8674,16 @@ __metadata: languageName: node linkType: hard +"eslint-scope@npm:5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: ^4.3.0 + estraverse: ^4.1.1 + checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb + languageName: node + linkType: hard + "eslint-scope@npm:^7.2.2": version: 7.2.2 resolution: "eslint-scope@npm:7.2.2" @@ -4205,6 +8787,13 @@ __metadata: languageName: node linkType: hard +"estraverse@npm:^4.1.1": + version: 4.3.0 + resolution: "estraverse@npm:4.3.0" + checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827 + languageName: node + linkType: hard + "estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" @@ -4226,7 +8815,14 @@ __metadata: languageName: node linkType: hard -"etag@npm:^1.8.1": +"eta@npm:^2.0.0": + version: 2.2.0 + resolution: "eta@npm:2.2.0" + checksum: 6a09631481d4f26a9662a1eb736a65cc1cbc48e24935e6ff5d83a83b0cb509ea56d588d66d7c087d590601dc59bdabdac2356936b1b789d020eb0cf2d8304d54 + languageName: node + linkType: hard + +"etag@npm:^1.8.1, etag@npm:~1.8.1": version: 1.8.1 resolution: "etag@npm:1.8.1" checksum: 571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff @@ -4356,6 +8952,16 @@ __metadata: languageName: node linkType: hard +"eval@npm:^0.1.8": + version: 0.1.8 + resolution: "eval@npm:0.1.8" + dependencies: + "@types/node": "*" + require-like: ">= 0.1.1" + checksum: d005567f394cfbe60948e34982e4637d2665030f9aa7dcac581ea6f9ec6eceb87133ed3dc0ae21764aa362485c242a731dbb6371f1f1a86807c58676431e9d1a + languageName: node + linkType: hard + "event-stream@npm:=3.3.4": version: 3.3.4 resolution: "event-stream@npm:3.3.4" @@ -4371,6 +8977,20 @@ __metadata: languageName: node linkType: hard +"eventemitter3@npm:^4.0.0": + version: 4.0.7 + resolution: "eventemitter3@npm:4.0.7" + checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 + languageName: node + linkType: hard + +"events@npm:^3.2.0": + version: 3.3.0 + resolution: "events@npm:3.3.0" + checksum: f6f487ad2198aa41d878fa31452f1a3c00958f46e9019286ff4787c84aac329332ab45c9cdc8c445928fc6d7ded294b9e005a7fce9426488518017831b272780 + languageName: node + linkType: hard + "evp_bytestokey@npm:^1.0.3": version: 1.0.3 resolution: "evp_bytestokey@npm:1.0.3" @@ -4423,6 +9043,61 @@ __metadata: languageName: node linkType: hard +"express@npm:^4.17.3": + version: 4.18.2 + resolution: "express@npm:4.18.2" + dependencies: + accepts: ~1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: ~1.0.4 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + etag: ~1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: ~1.1.2 + on-finished: 2.4.1 + parseurl: ~1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: ~2.0.7 + qs: 6.11.0 + range-parser: ~1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: ~1.6.18 + utils-merge: 1.0.1 + vary: ~1.1.2 + checksum: 3c4b9b076879442f6b968fe53d85d9f1eeacbb4f4c41e5f16cc36d77ce39a2b0d81b3f250514982110d815b2f7173f5561367f9110fcc541f9371948e8c8b037 + languageName: node + linkType: hard + +"extend-shallow@npm:^2.0.1": + version: 2.0.1 + resolution: "extend-shallow@npm:2.0.1" + dependencies: + is-extendable: ^0.1.0 + checksum: 8fb58d9d7a511f4baf78d383e637bd7d2e80843bd9cd0853649108ea835208fb614da502a553acc30208e1325240bb7cc4a68473021612496bb89725483656d8 + languageName: node + linkType: hard + +"extend@npm:^3.0.0": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 + languageName: node + linkType: hard + "extract-zip@npm:2.0.1": version: 2.0.1 resolution: "extract-zip@npm:2.0.1" @@ -4454,7 +9129,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": +"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": version: 3.3.1 resolution: "fast-glob@npm:3.3.1" dependencies: @@ -4481,6 +9156,15 @@ __metadata: languageName: node linkType: hard +"fast-url-parser@npm:1.1.3": + version: 1.1.3 + resolution: "fast-url-parser@npm:1.1.3" + dependencies: + punycode: ^1.3.2 + checksum: 5043d0c4a8d775ff58504d56c096563c11b113e4cb8a2668c6f824a1cd4fb3812e2fdf76537eb24a7ce4ae7def6bd9747da630c617cf2a4b6ce0c42514e4f21c + languageName: node + linkType: hard + "fastq@npm:^1.6.0": version: 1.15.0 resolution: "fastq@npm:1.15.0" @@ -4490,6 +9174,46 @@ __metadata: languageName: node linkType: hard +"faye-websocket@npm:^0.11.3": + version: 0.11.4 + resolution: "faye-websocket@npm:0.11.4" + dependencies: + websocket-driver: ">=0.5.1" + checksum: d49a62caf027f871149fc2b3f3c7104dc6d62744277eb6f9f36e2d5714e847d846b9f7f0d0b7169b25a012e24a594cde11a93034b30732e4c683f20b8a5019fa + languageName: node + linkType: hard + +"fbemitter@npm:^3.0.0": + version: 3.0.0 + resolution: "fbemitter@npm:3.0.0" + dependencies: + fbjs: ^3.0.0 + checksum: 069690b8cdff3521ade3c9beb92ba0a38d818a86ef36dff8690e66749aef58809db4ac0d6938eb1cacea2dbef5f2a508952d455669590264cdc146bbe839f605 + languageName: node + linkType: hard + +"fbjs-css-vars@npm:^1.0.0": + version: 1.0.2 + resolution: "fbjs-css-vars@npm:1.0.2" + checksum: 72baf6d22c45b75109118b4daecb6c8016d4c83c8c0f23f683f22e9d7c21f32fff6201d288df46eb561e3c7d4bb4489b8ad140b7f56444c453ba407e8bd28511 + languageName: node + linkType: hard + +"fbjs@npm:^3.0.0, fbjs@npm:^3.0.1": + version: 3.0.5 + resolution: "fbjs@npm:3.0.5" + dependencies: + cross-fetch: ^3.1.5 + fbjs-css-vars: ^1.0.0 + loose-envify: ^1.0.0 + object-assign: ^4.1.0 + promise: ^7.1.1 + setimmediate: ^1.0.5 + ua-parser-js: ^1.0.35 + checksum: e609b5b64686bc96495a5c67728ed9b2710b9b3d695c5759c5f5e47c9483d1c323543ac777a86459e3694efc5712c6ce7212e944feb19752867d699568bb0e54 + languageName: node + linkType: hard + "fd-slicer@npm:~1.1.0": version: 1.1.0 resolution: "fd-slicer@npm:1.1.0" @@ -4499,6 +9223,15 @@ __metadata: languageName: node linkType: hard +"feed@npm:^4.2.2": + version: 4.2.2 + resolution: "feed@npm:4.2.2" + dependencies: + xml-js: ^1.6.11 + checksum: 2e6992a675a049511eef7bda8ca6c08cb9540cd10e8b275ec4c95d166228ec445a335fa8de990358759f248a92861e51decdcd32bf1c54737d5b7aed7c7ffe97 + languageName: node + linkType: hard + "fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4": version: 3.2.0 resolution: "fetch-blob@npm:3.2.0" @@ -4535,6 +9268,25 @@ __metadata: languageName: node linkType: hard +"file-loader@npm:^6.2.0": + version: 6.2.0 + resolution: "file-loader@npm:6.2.0" + dependencies: + loader-utils: ^2.0.0 + schema-utils: ^3.0.0 + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: faf43eecf233f4897b0150aaa874eeeac214e4f9de49738a9e0ef734a30b5260059e85b7edadf852b98e415f875bd5f12587768a93fd52aaf2e479ecf95fab20 + languageName: node + linkType: hard + +"filesize@npm:^8.0.6": + version: 8.0.7 + resolution: "filesize@npm:8.0.7" + checksum: 8603d27c5287b984cb100733640645e078f5f5ad65c6d913173e01fb99e09b0747828498fd86647685ccecb69be31f3587b9739ab1e50732116b2374aff4cbf9 + languageName: node + linkType: hard + "fill-range@npm:^7.0.1": version: 7.0.1 resolution: "fill-range@npm:7.0.1" @@ -4544,6 +9296,32 @@ __metadata: languageName: node linkType: hard +"finalhandler@npm:1.2.0": + version: 1.2.0 + resolution: "finalhandler@npm:1.2.0" + dependencies: + debug: 2.6.9 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + on-finished: 2.4.1 + parseurl: ~1.3.3 + statuses: 2.0.1 + unpipe: ~1.0.0 + checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 + languageName: node + linkType: hard + +"find-cache-dir@npm:^3.3.1": + version: 3.3.2 + resolution: "find-cache-dir@npm:3.3.2" + dependencies: + commondir: ^1.0.1 + make-dir: ^3.0.2 + pkg-dir: ^4.1.0 + checksum: 1e61c2e64f5c0b1c535bd85939ae73b0e5773142713273818cc0b393ee3555fb0fd44e1a5b161b8b6c3e03e98c2fcc9c227d784850a13a90a8ab576869576817 + languageName: node + linkType: hard + "find-replace@npm:^3.0.0": version: 3.0.0 resolution: "find-replace@npm:3.0.0" @@ -4572,6 +9350,25 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^3.0.0": + version: 3.0.0 + resolution: "find-up@npm:3.0.0" + dependencies: + locate-path: ^3.0.0 + checksum: 38eba3fe7a66e4bc7f0f5a1366dc25508b7cfc349f852640e3678d26ad9a6d7e2c43eff0a472287de4a9753ef58f066a0ea892a256fa3636ad51b3fe1e17fae9 + languageName: node + linkType: hard + +"find-up@npm:^4.0.0": + version: 4.1.0 + resolution: "find-up@npm:4.1.0" + dependencies: + locate-path: ^5.0.0 + path-exists: ^4.0.0 + checksum: 4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 + languageName: node + linkType: hard + "find-up@npm:^6.0.0": version: 6.3.0 resolution: "find-up@npm:6.3.0" @@ -4609,23 +9406,77 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.12.1": +"flux@npm:^4.0.1": + version: 4.0.4 + resolution: "flux@npm:4.0.4" + dependencies: + fbemitter: ^3.0.0 + fbjs: ^3.0.1 + peerDependencies: + react: ^15.0.2 || ^16.0.0 || ^17.0.0 + checksum: 8fa5c2f9322258de3e331f67c6f1078a7f91c4dec9dbe8a54c4b8a80eed19a4f91889028b768668af4a796e8f2ee75e461e1571b8615432a3920ae95cc4ff794 + languageName: node + linkType: hard + +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.14.7, follow-redirects@npm:^1.15.0": version: 1.15.3 resolution: "follow-redirects@npm:1.15.3" peerDependenciesMeta: - debug: + debug: + optional: true + checksum: 584da22ec5420c837bd096559ebfb8fe69d82512d5585004e36a3b4a6ef6d5905780e0c74508c7b72f907d1fa2b7bd339e613859e9c304d0dc96af2027fd0231 + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.0": + version: 3.1.1 + resolution: "foreground-child@npm:3.1.1" + dependencies: + cross-spawn: ^7.0.0 + signal-exit: ^4.0.1 + checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 + languageName: node + linkType: hard + +"fork-ts-checker-webpack-plugin@npm:^6.5.0": + version: 6.5.3 + resolution: "fork-ts-checker-webpack-plugin@npm:6.5.3" + dependencies: + "@babel/code-frame": ^7.8.3 + "@types/json-schema": ^7.0.5 + chalk: ^4.1.0 + chokidar: ^3.4.2 + cosmiconfig: ^6.0.0 + deepmerge: ^4.2.2 + fs-extra: ^9.0.0 + glob: ^7.1.6 + memfs: ^3.1.2 + minimatch: ^3.0.4 + schema-utils: 2.7.0 + semver: ^7.3.2 + tapable: ^1.0.0 + peerDependencies: + eslint: ">= 6" + typescript: ">= 2.7" + vue-template-compiler: "*" + webpack: ">= 4" + peerDependenciesMeta: + eslint: optional: true - checksum: 584da22ec5420c837bd096559ebfb8fe69d82512d5585004e36a3b4a6ef6d5905780e0c74508c7b72f907d1fa2b7bd339e613859e9c304d0dc96af2027fd0231 + vue-template-compiler: + optional: true + checksum: 9732a49bfeed8fc23e6e8a59795fa7c238edeba91040a9b520db54b4d316dda27f9f1893d360e296fd0ad8930627d364417d28a8c7007fba60cc730ebfce4956 languageName: node linkType: hard -"foreground-child@npm:^3.1.0": - version: 3.1.1 - resolution: "foreground-child@npm:3.1.1" +"form-data@npm:^4.0.0": + version: 4.0.0 + resolution: "form-data@npm:4.0.0" dependencies: - cross-spawn: ^7.0.0 - signal-exit: ^4.0.1 - checksum: 139d270bc82dc9e6f8bc045fe2aae4001dc2472157044fdfad376d0a3457f77857fa883c1c8b21b491c6caade9a926a4bed3d3d2e8d3c9202b151a4cbbd0bcd5 + asynckit: ^0.4.0 + combined-stream: ^1.0.8 + mime-types: ^2.1.12 + checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c languageName: node linkType: hard @@ -4638,6 +9489,13 @@ __metadata: languageName: node linkType: hard +"forwarded@npm:0.2.0": + version: 0.2.0 + resolution: "forwarded@npm:0.2.0" + checksum: fd27e2394d8887ebd16a66ffc889dc983fbbd797d5d3f01087c020283c0f019a7d05ee85669383d8e0d216b116d720fc0cef2f6e9b7eb9f4c90c6e0bc7fd28e6 + languageName: node + linkType: hard + "fp-ts@npm:1.19.3": version: 1.19.3 resolution: "fp-ts@npm:1.19.3" @@ -4652,7 +9510,14 @@ __metadata: languageName: node linkType: hard -"fresh@npm:~0.5.2": +"fraction.js@npm:^4.3.6": + version: 4.3.7 + resolution: "fraction.js@npm:4.3.7" + checksum: e1553ae3f08e3ba0e8c06e43a3ab20b319966dfb7ddb96fd9b5d0ee11a66571af7f993229c88ebbb0d4a816eb813a24ed48207b140d442a8f76f33763b8d1f3f + languageName: node + linkType: hard + +"fresh@npm:0.5.2, fresh@npm:~0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" checksum: 13ea8b08f91e669a64e3ba3a20eb79d7ca5379a81f1ff7f4310d54e2320645503cc0c78daedc93dfb6191287295f6479544a649c64d8e41a1c0fb0c221552346 @@ -4686,7 +9551,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^10.1.0": +"fs-extra@npm:^10.0.0, fs-extra@npm:^10.1.0": version: 10.1.0 resolution: "fs-extra@npm:10.1.0" dependencies: @@ -4708,6 +9573,18 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^9.0.0": + version: 9.1.0 + resolution: "fs-extra@npm:9.1.0" + dependencies: + at-least-node: ^1.0.0 + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -4726,6 +9603,13 @@ __metadata: languageName: node linkType: hard +"fs-monkey@npm:^1.0.4": + version: 1.0.5 + resolution: "fs-monkey@npm:1.0.5" + checksum: 424b67f65b37fe66117ae2bb061f790fe6d4b609e1d160487c74b3d69fbf42f262c665ccfba32e8b5f113f96f92e9a58fcdebe42d5f6649bdfc72918093a3119 + languageName: node + linkType: hard + "fs.realpath@npm:^1.0.0": version: 1.0.0 resolution: "fs.realpath@npm:1.0.0" @@ -4801,6 +9685,13 @@ __metadata: languageName: node linkType: hard +"gensync@npm:^1.0.0-beta.1, gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec + languageName: node + linkType: hard + "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -4815,7 +9706,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2": +"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1": version: 1.2.1 resolution: "get-intrinsic@npm:1.2.1" dependencies: @@ -4827,6 +9718,13 @@ __metadata: languageName: node linkType: hard +"get-own-enumerable-property-symbols@npm:^3.0.0": + version: 3.0.2 + resolution: "get-own-enumerable-property-symbols@npm:3.0.2" + checksum: 8f0331f14159f939830884799f937343c8c0a2c330506094bc12cbee3665d88337fe97a4ea35c002cc2bdba0f5d9975ad7ec3abb925015cdf2a93e76d4759ede + languageName: node + linkType: hard + "get-stdin@npm:^8.0.0": version: 8.0.0 resolution: "get-stdin@npm:8.0.0" @@ -4834,6 +9732,15 @@ __metadata: languageName: node linkType: hard +"get-stream@npm:^4.1.0": + version: 4.1.0 + resolution: "get-stream@npm:4.1.0" + dependencies: + pump: ^3.0.0 + checksum: 443e1914170c15bd52ff8ea6eff6dfc6d712b031303e36302d2778e3de2506af9ee964d6124010f7818736dcfde05c04ba7ca6cc26883106e084357a17ae7d73 + languageName: node + linkType: hard + "get-stream@npm:^5.1.0": version: 5.2.0 resolution: "get-stream@npm:5.2.0" @@ -4850,6 +9757,13 @@ __metadata: languageName: node linkType: hard +"github-slugger@npm:^1.4.0": + version: 1.5.0 + resolution: "github-slugger@npm:1.5.0" + checksum: c70988224578b3bdaa25df65973ffc8c24594a77a28550c3636e495e49d17aef5cdb04c04fa3f1744babef98c61eecc6a43299a13ea7f3cc33d680bf9053ffbe + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -4859,7 +9773,7 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:^6.0.2": +"glob-parent@npm:^6.0.1, glob-parent@npm:^6.0.2": version: 6.0.2 resolution: "glob-parent@npm:6.0.2" dependencies: @@ -4868,6 +9782,13 @@ __metadata: languageName: node linkType: hard +"glob-to-regexp@npm:^0.4.1": + version: 0.4.1 + resolution: "glob-to-regexp@npm:0.4.1" + checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167 + languageName: node + linkType: hard + "glob@npm:7.2.0": version: 7.2.0 resolution: "glob@npm:7.2.0" @@ -4897,7 +9818,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3, glob@npm:^7.1.4": +"glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -4911,6 +9832,42 @@ __metadata: languageName: node linkType: hard +"global-dirs@npm:^3.0.0": + version: 3.0.1 + resolution: "global-dirs@npm:3.0.1" + dependencies: + ini: 2.0.0 + checksum: 70147b80261601fd40ac02a104581432325c1c47329706acd773f3a6ce99bb36d1d996038c85ccacd482ad22258ec233c586b6a91535b1a116b89663d49d6438 + languageName: node + linkType: hard + +"global-modules@npm:^2.0.0": + version: 2.0.0 + resolution: "global-modules@npm:2.0.0" + dependencies: + global-prefix: ^3.0.0 + checksum: d6197f25856c878c2fb5f038899f2dca7cbb2f7b7cf8999660c0104972d5cfa5c68b5a0a77fa8206bb536c3903a4615665acb9709b4d80846e1bb47eaef65430 + languageName: node + linkType: hard + +"global-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "global-prefix@npm:3.0.0" + dependencies: + ini: ^1.3.5 + kind-of: ^6.0.2 + which: ^1.3.1 + checksum: 8a82fc1d6f22c45484a4e34656cc91bf021a03e03213b0035098d605bfc612d7141f1e14a21097e8a0413b4884afd5b260df0b6a25605ce9d722e11f1df2881d + languageName: node + linkType: hard + +"globals@npm:^11.1.0": + version: 11.12.0 + resolution: "globals@npm:11.12.0" + checksum: 67051a45eca3db904aee189dfc7cd53c20c7d881679c93f6146ddd4c9f4ab2268e68a919df740d39c71f4445d2b38ee360fc234428baea1dbdfe68bbcb46979e + languageName: node + linkType: hard + "globals@npm:^13.19.0": version: 13.22.0 resolution: "globals@npm:13.22.0" @@ -4920,7 +9877,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.0.1, globby@npm:^11.1.0": +"globby@npm:^11.0.1, globby@npm:^11.0.4, globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: @@ -4934,7 +9891,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^13.1.2, globby@npm:^13.1.4": +"globby@npm:^13.1.1, globby@npm:^13.1.2, globby@npm:^13.1.4": version: 13.2.2 resolution: "globby@npm:13.2.2" dependencies: @@ -4947,7 +9904,35 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": +"gopd@npm:^1.0.1": + version: 1.0.1 + resolution: "gopd@npm:1.0.1" + dependencies: + get-intrinsic: ^1.1.3 + checksum: a5ccfb8806e0917a94e0b3de2af2ea4979c1da920bc381667c260e00e7cafdbe844e2cb9c5bcfef4e5412e8bf73bab837285bc35c7ba73aaaf0134d4583393a6 + languageName: node + linkType: hard + +"got@npm:^9.6.0": + version: 9.6.0 + resolution: "got@npm:9.6.0" + dependencies: + "@sindresorhus/is": ^0.14.0 + "@szmarczak/http-timer": ^1.1.2 + cacheable-request: ^6.0.0 + decompress-response: ^3.3.0 + duplexer3: ^0.1.4 + get-stream: ^4.1.0 + lowercase-keys: ^1.0.1 + mimic-response: ^1.0.1 + p-cancelable: ^1.0.0 + to-readable-stream: ^1.0.0 + url-parse-lax: ^3.0.0 + checksum: 941807bd9704bacf5eb401f0cc1212ffa1f67c6642f2d028fd75900471c221b1da2b8527f4553d2558f3faeda62ea1cf31665f8b002c6137f5de8732f07370b0 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 @@ -4961,6 +9946,34 @@ __metadata: languageName: node linkType: hard +"gray-matter@npm:^4.0.3": + version: 4.0.3 + resolution: "gray-matter@npm:4.0.3" + dependencies: + js-yaml: ^3.13.1 + kind-of: ^6.0.2 + section-matter: ^1.0.0 + strip-bom-string: ^1.0.0 + checksum: 37717bd424344487d655392251ce8d8878a1275ee087003e61208fba3bfd59cbb73a85b2159abf742ae95e23db04964813fdc33ae18b074208428b2528205222 + languageName: node + linkType: hard + +"gzip-size@npm:^6.0.0": + version: 6.0.0 + resolution: "gzip-size@npm:6.0.0" + dependencies: + duplexer: ^0.1.2 + checksum: 2df97f359696ad154fc171dcb55bc883fe6e833bca7a65e457b9358f3cb6312405ed70a8da24a77c1baac0639906cd52358dc0ce2ec1a937eaa631b934c94194 + languageName: node + linkType: hard + +"handle-thing@npm:^2.0.0": + version: 2.0.1 + resolution: "handle-thing@npm:2.0.1" + checksum: 68071f313062315cd9dce55710e9496873945f1dd425107007058fc1629f93002a7649fcc3e464281ce02c7e809a35f5925504ab8105d972cf649f1f47cb7d6c + languageName: node + linkType: hard + "hardhat@npm:^2.17.4": version: 2.17.4 resolution: "hardhat@npm:2.17.4" @@ -5041,6 +10054,15 @@ __metadata: languageName: node linkType: hard +"has-property-descriptors@npm:^1.0.0": + version: 1.0.0 + resolution: "has-property-descriptors@npm:1.0.0" + dependencies: + get-intrinsic: ^1.1.1 + checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb + languageName: node + linkType: hard + "has-proto@npm:^1.0.1": version: 1.0.1 resolution: "has-proto@npm:1.0.1" @@ -5071,6 +10093,13 @@ __metadata: languageName: node linkType: hard +"has-yarn@npm:^2.1.0": + version: 2.1.0 + resolution: "has-yarn@npm:2.1.0" + checksum: 5eb1d0bb8518103d7da24532bdbc7124ffc6d367b5d3c10840b508116f2f1bcbcf10fd3ba843ff6e2e991bdf9969fd862d42b2ed58aade88343326c950b7e7f7 + languageName: node + linkType: hard + "has@npm:^1.0.3": version: 1.0.3 resolution: "has@npm:1.0.3" @@ -5101,7 +10130,105 @@ __metadata: languageName: node linkType: hard -"he@npm:1.2.0": +"hast-to-hyperscript@npm:^9.0.0": + version: 9.0.1 + resolution: "hast-to-hyperscript@npm:9.0.1" + dependencies: + "@types/unist": ^2.0.3 + comma-separated-tokens: ^1.0.0 + property-information: ^5.3.0 + space-separated-tokens: ^1.0.0 + style-to-object: ^0.3.0 + unist-util-is: ^4.0.0 + web-namespaces: ^1.0.0 + checksum: de570d789853018fff2fd38fc096549b9814e366b298f60c90c159a57018230eefc44d46a246027b0e2426ed9e99f2e270050bc183d5bdfe4c9487c320b392cd + languageName: node + linkType: hard + +"hast-util-from-parse5@npm:^6.0.0": + version: 6.0.1 + resolution: "hast-util-from-parse5@npm:6.0.1" + dependencies: + "@types/parse5": ^5.0.0 + hastscript: ^6.0.0 + property-information: ^5.0.0 + vfile: ^4.0.0 + vfile-location: ^3.2.0 + web-namespaces: ^1.0.0 + checksum: 4daa78201468af7779161e7caa2513c329830778e0528481ab16b3e1bcef4b831f6285b526aacdddbee802f3bd9d64df55f80f010591ea1916da535e3a923b83 + languageName: node + linkType: hard + +"hast-util-is-element@npm:^1.0.0, hast-util-is-element@npm:^1.1.0": + version: 1.1.0 + resolution: "hast-util-is-element@npm:1.1.0" + checksum: 30fad3f65e7ab2f0efd5db9e7344d0820b70971988dfe79f62d8447598b2a1ce8a59cd4bfc05ae0d9a1c451b9b53cbe1023743d7eac764d64720b6b73475f62f + languageName: node + linkType: hard + +"hast-util-parse-selector@npm:^2.0.0": + version: 2.2.5 + resolution: "hast-util-parse-selector@npm:2.2.5" + checksum: 22ee4afbd11754562144cb3c4f3ec52524dafba4d90ee52512902d17cf11066d83b38f7bdf6ca571bbc2541f07ba30db0d234657b6ecb8ca4631587466459605 + languageName: node + linkType: hard + +"hast-util-raw@npm:6.0.1": + version: 6.0.1 + resolution: "hast-util-raw@npm:6.0.1" + dependencies: + "@types/hast": ^2.0.0 + hast-util-from-parse5: ^6.0.0 + hast-util-to-parse5: ^6.0.0 + html-void-elements: ^1.0.0 + parse5: ^6.0.0 + unist-util-position: ^3.0.0 + vfile: ^4.0.0 + web-namespaces: ^1.0.0 + xtend: ^4.0.0 + zwitch: ^1.0.0 + checksum: f6d960644f9fbbe0b92d0227b20a24d659cce021d5f9fd218e077154931b4524ee920217b7fd5a45ec2736ec1dee53de9209fe449f6f89454c01d225ff0e7851 + languageName: node + linkType: hard + +"hast-util-to-parse5@npm:^6.0.0": + version: 6.0.0 + resolution: "hast-util-to-parse5@npm:6.0.0" + dependencies: + hast-to-hyperscript: ^9.0.0 + property-information: ^5.0.0 + web-namespaces: ^1.0.0 + xtend: ^4.0.0 + zwitch: ^1.0.0 + checksum: 91a36244e37df1d63c8b7e865ab0c0a25bb7396155602be005cf71d95c348e709568f80e0f891681a3711d733ad896e70642dc41a05b574eddf2e07d285408a8 + languageName: node + linkType: hard + +"hast-util-to-text@npm:^2.0.0": + version: 2.0.1 + resolution: "hast-util-to-text@npm:2.0.1" + dependencies: + hast-util-is-element: ^1.0.0 + repeat-string: ^1.0.0 + unist-util-find-after: ^3.0.0 + checksum: 4e7960b414b7a6b2f0180e4af416cd8ae3c7ba1531d7eaec7e6dc9509daf88308784bbf5b94885384dccc42abcb74cc6cc26755c76914d646f32aa6bc32ea34b + languageName: node + linkType: hard + +"hastscript@npm:^6.0.0": + version: 6.0.0 + resolution: "hastscript@npm:6.0.0" + dependencies: + "@types/hast": ^2.0.0 + comma-separated-tokens: ^1.0.0 + hast-util-parse-selector: ^2.0.0 + property-information: ^5.0.0 + space-separated-tokens: ^1.0.0 + checksum: 5e50b85af0d2cb7c17979cb1ddca75d6b96b53019dd999b39e7833192c9004201c3cee6445065620ea05d0087d9ae147a4844e582d64868be5bc6b0232dfe52d + languageName: node + linkType: hard + +"he@npm:1.2.0, he@npm:^1.2.0": version: 1.2.0 resolution: "he@npm:1.2.0" bin: @@ -5110,6 +10237,20 @@ __metadata: languageName: node linkType: hard +"history@npm:^4.9.0": + version: 4.10.1 + resolution: "history@npm:4.10.1" + dependencies: + "@babel/runtime": ^7.1.2 + loose-envify: ^1.2.0 + resolve-pathname: ^3.0.0 + tiny-invariant: ^1.0.2 + tiny-warning: ^1.0.0 + value-equal: ^1.0.1 + checksum: addd84bc4683929bae4400419b5af132ff4e4e9b311a0d4e224579ea8e184a6b80d7f72c55927e4fa117f69076a9e47ce082d8d0b422f1a9ddac7991490ca1d0 + languageName: node + linkType: hard + "hmac-drbg@npm:^1.0.1": version: 1.0.1 resolution: "hmac-drbg@npm:1.0.1" @@ -5121,6 +10262,34 @@ __metadata: languageName: node linkType: hard +"hoist-non-react-statics@npm:^3.1.0": + version: 3.3.2 + resolution: "hoist-non-react-statics@npm:3.3.2" + dependencies: + react-is: ^16.7.0 + checksum: b1538270429b13901ee586aa44f4cc3ecd8831c061d06cb8322e50ea17b3f5ce4d0e2e66394761e6c8e152cd8c34fb3b4b690116c6ce2bd45b18c746516cb9e8 + languageName: node + linkType: hard + +"hpack.js@npm:^2.1.6": + version: 2.1.6 + resolution: "hpack.js@npm:2.1.6" + dependencies: + inherits: ^2.0.1 + obuf: ^1.0.0 + readable-stream: ^2.0.1 + wbuf: ^1.1.0 + checksum: 2de144115197967ad6eeee33faf41096c6ba87078703c5cb011632dcfbffeb45784569e0cf02c317bd79c48375597c8ec88c30fff5bb0b023e8f654fb6e9c06e + languageName: node + linkType: hard + +"html-entities@npm:^2.3.2": + version: 2.4.0 + resolution: "html-entities@npm:2.4.0" + checksum: 25bea32642ce9ebd0eedc4d24381883ecb0335ccb8ac26379a0958b9b16652fdbaa725d70207ce54a51db24103436a698a8e454397d3ba8ad81460224751f1dc + languageName: node + linkType: hard + "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" @@ -5128,6 +10297,76 @@ __metadata: languageName: node linkType: hard +"html-minifier-terser@npm:^6.0.2, html-minifier-terser@npm:^6.1.0": + version: 6.1.0 + resolution: "html-minifier-terser@npm:6.1.0" + dependencies: + camel-case: ^4.1.2 + clean-css: ^5.2.2 + commander: ^8.3.0 + he: ^1.2.0 + param-case: ^3.0.4 + relateurl: ^0.2.7 + terser: ^5.10.0 + bin: + html-minifier-terser: cli.js + checksum: ac52c14006476f773204c198b64838477859dc2879490040efab8979c0207424da55d59df7348153f412efa45a0840a1ca3c757bf14767d23a15e3e389d37a93 + languageName: node + linkType: hard + +"html-tags@npm:^3.2.0": + version: 3.3.1 + resolution: "html-tags@npm:3.3.1" + checksum: b4ef1d5a76b678e43cce46e3783d563607b1d550cab30b4f511211564574770aa8c658a400b100e588bc60b8234e59b35ff72c7851cc28f3b5403b13a2c6cbce + languageName: node + linkType: hard + +"html-void-elements@npm:^1.0.0": + version: 1.0.5 + resolution: "html-void-elements@npm:1.0.5" + checksum: 1a56f4f6cfbeb994c21701ff72b4b7f556fe784a70e5e554d1566ff775af83b91ea93f10664f039a67802d9f7b40d4a7f1ed20312bab47bd88d89bd792ea84ca + languageName: node + linkType: hard + +"html-webpack-plugin@npm:^5.5.0": + version: 5.5.3 + resolution: "html-webpack-plugin@npm:5.5.3" + dependencies: + "@types/html-minifier-terser": ^6.0.0 + html-minifier-terser: ^6.0.2 + lodash: ^4.17.21 + pretty-error: ^4.0.0 + tapable: ^2.0.0 + peerDependencies: + webpack: ^5.20.0 + checksum: ccf685195739c372ad641bbd0c9100a847904f34eedc7aff3ece7856cd6c78fd3746d2d615af1bb71e5727993fe711b89e9b744f033ed3fde646540bf5d5e954 + languageName: node + linkType: hard + +"htmlparser2@npm:^6.1.0": + version: 6.1.0 + resolution: "htmlparser2@npm:6.1.0" + dependencies: + domelementtype: ^2.0.1 + domhandler: ^4.0.0 + domutils: ^2.5.2 + entities: ^2.0.0 + checksum: 81a7b3d9c3bb9acb568a02fc9b1b81ffbfa55eae7f1c41ae0bf840006d1dbf54cb3aa245b2553e2c94db674840a9f0fdad7027c9a9d01a062065314039058c4e + languageName: node + linkType: hard + +"htmlparser2@npm:^8.0.1": + version: 8.0.2 + resolution: "htmlparser2@npm:8.0.2" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + entities: ^4.4.0 + checksum: 29167a0f9282f181da8a6d0311b76820c8a59bc9e3c87009e21968264c2987d2723d6fde5a964d4b7b6cba663fca96ffb373c06d8223a85f52a6089ced942700 + languageName: node + linkType: hard + "http-assert@npm:^1.3.0": version: 1.5.0 resolution: "http-assert@npm:1.5.0" @@ -5138,13 +10377,20 @@ __metadata: languageName: node linkType: hard -"http-cache-semantics@npm:^4.1.1": +"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 languageName: node linkType: hard +"http-deceiver@npm:^1.2.7": + version: 1.2.7 + resolution: "http-deceiver@npm:1.2.7" + checksum: 64d7d1ae3a6933eb0e9a94e6f27be4af45a53a96c3c34e84ff57113787105a89fff9d1c3df263ef63add823df019b0e8f52f7121e32393bb5ce9a713bf100b41 + languageName: node + linkType: hard + "http-errors@npm:2.0.0": version: 2.0.0 resolution: "http-errors@npm:2.0.0" @@ -5183,6 +10429,13 @@ __metadata: languageName: node linkType: hard +"http-parser-js@npm:>=0.5.1": + version: 0.5.8 + resolution: "http-parser-js@npm:0.5.8" + checksum: 6bbdf2429858e8cf13c62375b0bfb6dc3955ca0f32e58237488bc86cd2378f31d31785fd3ac4ce93f1c74e0189cf8823c91f5cb061696214fd368d2452dc871d + languageName: node + linkType: hard + "http-proxy-agent@npm:^5.0.0": version: 5.0.0 resolution: "http-proxy-agent@npm:5.0.0" @@ -5194,6 +10447,35 @@ __metadata: languageName: node linkType: hard +"http-proxy-middleware@npm:^2.0.3": + version: 2.0.6 + resolution: "http-proxy-middleware@npm:2.0.6" + dependencies: + "@types/http-proxy": ^1.17.8 + http-proxy: ^1.18.1 + is-glob: ^4.0.1 + is-plain-obj: ^3.0.0 + micromatch: ^4.0.2 + peerDependencies: + "@types/express": ^4.17.13 + peerDependenciesMeta: + "@types/express": + optional: true + checksum: 2ee85bc878afa6cbf34491e972ece0f5be0a3e5c98a60850cf40d2a9a5356e1fc57aab6cff33c1fc37691b0121c3a42602d2b1956c52577e87a5b77b62ae1c3a + languageName: node + linkType: hard + +"http-proxy@npm:^1.18.1": + version: 1.18.1 + resolution: "http-proxy@npm:1.18.1" + dependencies: + eventemitter3: ^4.0.0 + follow-redirects: ^1.0.0 + requires-port: ^1.0.0 + checksum: f5bd96bf83e0b1e4226633dbb51f8b056c3e6321917df402deacec31dd7fe433914fc7a2c1831cf7ae21e69c90b3a669b8f434723e9e8b71fd68afe30737b6a5 + languageName: node + linkType: hard + "https-proxy-agent@npm:5.0.1, https-proxy-agent@npm:^5.0.0": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" @@ -5245,6 +10527,15 @@ __metadata: languageName: node linkType: hard +"icss-utils@npm:^5.0.0, icss-utils@npm:^5.1.0": + version: 5.1.0 + resolution: "icss-utils@npm:5.1.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 5c324d283552b1269cfc13a503aaaa172a280f914e5b81544f3803bc6f06a3b585fb79f66f7c771a2c052db7982c18bf92d001e3b47282e3abbbb4c4cc488d68 + languageName: node + linkType: hard + "ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": version: 1.2.1 resolution: "ieee754@npm:1.2.1" @@ -5266,6 +10557,31 @@ __metadata: languageName: node linkType: hard +"image-size@npm:^1.0.1": + version: 1.0.2 + resolution: "image-size@npm:1.0.2" + dependencies: + queue: 6.0.2 + bin: + image-size: bin/image-size.js + checksum: 01745fdb47f87cecf538e69c63f9adc5bfab30a345345c2de91105f3afbd1bfcfba1256af02bf3323077b33b0004469a837e077bf0cbb9c907e9c1e9e7547585 + languageName: node + linkType: hard + +"immediate@npm:^3.2.3": + version: 3.3.0 + resolution: "immediate@npm:3.3.0" + checksum: 634b4305101e2452eba6c07d485bf3e415995e533c94b9c3ffbc37026fa1be34def6e4f2276b0dc2162a3f91628564a4bfb26280278b89d3ee54624e854d2f5f + languageName: node + linkType: hard + +"immer@npm:^9.0.7": + version: 9.0.21 + resolution: "immer@npm:9.0.21" + checksum: 70e3c274165995352f6936695f0ef4723c52c92c92dd0e9afdfe008175af39fa28e76aafb3a2ca9d57d1fb8f796efc4dd1e1cc36f18d33fa5b74f3dfb0375432 + languageName: node + linkType: hard + "immutable@npm:^4.0.0-rc.12": version: 4.3.4 resolution: "immutable@npm:4.3.4" @@ -5273,7 +10589,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -5283,6 +10599,13 @@ __metadata: languageName: node linkType: hard +"import-lazy@npm:^2.1.0": + version: 2.1.0 + resolution: "import-lazy@npm:2.1.0" + checksum: 05294f3b9dd4971d3a996f0d2f176410fb6745d491d6e73376429189f5c1c3d290548116b2960a7cf3e89c20cdf11431739d1d2d8c54b84061980795010e803a + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -5304,6 +10627,13 @@ __metadata: languageName: node linkType: hard +"infima@npm:0.2.0-alpha.43": + version: 0.2.0-alpha.43 + resolution: "infima@npm:0.2.0-alpha.43" + checksum: fc5f79240e940eddd750439511767092ccb4051e5e91d253ec7630a9e7ce691812da3aa0f05e46b4c0a95dbfadeae5714fd0073f8d2df12e5aaff0697a1d6aa2 + languageName: node + linkType: hard + "inflation@npm:^2.0.0": version: 2.0.0 resolution: "inflation@npm:2.0.0" @@ -5321,7 +10651,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4": +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.0, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 @@ -5335,6 +10665,27 @@ __metadata: languageName: node linkType: hard +"ini@npm:2.0.0": + version: 2.0.0 + resolution: "ini@npm:2.0.0" + checksum: e7aadc5fb2e4aefc666d74ee2160c073995a4061556b1b5b4241ecb19ad609243b9cceafe91bae49c219519394bbd31512516cb22a3b1ca6e66d869e0447e84e + languageName: node + linkType: hard + +"ini@npm:^1.3.5, ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: dfd98b0ca3a4fc1e323e38a6c8eb8936e31a97a918d3b377649ea15bdb15d481207a0dda1021efbd86b464cae29a0d33c1d7dcaf6c5672bee17fa849bc50a1b3 + languageName: node + linkType: hard + +"inline-style-parser@npm:0.1.1": + version: 0.1.1 + resolution: "inline-style-parser@npm:0.1.1" + checksum: 5d545056a3e1f2bf864c928a886a0e1656a3517127d36917b973de581bd54adc91b4bf1febcb0da054f204b4934763f1a4e09308b4d55002327cf1d48ac5d966 + languageName: node + linkType: hard + "integration-tests@workspace:compiler/integration-tests": version: 0.0.0-use.local resolution: "integration-tests@workspace:compiler/integration-tests" @@ -5359,6 +10710,22 @@ __metadata: languageName: unknown linkType: soft +"interpret@npm:^1.0.0": + version: 1.4.0 + resolution: "interpret@npm:1.4.0" + checksum: 2e5f51268b5941e4a17e4ef0575bc91ed0ab5f8515e3cf77486f7c14d13f3010df9c0959f37063dcc96e78d12dc6b0bb1b9e111cdfe69771f4656d2993d36155 + languageName: node + linkType: hard + +"invariant@npm:^2.2.4": + version: 2.2.4 + resolution: "invariant@npm:2.2.4" + dependencies: + loose-envify: ^1.0.0 + checksum: cc3182d793aad82a8d1f0af697b462939cb46066ec48bbf1707c150ad5fad6406137e91a262022c269702e01621f35ef60269f6c0d7fd178487959809acdfb14 + languageName: node + linkType: hard + "io-ts@npm:1.10.4": version: 1.10.4 resolution: "io-ts@npm:1.10.4" @@ -5382,6 +10749,20 @@ __metadata: languageName: node linkType: hard +"ipaddr.js@npm:1.9.1": + version: 1.9.1 + resolution: "ipaddr.js@npm:1.9.1" + checksum: f88d3825981486f5a1942414c8d77dd6674dd71c065adcfa46f578d677edcb99fda25af42675cb59db492fdf427b34a5abfcde3982da11a8fd83a500b41cfe77 + languageName: node + linkType: hard + +"ipaddr.js@npm:^2.0.1": + version: 2.1.0 + resolution: "ipaddr.js@npm:2.1.0" + checksum: 807a054f2bd720c4d97ee479d6c9e865c233bea21f139fb8dabd5a35c4226d2621c42e07b4ad94ff3f82add926a607d8d9d37c625ad0319f0e08f9f2bd1968e2 + languageName: node + linkType: hard + "irregular-plurals@npm:^3.3.0": version: 3.5.0 resolution: "irregular-plurals@npm:3.5.0" @@ -5389,6 +10770,30 @@ __metadata: languageName: node linkType: hard +"is-alphabetical@npm:1.0.4, is-alphabetical@npm:^1.0.0": + version: 1.0.4 + resolution: "is-alphabetical@npm:1.0.4" + checksum: 6508cce44fd348f06705d377b260974f4ce68c74000e7da4045f0d919e568226dc3ce9685c5a2af272195384df6930f748ce9213fc9f399b5d31b362c66312cb + languageName: node + linkType: hard + +"is-alphanumerical@npm:^1.0.0": + version: 1.0.4 + resolution: "is-alphanumerical@npm:1.0.4" + dependencies: + is-alphabetical: ^1.0.0 + is-decimal: ^1.0.0 + checksum: e2e491acc16fcf5b363f7c726f666a9538dba0a043665740feb45bba1652457a73441e7c5179c6768a638ed396db3437e9905f403644ec7c468fb41f4813d03f + languageName: node + linkType: hard + +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: eef4417e3c10e60e2c810b6084942b3ead455af16c4509959a27e490e7aee87cfb3f38e01bbde92220b528a0ee1a18d52b787e1458ee86174d8c7f0e58cd488f + languageName: node + linkType: hard + "is-binary-path@npm:~2.1.0": version: 2.1.0 resolution: "is-binary-path@npm:2.1.0" @@ -5398,7 +10803,7 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^2.0.5": +"is-buffer@npm:^2.0.0, is-buffer@npm:^2.0.5": version: 2.0.5 resolution: "is-buffer@npm:2.0.5" checksum: 764c9ad8b523a9f5a32af29bdf772b08eb48c04d2ad0a7240916ac2688c983bf5f8504bf25b35e66240edeb9d9085461f9b5dae1f3d2861c6b06a65fe983de42 @@ -5414,6 +10819,17 @@ __metadata: languageName: node linkType: hard +"is-ci@npm:^2.0.0": + version: 2.0.0 + resolution: "is-ci@npm:2.0.0" + dependencies: + ci-info: ^2.0.0 + bin: + is-ci: bin.js + checksum: 77b869057510f3efa439bbb36e9be429d53b3f51abd4776eeea79ab3b221337fe1753d1e50058a9e2c650d38246108beffb15ccfd443929d77748d8c0cc90144 + languageName: node + linkType: hard + "is-core-module@npm:^2.13.0": version: 2.13.0 resolution: "is-core-module@npm:2.13.0" @@ -5423,6 +10839,13 @@ __metadata: languageName: node linkType: hard +"is-decimal@npm:^1.0.0": + version: 1.0.4 + resolution: "is-decimal@npm:1.0.4" + checksum: ed483a387517856dc395c68403a10201fddcc1b63dc56513fbe2fe86ab38766120090ecdbfed89223d84ca8b1cd28b0641b93cb6597b6e8f4c097a7c24e3fb96 + languageName: node + linkType: hard + "is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": version: 2.2.1 resolution: "is-docker@npm:2.2.1" @@ -5448,6 +10871,13 @@ __metadata: languageName: node linkType: hard +"is-extendable@npm:^0.1.0": + version: 0.1.1 + resolution: "is-extendable@npm:0.1.1" + checksum: 3875571d20a7563772ecc7a5f36cb03167e9be31ad259041b4a8f73f33f885441f778cee1f1fe0085eb4bc71679b9d8c923690003a36a6a5fdf8023e6e3f0672 + languageName: node + linkType: hard + "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -5494,6 +10924,13 @@ __metadata: languageName: node linkType: hard +"is-hexadecimal@npm:^1.0.0": + version: 1.0.4 + resolution: "is-hexadecimal@npm:1.0.4" + checksum: a452e047587b6069332d83130f54d30da4faf2f2ebaa2ce6d073c27b5703d030d58ed9e0b729c8e4e5b52c6f1dab26781bb77b7bc6c7805f14f320e328ff8cd5 + languageName: node + linkType: hard + "is-inside-container@npm:^1.0.0": version: 1.0.0 resolution: "is-inside-container@npm:1.0.0" @@ -5505,6 +10942,16 @@ __metadata: languageName: node linkType: hard +"is-installed-globally@npm:^0.4.0": + version: 0.4.0 + resolution: "is-installed-globally@npm:0.4.0" + dependencies: + global-dirs: ^3.0.0 + is-path-inside: ^3.0.2 + checksum: 3359840d5982d22e9b350034237b2cda2a12bac1b48a721912e1ab8e0631dd07d45a2797a120b7b87552759a65ba03e819f1bd63f2d7ab8657ec0b44ee0bf399 + languageName: node + linkType: hard + "is-lambda@npm:^1.0.1": version: 1.0.1 resolution: "is-lambda@npm:1.0.1" @@ -5519,6 +10966,13 @@ __metadata: languageName: node linkType: hard +"is-npm@npm:^5.0.0": + version: 5.0.0 + resolution: "is-npm@npm:5.0.0" + checksum: 9baff02b0c69a3d3c79b162cb2f9e67fb40ef6d172c16601b2e2471c21e9a4fa1fc9885a308d7bc6f3a3cd2a324c27fa0bf284c133c3349bb22571ab70d041cc + languageName: node + linkType: hard + "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -5526,20 +10980,57 @@ __metadata: languageName: node linkType: hard -"is-path-inside@npm:^3.0.3": +"is-obj@npm:^1.0.1": + version: 1.0.1 + resolution: "is-obj@npm:1.0.1" + checksum: 3ccf0efdea12951e0b9c784e2b00e77e87b2f8bd30b42a498548a8afcc11b3287342a2030c308e473e93a7a19c9ea7854c99a8832a476591c727df2a9c79796c + languageName: node + linkType: hard + +"is-obj@npm:^2.0.0": + version: 2.0.0 + resolution: "is-obj@npm:2.0.0" + checksum: c9916ac8f4621962a42f5e80e7ffdb1d79a3fab7456ceaeea394cd9e0858d04f985a9ace45be44433bf605673c8be8810540fe4cc7f4266fc7526ced95af5a08 + languageName: node + linkType: hard + +"is-path-cwd@npm:^2.2.0": + version: 2.2.0 + resolution: "is-path-cwd@npm:2.2.0" + checksum: 46a840921bb8cc0dc7b5b423a14220e7db338072a4495743a8230533ce78812dc152548c86f4b828411fe98c5451959f07cf841c6a19f611e46600bd699e8048 + languageName: node + linkType: hard + +"is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 languageName: node linkType: hard -"is-plain-obj@npm:^2.1.0": +"is-plain-obj@npm:^2.0.0, is-plain-obj@npm:^2.1.0": version: 2.1.0 resolution: "is-plain-obj@npm:2.1.0" checksum: cec9100678b0a9fe0248a81743041ed990c2d4c99f893d935545cfbc42876cbe86d207f3b895700c690ad2fa520e568c44afc1605044b535a7820c1d40e38daa languageName: node linkType: hard +"is-plain-obj@npm:^3.0.0": + version: 3.0.0 + resolution: "is-plain-obj@npm:3.0.0" + checksum: a6ebdf8e12ab73f33530641972a72a4b8aed6df04f762070d823808303e4f76d87d5ea5bd76f96a7bbe83d93f04ac7764429c29413bd9049853a69cb630fb21c + languageName: node + linkType: hard + +"is-plain-object@npm:^2.0.4": + version: 2.0.4 + resolution: "is-plain-object@npm:2.0.4" + dependencies: + isobject: ^3.0.1 + checksum: 2a401140cfd86cabe25214956ae2cfee6fbd8186809555cd0e84574f88de7b17abacb2e477a6a658fa54c6083ecbda1e6ae404c7720244cd198903848fca70ca + languageName: node + linkType: hard + "is-plain-object@npm:^5.0.0": version: 5.0.0 resolution: "is-plain-object@npm:5.0.0" @@ -5554,6 +11045,20 @@ __metadata: languageName: node linkType: hard +"is-regexp@npm:^1.0.0": + version: 1.0.0 + resolution: "is-regexp@npm:1.0.0" + checksum: be692828e24cba479ec33644326fa98959ec68ba77965e0291088c1a741feaea4919d79f8031708f85fd25e39de002b4520622b55460660b9c369e6f7187faef + languageName: node + linkType: hard + +"is-root@npm:^2.1.0": + version: 2.1.0 + resolution: "is-root@npm:2.1.0" + checksum: 37eea0822a2a9123feb58a9d101558ba276771a6d830f87005683349a9acff15958a9ca590a44e778c6b335660b83e85c744789080d734f6081a935a4880aee2 + languageName: node + linkType: hard + "is-stream@npm:^2.0.0": version: 2.0.1 resolution: "is-stream@npm:2.0.1" @@ -5568,6 +11073,13 @@ __metadata: languageName: node linkType: hard +"is-typedarray@npm:^1.0.0": + version: 1.0.0 + resolution: "is-typedarray@npm:1.0.0" + checksum: 3508c6cd0a9ee2e0df2fa2e9baabcdc89e911c7bd5cf64604586697212feec525aa21050e48affb5ffc3df20f0f5d2e2cf79b08caa64e1ccc9578e251763aef7 + languageName: node + linkType: hard + "is-unicode-supported@npm:^0.1.0": version: 0.1.0 resolution: "is-unicode-supported@npm:0.1.0" @@ -5582,6 +11094,20 @@ __metadata: languageName: node linkType: hard +"is-whitespace-character@npm:^1.0.0": + version: 1.0.4 + resolution: "is-whitespace-character@npm:1.0.4" + checksum: adab8ad9847ccfcb6f1b7000b8f622881b5ba2a09ce8be2794a6d2b10c3af325b469fc562c9fb889f468eed27be06e227ac609d0aa1e3a59b4dbcc88e2b0418e + languageName: node + linkType: hard + +"is-word-character@npm:^1.0.0": + version: 1.0.4 + resolution: "is-word-character@npm:1.0.4" + checksum: 1821d6c6abe5bc0b3abe3fdc565d66d7c8a74ea4e93bc77b4a47d26e2e2a306d6ab7d92b353b0d2b182869e3ecaa8f4a346c62d0e31d38ebc0ceaf7cae182c3f + languageName: node + linkType: hard + "is-wsl@npm:^2.2.0": version: 2.2.0 resolution: "is-wsl@npm:2.2.0" @@ -5591,6 +11117,27 @@ __metadata: languageName: node linkType: hard +"is-yarn-global@npm:^0.3.0": + version: 0.3.0 + resolution: "is-yarn-global@npm:0.3.0" + checksum: bca013d65fee2862024c9fbb3ba13720ffca2fe750095174c1c80922fdda16402b5c233f5ac9e265bc12ecb5446e7b7f519a32d9541788f01d4d44e24d2bf481 + languageName: node + linkType: hard + +"isarray@npm:0.0.1": + version: 0.0.1 + resolution: "isarray@npm:0.0.1" + checksum: 49191f1425681df4a18c2f0f93db3adb85573bcdd6a4482539d98eac9e705d8961317b01175627e860516a2fc45f8f9302db26e5a380a97a520e272e2a40a8d4 + languageName: node + linkType: hard + +"isarray@npm:~1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab + languageName: node + linkType: hard + "isbinaryfile@npm:^5.0.0": version: 5.0.0 resolution: "isbinaryfile@npm:5.0.0" @@ -5605,6 +11152,13 @@ __metadata: languageName: node linkType: hard +"isobject@npm:^3.0.1": + version: 3.0.1 + resolution: "isobject@npm:3.0.1" + checksum: db85c4c970ce30693676487cca0e61da2ca34e8d4967c2e1309143ff910c207133a969f9e4ddb2dc6aba670aabce4e0e307146c310350b298e74a31f7d464703 + languageName: node + linkType: hard + "istanbul-lib-coverage@npm:^3.0.0": version: 3.2.0 resolution: "istanbul-lib-coverage@npm:3.2.0" @@ -5646,6 +11200,65 @@ __metadata: languageName: node linkType: hard +"jest-util@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-util@npm:29.7.0" + dependencies: + "@jest/types": ^29.6.3 + "@types/node": "*" + chalk: ^4.0.0 + ci-info: ^3.2.0 + graceful-fs: ^4.2.9 + picomatch: ^2.2.3 + checksum: 042ab4980f4ccd4d50226e01e5c7376a8556b472442ca6091a8f102488c0f22e6e8b89ea874111d2328a2080083bf3225c86f3788c52af0bd0345a00eb57a3ca + languageName: node + linkType: hard + +"jest-worker@npm:^27.4.5": + version: 27.5.1 + resolution: "jest-worker@npm:27.5.1" + dependencies: + "@types/node": "*" + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: 98cd68b696781caed61c983a3ee30bf880b5bd021c01d98f47b143d4362b85d0737f8523761e2713d45e18b4f9a2b98af1eaee77afade4111bb65c77d6f7c980 + languageName: node + linkType: hard + +"jest-worker@npm:^29.1.2": + version: 29.7.0 + resolution: "jest-worker@npm:29.7.0" + dependencies: + "@types/node": "*" + jest-util: ^29.7.0 + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: 30fff60af49675273644d408b650fc2eb4b5dcafc5a0a455f238322a8f9d8a98d847baca9d51ff197b6747f54c7901daa2287799230b856a0f48287d131f8c13 + languageName: node + linkType: hard + +"jiti@npm:^1.18.2": + version: 1.20.0 + resolution: "jiti@npm:1.20.0" + bin: + jiti: bin/jiti.js + checksum: 7924062b5675142e3e272a27735be84b7bfc0a0eb73217fc2dcafa034f37c4f7b4b9ffc07dd98bcff0f739a8811ce1544db205ae7e97b1c86f0df92c65ce3c72 + languageName: node + linkType: hard + +"joi@npm:^17.6.0": + version: 17.11.0 + resolution: "joi@npm:17.11.0" + dependencies: + "@hapi/hoek": ^9.0.0 + "@hapi/topo": ^5.0.0 + "@sideway/address": ^4.1.3 + "@sideway/formula": ^3.0.1 + "@sideway/pinpoint": ^2.0.0 + checksum: 3a4e9ecba345cdafe585e7ed8270a44b39718e11dff3749aa27e0001a63d578b75100c062be28e6f48f960b594864034e7a13833f33fbd7ad56d5ce6b617f9bf + languageName: node + linkType: hard + "js-sdsl@npm:^4.1.4": version: 4.4.2 resolution: "js-sdsl@npm:4.4.2" @@ -5667,7 +11280,7 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^4.0.0": +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 @@ -5685,7 +11298,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^3.14.1": +"js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.1": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" dependencies: @@ -5697,6 +11310,31 @@ __metadata: languageName: node linkType: hard +"jsesc@npm:^2.5.1": + version: 2.5.2 + resolution: "jsesc@npm:2.5.2" + bin: + jsesc: bin/jsesc + checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d + languageName: node + linkType: hard + +"jsesc@npm:~0.5.0": + version: 0.5.0 + resolution: "jsesc@npm:0.5.0" + bin: + jsesc: bin/jsesc + checksum: b8b44cbfc92f198ad972fba706ee6a1dfa7485321ee8c0b25f5cedd538dcb20cde3197de16a7265430fce8277a12db066219369e3d51055038946039f6e20e17 + languageName: node + linkType: hard + +"json-buffer@npm:3.0.0": + version: 3.0.0 + resolution: "json-buffer@npm:3.0.0" + checksum: 0cecacb8025370686a916069a2ff81f7d55167421b6aa7270ee74e244012650dd6bce22b0852202ea7ff8624fce50ff0ec1bdf95914ccb4553426e290d5a63fa + languageName: node + linkType: hard + "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -5704,6 +11342,13 @@ __metadata: languageName: node linkType: hard +"json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 798ed4cf3354a2d9ccd78e86d2169515a0097a5c133337807cdf7f1fc32e1391d207ccfc276518cc1d7d8d4db93288b8a50ba4293d212ad1336e52a8ec0a941f + languageName: node + linkType: hard + "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -5711,6 +11356,13 @@ __metadata: languageName: node linkType: hard +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad + languageName: node + linkType: hard + "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" @@ -5718,6 +11370,15 @@ __metadata: languageName: node linkType: hard +"json5@npm:^2.1.2, json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 + languageName: node + linkType: hard + "jsonfile@npm:^2.1.0": version: 2.4.0 resolution: "jsonfile@npm:2.4.0" @@ -5755,6 +11416,17 @@ __metadata: languageName: node linkType: hard +"katex@npm:^0.13.0": + version: 0.13.24 + resolution: "katex@npm:0.13.24" + dependencies: + commander: ^8.0.0 + bin: + katex: cli.js + checksum: 1b7c8295867073d0db4f6fb41ef1c0e3418b8e23924ff61b446b36134cb74cdadc7242dfbfb922d9c32f0b15eda6160a08cd30948c4e78141966ca2991a1726b + languageName: node + linkType: hard + "keccak@npm:^3.0.0, keccak@npm:^3.0.2": version: 3.0.4 resolution: "keccak@npm:3.0.4" @@ -5776,6 +11448,15 @@ __metadata: languageName: node linkType: hard +"keyv@npm:^3.0.0": + version: 3.1.0 + resolution: "keyv@npm:3.1.0" + dependencies: + json-buffer: 3.0.0 + checksum: bb7e8f3acffdbafbc2dd5b63f377fe6ec4c0e2c44fc82720449ef8ab54f4a7ce3802671ed94c0f475ae0a8549703353a2124561fcf3317010c141b32ca1ce903 + languageName: node + linkType: hard + "keyv@npm:^4.5.3": version: 4.5.3 resolution: "keyv@npm:4.5.3" @@ -5785,6 +11466,22 @@ __metadata: languageName: node linkType: hard +"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": + version: 6.0.3 + resolution: "kind-of@npm:6.0.3" + checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b + languageName: node + linkType: hard + +"klaw-sync@npm:^6.0.0": + version: 6.0.0 + resolution: "klaw-sync@npm:6.0.0" + dependencies: + graceful-fs: ^4.1.11 + checksum: 0da397f8961313c3ef8f79fb63af9002cde5a8fb2aeb1a37351feff0dd6006129c790400c3f5c3b4e757bedcabb13d21ec0a5eaef5a593d59515d4f2c291e475 + languageName: node + linkType: hard + "klaw@npm:^1.0.0": version: 1.3.1 resolution: "klaw@npm:1.3.1" @@ -5797,6 +11494,13 @@ __metadata: languageName: node linkType: hard +"kleur@npm:^3.0.3": + version: 3.0.3 + resolution: "kleur@npm:3.0.3" + checksum: df82cd1e172f957bae9c536286265a5cdbd5eeca487cb0a3b2a7b41ef959fc61f8e7c0e9aeea9c114ccf2c166b6a8dd45a46fd619c1c569d210ecd2765ad5169 + languageName: node + linkType: hard + "kleur@npm:^4.0.3": version: 4.1.5 resolution: "kleur@npm:4.1.5" @@ -5882,6 +11586,25 @@ __metadata: languageName: node linkType: hard +"latest-version@npm:^5.1.0": + version: 5.1.0 + resolution: "latest-version@npm:5.1.0" + dependencies: + package-json: ^6.3.0 + checksum: fbc72b071eb66c40f652441fd783a9cca62f08bf42433651937f078cd9ef94bf728ec7743992777826e4e89305aef24f234b515e6030503a2cbee7fc9bdc2c0f + languageName: node + linkType: hard + +"launch-editor@npm:^2.6.0": + version: 2.6.1 + resolution: "launch-editor@npm:2.6.1" + dependencies: + picocolors: ^1.0.0 + shell-quote: ^1.8.1 + checksum: e06d193075ac09f7f8109f10cabe464a211bf7ed4cbe75f83348d6f67bf4d9f162f06e7a1ab3e1cd7fc250b5342c3b57080618aff2e646dc34248fe499227601 + languageName: node + linkType: hard + "level-supports@npm:^4.0.0": version: 4.0.1 resolution: "level-supports@npm:4.0.1" @@ -5909,6 +11632,13 @@ __metadata: languageName: node linkType: hard +"leven@npm:^3.1.0": + version: 3.1.0 + resolution: "leven@npm:3.1.0" + checksum: 638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 + languageName: node + linkType: hard + "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1" @@ -5929,6 +11659,20 @@ __metadata: languageName: node linkType: hard +"lilconfig@npm:^2.0.3": + version: 2.1.0 + resolution: "lilconfig@npm:2.1.0" + checksum: 8549bb352b8192375fed4a74694cd61ad293904eee33f9d4866c2192865c44c4eb35d10782966242634e0cbc1e91fe62b1247f148dc5514918e3a966da7ea117 + languageName: node + linkType: hard + +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 + languageName: node + linkType: hard + "load-json-file@npm:^7.0.0": version: 7.0.1 resolution: "load-json-file@npm:7.0.1" @@ -5936,6 +11680,31 @@ __metadata: languageName: node linkType: hard +"loader-runner@npm:^4.2.0": + version: 4.3.0 + resolution: "loader-runner@npm:4.3.0" + checksum: a90e00dee9a16be118ea43fec3192d0b491fe03a32ed48a4132eb61d498f5536a03a1315531c19d284392a8726a4ecad71d82044c28d7f22ef62e029bf761569 + languageName: node + linkType: hard + +"loader-utils@npm:^2.0.0": + version: 2.0.4 + resolution: "loader-utils@npm:2.0.4" + dependencies: + big.js: ^5.2.2 + emojis-list: ^3.0.0 + json5: ^2.1.2 + checksum: a5281f5fff1eaa310ad5e1164095689443630f3411e927f95031ab4fb83b4a98f388185bb1fe949e8ab8d4247004336a625e9255c22122b815bb9a4c5d8fc3b7 + languageName: node + linkType: hard + +"loader-utils@npm:^3.2.0": + version: 3.2.1 + resolution: "loader-utils@npm:3.2.1" + checksum: 4e3ea054cdc8be1ab1f1238f49f42fdf0483039eff920fb1d442039f3f0ad4ebd11fb8e584ccdf2cb7e3c56b3d40c1832416e6408a55651b843da288960cc792 + languageName: node + linkType: hard + "locate-path@npm:^2.0.0": version: 2.0.0 resolution: "locate-path@npm:2.0.0" @@ -5946,6 +11715,25 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^3.0.0": + version: 3.0.0 + resolution: "locate-path@npm:3.0.0" + dependencies: + p-locate: ^3.0.0 + path-exists: ^3.0.0 + checksum: 53db3996672f21f8b0bf2a2c645ae2c13ffdae1eeecfcd399a583bce8516c0b88dcb4222ca6efbbbeb6949df7e46860895be2c02e8d3219abd373ace3bfb4e11 + languageName: node + linkType: hard + +"locate-path@npm:^5.0.0": + version: 5.0.0 + resolution: "locate-path@npm:5.0.0" + dependencies: + p-locate: ^4.1.0 + checksum: 83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 + languageName: node + linkType: hard + "locate-path@npm:^6.0.0": version: 6.0.0 resolution: "locate-path@npm:6.0.0" @@ -5978,6 +11766,48 @@ __metadata: languageName: node linkType: hard +"lodash.curry@npm:^4.0.1": + version: 4.1.1 + resolution: "lodash.curry@npm:4.1.1" + checksum: 9192b70fe7df4d1ff780c0260bee271afa9168c93fe4fa24bc861900240531b59781b5fdaadf4644fea8f4fbcd96f0700539ab294b579ffc1022c6c15dcc462a + languageName: node + linkType: hard + +"lodash.debounce@npm:^4.0.8": + version: 4.0.8 + resolution: "lodash.debounce@npm:4.0.8" + checksum: a3f527d22c548f43ae31c861ada88b2637eb48ac6aa3eb56e82d44917971b8aa96fbb37aa60efea674dc4ee8c42074f90f7b1f772e9db375435f6c83a19b3bc6 + languageName: node + linkType: hard + +"lodash.escape@npm:^4.0.1": + version: 4.0.1 + resolution: "lodash.escape@npm:4.0.1" + checksum: fcb54f457497256964d619d5cccbd80a961916fca60df3fe0fa3e7f052715c2944c0ed5aefb4f9e047d127d44aa2d55555f3350cb42c6549e9e293fb30b41e7f + languageName: node + linkType: hard + +"lodash.flatten@npm:^4.4.0": + version: 4.4.0 + resolution: "lodash.flatten@npm:4.4.0" + checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb + languageName: node + linkType: hard + +"lodash.flow@npm:^3.3.0": + version: 3.5.0 + resolution: "lodash.flow@npm:3.5.0" + checksum: a9a62ad344e3c5a1f42bc121da20f64dd855aaafecee24b1db640f29b88bd165d81c37ff7e380a7191de6f70b26f5918abcebbee8396624f78f3618a0b18634c + languageName: node + linkType: hard + +"lodash.invokemap@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.invokemap@npm:4.6.0" + checksum: 646ceebbefbcb6da301f8c2868254680fd0bcdc6ada470495d9ae49c9c32938829c1b38a38c95d0258409a9655f85db404b16e648381c7450b7ed3d9c52d8808 + languageName: node + linkType: hard + "lodash.isequal@npm:^4.5.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" @@ -5985,6 +11815,13 @@ __metadata: languageName: node linkType: hard +"lodash.memoize@npm:^4.1.2": + version: 4.1.2 + resolution: "lodash.memoize@npm:4.1.2" + checksum: 9ff3942feeccffa4f1fafa88d32f0d24fdc62fd15ded5a74a5f950ff5f0c6f61916157246744c620173dddf38d37095a92327d5fd3861e2063e736a5c207d089 + languageName: node + linkType: hard + "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" @@ -5992,7 +11829,28 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15": +"lodash.pullall@npm:^4.2.0": + version: 4.2.0 + resolution: "lodash.pullall@npm:4.2.0" + checksum: 7a5fbaedf186ec197ce1e0b9ba1d88a89773ebaf6a8291c7d273838cac59cb3b339cf36ef00e94172862ee84d2304c38face161846f08f5581d0553dcbdcd090 + languageName: node + linkType: hard + +"lodash.uniq@npm:4.5.0, lodash.uniq@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.uniq@npm:4.5.0" + checksum: a4779b57a8d0f3c441af13d9afe7ecff22dd1b8ce1129849f71d9bbc8e8ee4e46dfb4b7c28f7ad3d67481edd6e51126e4e2a6ee276e25906d10f7140187c392d + languageName: node + linkType: hard + +"lodash.uniqby@npm:^4.7.0": + version: 4.7.0 + resolution: "lodash.uniqby@npm:4.7.0" + checksum: 659264545a95726d1493123345aad8cbf56e17810fa9a0b029852c6d42bc80517696af09d99b23bef1845d10d95e01b8b4a1da578f22aeba7a30d3e0022a4938 + languageName: node + linkType: hard + +"lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -6021,6 +11879,17 @@ __metadata: languageName: node linkType: hard +"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: ^3.0.0 || ^4.0.0 + bin: + loose-envify: cli.js + checksum: 6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 + languageName: node + linkType: hard + "loupe@npm:^2.3.1": version: 2.3.6 resolution: "loupe@npm:2.3.6" @@ -6030,6 +11899,29 @@ __metadata: languageName: node linkType: hard +"lower-case@npm:^2.0.2": + version: 2.0.2 + resolution: "lower-case@npm:2.0.2" + dependencies: + tslib: ^2.0.3 + checksum: 83a0a5f159ad7614bee8bf976b96275f3954335a84fad2696927f609ddae902802c4f3312d86668722e668bef41400254807e1d3a7f2e8c3eede79691aa1f010 + languageName: node + linkType: hard + +"lowercase-keys@npm:^1.0.0, lowercase-keys@npm:^1.0.1": + version: 1.0.1 + resolution: "lowercase-keys@npm:1.0.1" + checksum: 4d045026595936e09953e3867722e309415ff2c80d7701d067546d75ef698dac218a4f53c6d1d0e7368b47e45fd7529df47e6cb56fbb90523ba599f898b3d147 + languageName: node + linkType: hard + +"lowercase-keys@npm:^2.0.0": + version: 2.0.0 + resolution: "lowercase-keys@npm:2.0.0" + checksum: 24d7ebd56ccdf15ff529ca9e08863f3c54b0b9d1edb97a3ae1af34940ae666c01a1e6d200707bce730a8ef76cb57cc10e65f245ecaaf7e6bc8639f2fb460ac23 + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -6076,6 +11968,29 @@ __metadata: languageName: node linkType: hard +"lunr-languages@npm:^1.4.0": + version: 1.14.0 + resolution: "lunr-languages@npm:1.14.0" + checksum: 05dd6338af6897932f64f9cb735d5b48f9905d892499b22a3f3abc279b2ac71a6bce0fdfe59c01464c6ad3f8e44e2956ba0637f092535239793bbadf4540e72d + languageName: node + linkType: hard + +"lunr@npm:^2.3.9": + version: 2.3.9 + resolution: "lunr@npm:2.3.9" + checksum: 176719e24fcce7d3cf1baccce9dd5633cd8bdc1f41ebe6a180112e5ee99d80373fe2454f5d4624d437e5a8319698ca6837b9950566e15d2cae5f2a543a3db4b8 + languageName: node + linkType: hard + +"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2, make-dir@npm:^3.1.0": + version: 3.1.0 + resolution: "make-dir@npm:3.1.0" + dependencies: + semver: ^6.0.0 + checksum: 484200020ab5a1fdf12f393fe5f385fc8e4378824c940fba1729dcd198ae4ff24867bc7a5646331e50cead8abff5d9270c456314386e629acec6dff4b8016b78 + languageName: node + linkType: hard + "make-dir@npm:^4.0.0": version: 4.0.0 resolution: "make-dir@npm:4.0.0" @@ -6131,6 +12046,20 @@ __metadata: languageName: node linkType: hard +"mark.js@npm:^8.11.1": + version: 8.11.1 + resolution: "mark.js@npm:8.11.1" + checksum: aa6b9ae1c67245348d5b7abd253ef2acd6bb05c6be358d7d192416d964e42665fc10e0e865591c6f93ab9b57e8da1f23c23216e8ebddb580905ea7a0c0df15d4 + languageName: node + linkType: hard + +"markdown-escapes@npm:^1.0.0": + version: 1.0.4 + resolution: "markdown-escapes@npm:1.0.4" + checksum: 6833a93d72d3f70a500658872312c6fa8015c20cc835a85ae6901fa232683fbc6ed7118ebe920fea7c80039a560f339c026597d96eee0e9de602a36921804997 + languageName: node + linkType: hard + "marky@npm:^1.2.2": version: 1.2.5 resolution: "marky@npm:1.2.5" @@ -6174,6 +12103,61 @@ __metadata: languageName: node linkType: hard +"mdast-squeeze-paragraphs@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-squeeze-paragraphs@npm:4.0.0" + dependencies: + unist-util-remove: ^2.0.0 + checksum: dfe8ec8e8a62171f020e82b088cc35cb9da787736dc133a3b45ce8811782a93e69bf06d147072e281079f09fac67be8a36153ffffd9bfbf89ed284e4c4f56f75 + languageName: node + linkType: hard + +"mdast-util-definitions@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-util-definitions@npm:4.0.0" + dependencies: + unist-util-visit: ^2.0.0 + checksum: 2325f20b82b3fb8cb5fda77038ee0bbdd44f82cfca7c48a854724b58bc1fe5919630a3ce7c45e210726df59d46c881d020b2da7a493bfd1ee36eb2bbfef5d78e + languageName: node + linkType: hard + +"mdast-util-to-hast@npm:10.0.1": + version: 10.0.1 + resolution: "mdast-util-to-hast@npm:10.0.1" + dependencies: + "@types/mdast": ^3.0.0 + "@types/unist": ^2.0.0 + mdast-util-definitions: ^4.0.0 + mdurl: ^1.0.0 + unist-builder: ^2.0.0 + unist-util-generated: ^1.0.0 + unist-util-position: ^3.0.0 + unist-util-visit: ^2.0.0 + checksum: e5f385757df7e9b37db4d6f326bf7b4fc1b40f9ad01fc335686578f44abe0ba46d3e60af4d5e5b763556d02e65069ef9a09c49db049b52659203a43e7fa9084d + languageName: node + linkType: hard + +"mdast-util-to-string@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-to-string@npm:2.0.0" + checksum: 0b2113ada10e002fbccb014170506dabe2f2ddacaacbe4bc1045c33f986652c5a162732a2c057c5335cdb58419e2ad23e368e5be226855d4d4e280b81c4e9ec2 + languageName: node + linkType: hard + +"mdn-data@npm:2.0.14": + version: 2.0.14 + resolution: "mdn-data@npm:2.0.14" + checksum: 9d0128ed425a89f4cba8f787dca27ad9408b5cb1b220af2d938e2a0629d17d879a34d2cb19318bdb26c3f14c77dd5dfbae67211f5caaf07b61b1f2c5c8c7dc16 + languageName: node + linkType: hard + +"mdurl@npm:^1.0.0": + version: 1.0.1 + resolution: "mdurl@npm:1.0.1" + checksum: 71731ecba943926bfbf9f9b51e28b5945f9411c4eda80894221b47cc105afa43ba2da820732b436f0798fd3edbbffcd1fc1415843c41a87fea08a41cc1e3d02b + languageName: node + linkType: hard + "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" @@ -6191,6 +12175,15 @@ __metadata: languageName: node linkType: hard +"memfs@npm:^3.1.2, memfs@npm:^3.4.3": + version: 3.5.3 + resolution: "memfs@npm:3.5.3" + dependencies: + fs-monkey: ^1.0.4 + checksum: 18dfdeacad7c8047b976a6ccd58bc98ba76e122ad3ca0e50a21837fe2075fc0d9aafc58ab9cf2576c2b6889da1dd2503083f2364191b695273f40969db2ecc44 + languageName: node + linkType: hard + "memory-level@npm:^1.0.0": version: 1.0.0 resolution: "memory-level@npm:1.0.0" @@ -6209,6 +12202,13 @@ __metadata: languageName: node linkType: hard +"merge-descriptors@npm:1.0.1": + version: 1.0.1 + resolution: "merge-descriptors@npm:1.0.1" + checksum: 5abc259d2ae25bb06d19ce2b94a21632583c74e2a9109ee1ba7fd147aa7362b380d971e0251069f8b3eb7d48c21ac839e21fa177b335e82c76ec172e30c31a26 + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -6223,7 +12223,14 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.4": +"methods@npm:~1.1.2": + version: 1.1.2 + resolution: "methods@npm:1.1.2" + checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a + languageName: node + linkType: hard + +"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5" dependencies: @@ -6233,14 +12240,30 @@ __metadata: languageName: node linkType: hard -"mime-db@npm:1.52.0": +"mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": version: 1.52.0 resolution: "mime-db@npm:1.52.0" checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f languageName: node linkType: hard -"mime-types@npm:^2.1.18, mime-types@npm:^2.1.27, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-db@npm:~1.33.0": + version: 1.33.0 + resolution: "mime-db@npm:1.33.0" + checksum: 281a0772187c9b8f6096976cb193ac639c6007ac85acdbb8dc1617ed7b0f4777fa001d1b4f1b634532815e60717c84b2f280201d55677fb850c9d45015b50084 + languageName: node + linkType: hard + +"mime-types@npm:2.1.18": + version: 2.1.18 + resolution: "mime-types@npm:2.1.18" + dependencies: + mime-db: ~1.33.0 + checksum: 729265eff1e5a0e87cb7f869da742a610679585167d2f2ec997a7387fc6aedf8e5cad078e99b0164a927bdf3ace34fca27430d6487456ad090cba5594441ba43 + languageName: node + linkType: hard + +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.18, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -6249,6 +12272,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:1.6.0": + version: 1.6.0 + resolution: "mime@npm:1.6.0" + bin: + mime: cli.js + checksum: fef25e39263e6d207580bdc629f8872a3f9772c923c7f8c7e793175cee22777bbe8bba95e5d509a40aaa292d8974514ce634ae35769faa45f22d17edda5e8557 + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -6263,6 +12295,24 @@ __metadata: languageName: node linkType: hard +"mimic-response@npm:^1.0.0, mimic-response@npm:^1.0.1": + version: 1.0.1 + resolution: "mimic-response@npm:1.0.1" + checksum: 034c78753b0e622bc03c983663b1cdf66d03861050e0c8606563d149bc2b02d63f62ce4d32be4ab50d0553ae0ffe647fc34d1f5281184c6e1e8cf4d85e8d9823 + languageName: node + linkType: hard + +"mini-css-extract-plugin@npm:^2.6.1": + version: 2.7.6 + resolution: "mini-css-extract-plugin@npm:2.7.6" + dependencies: + schema-utils: ^4.0.0 + peerDependencies: + webpack: ^5.0.0 + checksum: be6f7cefc6275168eb0a6b8fe977083a18c743c9612c9f00e6c1a62c3393ca7960e93fba1a7ebb09b75f36a0204ad087d772c1ef574bc29c90c0e8175a3c0b83 + languageName: node + linkType: hard + "minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": version: 1.0.1 resolution: "minimalistic-assert@npm:1.0.1" @@ -6277,6 +12327,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:3.1.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: ^1.1.7 + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a + languageName: node + linkType: hard + "minimatch@npm:5.0.1": version: 5.0.1 resolution: "minimatch@npm:5.0.1" @@ -6286,15 +12345,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a - languageName: node - linkType: hard - "minimatch@npm:^9.0.1": version: 9.0.3 resolution: "minimatch@npm:9.0.3" @@ -6304,7 +12354,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.6": +"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 @@ -6484,6 +12534,13 @@ __metadata: languageName: node linkType: hard +"mrmime@npm:^1.0.0": + version: 1.0.1 + resolution: "mrmime@npm:1.0.1" + checksum: cc979da44bbbffebaa8eaf7a45117e851f2d4cb46a3ada6ceb78130466a04c15a0de9a9ce1c8b8ba6f6e1b8618866b1352992bf1757d241c0ddca558b9f28a77 + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -6505,6 +12562,18 @@ __metadata: languageName: node linkType: hard +"multicast-dns@npm:^7.2.5": + version: 7.2.5 + resolution: "multicast-dns@npm:7.2.5" + dependencies: + dns-packet: ^5.2.2 + thunky: ^1.0.2 + bin: + multicast-dns: cli.js + checksum: 00b8a57df152d4cd0297946320a94b7c3cdf75a46a2247f32f958a8927dea42958177f9b7fdae69fab2e4e033fb3416881af1f5e9055a3e1542888767139e2fb + languageName: node + linkType: hard + "nanocolors@npm:^0.2.1": version: 0.2.13 resolution: "nanocolors@npm:0.2.13" @@ -6521,7 +12590,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.25": +"nanoid@npm:^3.1.25, nanoid@npm:^3.3.6": version: 3.3.6 resolution: "nanoid@npm:3.3.6" bin: @@ -6551,6 +12620,23 @@ __metadata: languageName: node linkType: hard +"neo-async@npm:^2.6.2": + version: 2.6.2 + resolution: "neo-async@npm:2.6.2" + checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 + languageName: node + linkType: hard + +"no-case@npm:^3.0.4": + version: 3.0.4 + resolution: "no-case@npm:3.0.4" + dependencies: + lower-case: ^2.0.2 + tslib: ^2.0.3 + checksum: 0b2ebc113dfcf737d48dde49cfebf3ad2d82a8c3188e7100c6f375e30eafbef9e9124aadc3becef237b042fd5eb0aad2fd78669c20972d045bbe7fea8ba0be5c + languageName: node + linkType: hard + "node-addon-api@npm:^2.0.0": version: 2.0.2 resolution: "node-addon-api@npm:2.0.2" @@ -6567,6 +12653,15 @@ __metadata: languageName: node linkType: hard +"node-emoji@npm:^1.10.0": + version: 1.11.0 + resolution: "node-emoji@npm:1.11.0" + dependencies: + lodash: ^4.17.21 + checksum: e8c856c04a1645062112a72e59a98b203505ed5111ff84a3a5f40611afa229b578c7d50f1e6a7f17aa62baeea4a640d2e2f61f63afc05423aa267af10977fb2b + languageName: node + linkType: hard + "node-fetch@npm:2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" @@ -6592,6 +12687,27 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^2.6.12": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" + dependencies: + whatwg-url: ^5.0.0 + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 + languageName: node + linkType: hard + +"node-forge@npm:^1": + version: 1.3.1 + resolution: "node-forge@npm:1.3.1" + checksum: 08fb072d3d670599c89a1704b3e9c649ff1b998256737f0e06fbd1a5bf41cae4457ccaee32d95052d80bbafd9ffe01284e078c8071f0267dc9744e51c5ed42a9 + languageName: node + linkType: hard + "node-gyp-build@npm:^4.2.0, node-gyp-build@npm:^4.3.0": version: 4.6.1 resolution: "node-gyp-build@npm:4.6.1" @@ -6624,6 +12740,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.13": + version: 2.0.13 + resolution: "node-releases@npm:2.0.13" + checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 + languageName: node + linkType: hard + "nofilter@npm:^3.1.0": version: 3.1.0 resolution: "nofilter@npm:3.1.0" @@ -6649,6 +12772,27 @@ __metadata: languageName: node linkType: hard +"normalize-range@npm:^0.1.2": + version: 0.1.2 + resolution: "normalize-range@npm:0.1.2" + checksum: 9b2f14f093593f367a7a0834267c24f3cb3e887a2d9809c77d8a7e5fd08738bcd15af46f0ab01cc3a3d660386f015816b5c922cea8bf2ee79777f40874063184 + languageName: node + linkType: hard + +"normalize-url@npm:^4.1.0": + version: 4.5.1 + resolution: "normalize-url@npm:4.5.1" + checksum: 9a9dee01df02ad23e171171893e56e22d752f7cff86fb96aafeae074819b572ea655b60f8302e2d85dbb834dc885c972cc1c573892fea24df46b2765065dd05a + languageName: node + linkType: hard + +"normalize-url@npm:^6.0.1": + version: 6.1.0 + resolution: "normalize-url@npm:6.1.0" + checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 + languageName: node + linkType: hard + "npm-run-path@npm:^4.0.1": version: 4.0.1 resolution: "npm-run-path@npm:4.0.1" @@ -6679,6 +12823,29 @@ __metadata: languageName: node linkType: hard +"nprogress@npm:^0.2.0": + version: 0.2.0 + resolution: "nprogress@npm:0.2.0" + checksum: 66b7bec5d563ecf2d1c3d2815e6d5eb74ed815eee8563e0afa63d3f185ab1b9cf2ddd97e1ded263b9995c5019d26d600320e849e50f3747984daa033744619dc + languageName: node + linkType: hard + +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: ^1.0.0 + checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 + languageName: node + linkType: hard + +"object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f + languageName: node + linkType: hard + "object-inspect@npm:^1.9.0": version: 1.12.3 resolution: "object-inspect@npm:1.12.3" @@ -6686,6 +12853,25 @@ __metadata: languageName: node linkType: hard +"object-keys@npm:^1.1.1": + version: 1.1.1 + resolution: "object-keys@npm:1.1.1" + checksum: b363c5e7644b1e1b04aa507e88dcb8e3a2f52b6ffd0ea801e4c7a62d5aa559affe21c55a07fd4b1fd55fc03a33c610d73426664b20032405d7b92a1414c34d6a + languageName: node + linkType: hard + +"object.assign@npm:^4.1.0": + version: 4.1.4 + resolution: "object.assign@npm:4.1.4" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + has-symbols: ^1.0.3 + object-keys: ^1.1.1 + checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 + languageName: node + linkType: hard + "obliterator@npm:^2.0.0": version: 2.0.4 resolution: "obliterator@npm:2.0.4" @@ -6693,7 +12879,14 @@ __metadata: languageName: node linkType: hard -"on-finished@npm:^2.3.0": +"obuf@npm:^1.0.0, obuf@npm:^1.1.2": + version: 1.1.2 + resolution: "obuf@npm:1.1.2" + checksum: 41a2ba310e7b6f6c3b905af82c275bf8854896e2e4c5752966d64cbcd2f599cfffd5932006bcf3b8b419dfdacebb3a3912d5d94e10f1d0acab59876c8757f27f + languageName: node + linkType: hard + +"on-finished@npm:2.4.1, on-finished@npm:^2.3.0": version: 2.4.1 resolution: "on-finished@npm:2.4.1" dependencies: @@ -6702,6 +12895,13 @@ __metadata: languageName: node linkType: hard +"on-headers@npm:~1.0.2": + version: 1.0.2 + resolution: "on-headers@npm:1.0.2" + checksum: 2bf13467215d1e540a62a75021e8b318a6cfc5d4fc53af8e8f84ad98dbcea02d506c6d24180cd62e1d769c44721ba542f3154effc1f7579a8288c9f7873ed8e5 + languageName: node + linkType: hard + "once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -6736,7 +12936,7 @@ __metadata: languageName: node linkType: hard -"open@npm:^8.0.2": +"open@npm:^8.0.2, open@npm:^8.0.9, open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" dependencies: @@ -6759,6 +12959,15 @@ __metadata: languageName: node linkType: hard +"opener@npm:^1.5.2": + version: 1.5.2 + resolution: "opener@npm:1.5.2" + bin: + opener: bin/opener-bin.js + checksum: 33b620c0d53d5b883f2abc6687dd1c5fd394d270dbe33a6356f2d71e0a2ec85b100d5bac94694198ccf5c30d592da863b2292c5539009c715a9c80c697b4f6cc + languageName: node + linkType: hard + "optionator@npm:^0.9.3": version: 0.9.3 resolution: "optionator@npm:0.9.3" @@ -6796,6 +13005,13 @@ __metadata: languageName: node linkType: hard +"p-cancelable@npm:^1.0.0": + version: 1.1.0 + resolution: "p-cancelable@npm:1.1.0" + checksum: 2db3814fef6d9025787f30afaee4496a8857a28be3c5706432cbad76c688a6db1874308f48e364a42f5317f5e41e8e7b4f2ff5c8ff2256dbb6264bc361704ece + languageName: node + linkType: hard + "p-defer@npm:^1.0.0": version: 1.0.0 resolution: "p-defer@npm:1.0.0" @@ -6821,6 +13037,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^2.0.0, p-limit@npm:^2.2.0": + version: 2.3.0 + resolution: "p-limit@npm:2.3.0" + dependencies: + p-try: ^2.0.0 + checksum: 84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 + languageName: node + linkType: hard + "p-limit@npm:^3.0.2": version: 3.1.0 resolution: "p-limit@npm:3.1.0" @@ -6848,6 +13073,24 @@ __metadata: languageName: node linkType: hard +"p-locate@npm:^3.0.0": + version: 3.0.0 + resolution: "p-locate@npm:3.0.0" + dependencies: + p-limit: ^2.0.0 + checksum: 83991734a9854a05fe9dbb29f707ea8a0599391f52daac32b86f08e21415e857ffa60f0e120bfe7ce0cc4faf9274a50239c7895fc0d0579d08411e513b83a4ae + languageName: node + linkType: hard + +"p-locate@npm:^4.1.0": + version: 4.1.0 + resolution: "p-locate@npm:4.1.0" + dependencies: + p-limit: ^2.2.0 + checksum: 513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 + languageName: node + linkType: hard + "p-locate@npm:^5.0.0": version: 5.0.0 resolution: "p-locate@npm:5.0.0" @@ -6884,6 +13127,16 @@ __metadata: languageName: node linkType: hard +"p-retry@npm:^4.5.0": + version: 4.6.2 + resolution: "p-retry@npm:4.6.2" + dependencies: + "@types/retry": 0.12.0 + retry: ^0.13.1 + checksum: 45c270bfddaffb4a895cea16cb760dcc72bdecb6cb45fef1971fa6ea2e91ddeafddefe01e444ac73e33b1b3d5d29fb0dd18a7effb294262437221ddc03ce0f2e + languageName: node + linkType: hard + "p-timeout@npm:^5.0.2": version: 5.1.0 resolution: "p-timeout@npm:5.1.0" @@ -6898,6 +13151,35 @@ __metadata: languageName: node linkType: hard +"p-try@npm:^2.0.0": + version: 2.2.0 + resolution: "p-try@npm:2.2.0" + checksum: f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae + languageName: node + linkType: hard + +"package-json@npm:^6.3.0": + version: 6.5.0 + resolution: "package-json@npm:6.5.0" + dependencies: + got: ^9.6.0 + registry-auth-token: ^4.0.0 + registry-url: ^5.0.0 + semver: ^6.2.0 + checksum: cc9f890d3667d7610e6184decf543278b87f657d1ace0deb4a9c9155feca738ef88f660c82200763d3348010f4e42e9c7adc91e96ab0f86a770955995b5351e2 + languageName: node + linkType: hard + +"param-case@npm:^3.0.4": + version: 3.0.4 + resolution: "param-case@npm:3.0.4" + dependencies: + dot-case: ^3.0.4 + tslib: ^2.0.3 + checksum: b34227fd0f794e078776eb3aa6247442056cb47761e9cd2c4c881c86d84c64205f6a56ef0d70b41ee7d77da02c3f4ed2f88e3896a8fefe08bdfb4deca037c687 + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -6907,6 +13189,32 @@ __metadata: languageName: node linkType: hard +"parse-entities@npm:^2.0.0": + version: 2.0.0 + resolution: "parse-entities@npm:2.0.0" + dependencies: + character-entities: ^1.0.0 + character-entities-legacy: ^1.0.0 + character-reference-invalid: ^1.0.0 + is-alphanumerical: ^1.0.0 + is-decimal: ^1.0.0 + is-hexadecimal: ^1.0.0 + checksum: 7addfd3e7d747521afac33c8121a5f23043c6973809756920d37e806639b4898385d386fcf4b3c8e2ecf1bc28aac5ae97df0b112d5042034efbe80f44081ebce + languageName: node + linkType: hard + +"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" + dependencies: + "@babel/code-frame": ^7.0.0 + error-ex: ^1.3.1 + json-parse-even-better-errors: ^2.3.0 + lines-and-columns: ^1.1.6 + checksum: 62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 + languageName: node + linkType: hard + "parse-ms@npm:^3.0.0": version: 3.0.0 resolution: "parse-ms@npm:3.0.0" @@ -6914,20 +13222,56 @@ __metadata: languageName: node linkType: hard -"parse5@npm:^6.0.1": +"parse-numeric-range@npm:^1.3.0": + version: 1.3.0 + resolution: "parse-numeric-range@npm:1.3.0" + checksum: 289ca126d5b8ace7325b199218de198014f58ea6895ccc88a5247491d07f0143bf047f80b4a31784f1ca8911762278d7d6ecb90a31dfae31da91cc1a2524c8ce + languageName: node + linkType: hard + +"parse5-htmlparser2-tree-adapter@npm:^7.0.0": + version: 7.0.0 + resolution: "parse5-htmlparser2-tree-adapter@npm:7.0.0" + dependencies: + domhandler: ^5.0.2 + parse5: ^7.0.0 + checksum: fc5d01e07733142a1baf81de5c2a9c41426c04b7ab29dd218acb80cd34a63177c90aff4a4aee66cf9f1d0aeecff1389adb7452ad6f8af0a5888e3e9ad6ef733d + languageName: node + linkType: hard + +"parse5@npm:^6.0.0, parse5@npm:^6.0.1": version: 6.0.1 resolution: "parse5@npm:6.0.1" checksum: 7d569a176c5460897f7c8f3377eff640d54132b9be51ae8a8fa4979af940830b2b0c296ce75e5bd8f4041520aadde13170dbdec44889975f906098ea0002f4bd languageName: node linkType: hard -"parseurl@npm:^1.3.2": +"parse5@npm:^7.0.0": + version: 7.1.2 + resolution: "parse5@npm:7.1.2" + dependencies: + entities: ^4.4.0 + checksum: 59465dd05eb4c5ec87b76173d1c596e152a10e290b7abcda1aecf0f33be49646ea74840c69af975d7887543ea45564801736356c568d6b5e71792fd0f4055713 + languageName: node + linkType: hard + +"parseurl@npm:^1.3.2, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" checksum: 407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 languageName: node linkType: hard +"pascal-case@npm:^3.1.2": + version: 3.1.2 + resolution: "pascal-case@npm:3.1.2" + dependencies: + no-case: ^3.0.4 + tslib: ^2.0.3 + checksum: ba98bfd595fc91ef3d30f4243b1aee2f6ec41c53b4546bfa3039487c367abaa182471dcfc830a1f9e1a0df00c14a370514fa2b3a1aacc68b15a460c31116873e + languageName: node + linkType: hard + "path-exists@npm:^3.0.0": version: 3.0.0 resolution: "path-exists@npm:3.0.0" @@ -6956,6 +13300,13 @@ __metadata: languageName: node linkType: hard +"path-is-inside@npm:1.0.2": + version: 1.0.2 + resolution: "path-is-inside@npm:1.0.2" + checksum: 0b5b6c92d3018b82afb1f74fe6de6338c4c654de4a96123cb343f2b747d5606590ac0c890f956ed38220a4ab59baddfd7b713d78a62d240b20b14ab801fa02cb + languageName: node + linkType: hard + "path-key@npm:^3.0.0, path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -6987,6 +13338,29 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:0.1.7": + version: 0.1.7 + resolution: "path-to-regexp@npm:0.1.7" + checksum: 69a14ea24db543e8b0f4353305c5eac6907917031340e5a8b37df688e52accd09e3cebfe1660b70d76b6bd89152f52183f28c74813dbf454ba1a01c82a38abce + languageName: node + linkType: hard + +"path-to-regexp@npm:2.2.1": + version: 2.2.1 + resolution: "path-to-regexp@npm:2.2.1" + checksum: b921a74e7576e25b06ad1635abf7e8125a29220d2efc2b71d74b9591f24a27e6f09078fa9a1b27516a097ea0637b7cab79d19b83d7f36a8ef3ef5422770e89d9 + languageName: node + linkType: hard + +"path-to-regexp@npm:^1.7.0": + version: 1.8.0 + resolution: "path-to-regexp@npm:1.8.0" + dependencies: + isarray: 0.0.1 + checksum: 709f6f083c0552514ef4780cb2e7e4cf49b0cc89a97439f2b7cc69a608982b7690fb5d1720a7473a59806508fc2dae0be751ba49f495ecf89fd8fbc62abccbcd + languageName: node + linkType: hard + "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -7037,7 +13411,7 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.3.1": +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf @@ -7054,6 +13428,24 @@ __metadata: languageName: node linkType: hard +"pkg-dir@npm:^4.1.0": + version: 4.2.0 + resolution: "pkg-dir@npm:4.2.0" + dependencies: + find-up: ^4.0.0 + checksum: 9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 + languageName: node + linkType: hard + +"pkg-up@npm:^3.1.0": + version: 3.1.0 + resolution: "pkg-up@npm:3.1.0" + dependencies: + find-up: ^3.0.0 + checksum: 5bac346b7c7c903613c057ae3ab722f320716199d753f4a7d053d38f2b5955460f3e6ab73b4762c62fd3e947f58e04f1343e92089e7bb6091c90877406fcd8c8 + languageName: node + linkType: hard + "playwright-core@npm:1.38.0": version: 1.38.0 resolution: "playwright-core@npm:1.38.0" @@ -7091,10 +13483,455 @@ __metadata: version: 1.0.32 resolution: "portfinder@npm:1.0.32" dependencies: - async: ^2.6.4 - debug: ^3.2.7 - mkdirp: ^0.5.6 - checksum: 116b4aed1b9e16f6d5503823d966d9ffd41b1c2339e27f54c06cd2f3015a9d8ef53e2a53b57bc0a25af0885977b692007353aa28f9a0a98a44335cb50487240d + async: ^2.6.4 + debug: ^3.2.7 + mkdirp: ^0.5.6 + checksum: 116b4aed1b9e16f6d5503823d966d9ffd41b1c2339e27f54c06cd2f3015a9d8ef53e2a53b57bc0a25af0885977b692007353aa28f9a0a98a44335cb50487240d + languageName: node + linkType: hard + +"postcss-calc@npm:^8.2.3": + version: 8.2.4 + resolution: "postcss-calc@npm:8.2.4" + dependencies: + postcss-selector-parser: ^6.0.9 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.2 + checksum: 314b4cebb0c4ed0cf8356b4bce71eca78f5a7842e6a3942a3bba49db168d5296b2bd93c3f735ae1c616f2651d94719ade33becc03c73d2d79c7394fb7f73eabb + languageName: node + linkType: hard + +"postcss-colormin@npm:^5.3.1": + version: 5.3.1 + resolution: "postcss-colormin@npm:5.3.1" + dependencies: + browserslist: ^4.21.4 + caniuse-api: ^3.0.0 + colord: ^2.9.1 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: e5778baab30877cd1f51e7dc9d2242a162aeca6360a52956acd7f668c5bc235c2ccb7e4df0370a804d65ebe00c5642366f061db53aa823f9ed99972cebd16024 + languageName: node + linkType: hard + +"postcss-convert-values@npm:^5.1.3": + version: 5.1.3 + resolution: "postcss-convert-values@npm:5.1.3" + dependencies: + browserslist: ^4.21.4 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: df48cdaffabf9737f9cfdc58a3dc2841cf282506a7a944f6c70236cff295d3a69f63de6e0935eeb8a9d3f504324e5b4e240abc29e21df9e35a02585d3060aeb5 + languageName: node + linkType: hard + +"postcss-discard-comments@npm:^5.1.2": + version: 5.1.2 + resolution: "postcss-discard-comments@npm:5.1.2" + peerDependencies: + postcss: ^8.2.15 + checksum: abfd064ebc27aeaf5037643dd51ffaff74d1fa4db56b0523d073ace4248cbb64ffd9787bd6924b0983a9d0bd0e9bf9f10d73b120e50391dc236e0d26c812fa2a + languageName: node + linkType: hard + +"postcss-discard-duplicates@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-discard-duplicates@npm:5.1.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 88d6964201b1f4ed6bf7a32cefe68e86258bb6e42316ca01d9b32bdb18e7887d02594f89f4a2711d01b51ea6e3fcca8c54be18a59770fe5f4521c61d3eb6ca35 + languageName: node + linkType: hard + +"postcss-discard-empty@npm:^5.1.1": + version: 5.1.1 + resolution: "postcss-discard-empty@npm:5.1.1" + peerDependencies: + postcss: ^8.2.15 + checksum: 970adb12fae5c214c0768236ad9a821552626e77dedbf24a8213d19cc2c4a531a757cd3b8cdd3fc22fb1742471b8692a1db5efe436a71236dec12b1318ee8ff4 + languageName: node + linkType: hard + +"postcss-discard-overridden@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-discard-overridden@npm:5.1.0" + peerDependencies: + postcss: ^8.2.15 + checksum: d64d4a545aa2c81b22542895cfcddc787d24119f294d35d29b0599a1c818b3cc51f4ee80b80f5a0a09db282453dd5ac49f104c2117cc09112d0ac9b40b499a41 + languageName: node + linkType: hard + +"postcss-discard-unused@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-discard-unused@npm:5.1.0" + dependencies: + postcss-selector-parser: ^6.0.5 + peerDependencies: + postcss: ^8.2.15 + checksum: 5c09403a342a065033f5f22cefe6b402c76c2dc0aac31a736a2062d82c2a09f0ff2525b3df3a0c6f4e0ffc7a0392efd44bfe7f9d018e4cae30d15b818b216622 + languageName: node + linkType: hard + +"postcss-loader@npm:^7.0.0": + version: 7.3.3 + resolution: "postcss-loader@npm:7.3.3" + dependencies: + cosmiconfig: ^8.2.0 + jiti: ^1.18.2 + semver: ^7.3.8 + peerDependencies: + postcss: ^7.0.0 || ^8.0.1 + webpack: ^5.0.0 + checksum: c724044d6ae56334535c26bb4efc9c151431d44d60bc8300157c760747281a242757d8dab32db72738434531175b38a408cb0b270bb96207c07584dcfcd899ff + languageName: node + linkType: hard + +"postcss-merge-idents@npm:^5.1.1": + version: 5.1.1 + resolution: "postcss-merge-idents@npm:5.1.1" + dependencies: + cssnano-utils: ^3.1.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: ed8a673617ea6ae3e15d69558063cb1a5eeee01732f78cdc0196ab910324abc30828724ab8dfc4cda27e8c0077542e25688470f829819a2604625a673387ec72 + languageName: node + linkType: hard + +"postcss-merge-longhand@npm:^5.1.7": + version: 5.1.7 + resolution: "postcss-merge-longhand@npm:5.1.7" + dependencies: + postcss-value-parser: ^4.2.0 + stylehacks: ^5.1.1 + peerDependencies: + postcss: ^8.2.15 + checksum: 81c3fc809f001b9b71a940148e242bdd6e2d77713d1bfffa15eb25c1f06f6648d5e57cb21645746d020a2a55ff31e1740d2b27900442913a9d53d8a01fb37e1b + languageName: node + linkType: hard + +"postcss-merge-rules@npm:^5.1.4": + version: 5.1.4 + resolution: "postcss-merge-rules@npm:5.1.4" + dependencies: + browserslist: ^4.21.4 + caniuse-api: ^3.0.0 + cssnano-utils: ^3.1.0 + postcss-selector-parser: ^6.0.5 + peerDependencies: + postcss: ^8.2.15 + checksum: 8ab6a569babe6cb412d6612adee74f053cea7edb91fa013398515ab36754b1fec830d68782ed8cdfb44cffdc6b78c79eab157bff650f428aa4460d3f3857447e + languageName: node + linkType: hard + +"postcss-minify-font-values@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-minify-font-values@npm:5.1.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 35e858fa41efa05acdeb28f1c76579c409fdc7eabb1744c3bd76e895bb9fea341a016746362a67609688ab2471f587202b9a3e14ea28ad677754d663a2777ece + languageName: node + linkType: hard + +"postcss-minify-gradients@npm:^5.1.1": + version: 5.1.1 + resolution: "postcss-minify-gradients@npm:5.1.1" + dependencies: + colord: ^2.9.1 + cssnano-utils: ^3.1.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 27354072a07c5e6dab36731103b94ca2354d4ed3c5bc6aacfdf2ede5a55fa324679d8fee5450800bc50888dbb5e9ed67569c0012040c2be128143d0cebb36d67 + languageName: node + linkType: hard + +"postcss-minify-params@npm:^5.1.4": + version: 5.1.4 + resolution: "postcss-minify-params@npm:5.1.4" + dependencies: + browserslist: ^4.21.4 + cssnano-utils: ^3.1.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: bd63e2cc89edcf357bb5c2a16035f6d02ef676b8cede4213b2bddd42626b3d428403849188f95576fc9f03e43ebd73a29bf61d33a581be9a510b13b7f7f100d5 + languageName: node + linkType: hard + +"postcss-minify-selectors@npm:^5.2.1": + version: 5.2.1 + resolution: "postcss-minify-selectors@npm:5.2.1" + dependencies: + postcss-selector-parser: ^6.0.5 + peerDependencies: + postcss: ^8.2.15 + checksum: 6fdbc84f99a60d56b43df8930707da397775e4c36062a106aea2fd2ac81b5e24e584a1892f4baa4469fa495cb87d1422560eaa8f6c9d500f9f0b691a5f95bab5 + languageName: node + linkType: hard + +"postcss-modules-extract-imports@npm:^3.0.0": + version: 3.0.0 + resolution: "postcss-modules-extract-imports@npm:3.0.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 4b65f2f1382d89c4bc3c0a1bdc5942f52f3cb19c110c57bd591ffab3a5fee03fcf831604168205b0c1b631a3dce2255c70b61aaae3ef39d69cd7eb450c2552d2 + languageName: node + linkType: hard + +"postcss-modules-local-by-default@npm:^4.0.3": + version: 4.0.3 + resolution: "postcss-modules-local-by-default@npm:4.0.3" + dependencies: + icss-utils: ^5.0.0 + postcss-selector-parser: ^6.0.2 + postcss-value-parser: ^4.1.0 + peerDependencies: + postcss: ^8.1.0 + checksum: 2f8083687f3d6067885f8863dd32dbbb4f779cfcc7e52c17abede9311d84faf6d3ed8760e7c54c6380281732ae1f78e5e56a28baf3c271b33f450a11c9e30485 + languageName: node + linkType: hard + +"postcss-modules-scope@npm:^3.0.0": + version: 3.0.0 + resolution: "postcss-modules-scope@npm:3.0.0" + dependencies: + postcss-selector-parser: ^6.0.4 + peerDependencies: + postcss: ^8.1.0 + checksum: 330b9398dbd44c992c92b0dc612c0626135e2cc840fee41841eb61247a6cfed95af2bd6f67ead9dd9d0bb41f5b0367129d93c6e434fa3e9c58ade391d9a5a138 + languageName: node + linkType: hard + +"postcss-modules-values@npm:^4.0.0": + version: 4.0.0 + resolution: "postcss-modules-values@npm:4.0.0" + dependencies: + icss-utils: ^5.0.0 + peerDependencies: + postcss: ^8.1.0 + checksum: f7f2cdf14a575b60e919ad5ea52fed48da46fe80db2733318d71d523fc87db66c835814940d7d05b5746b0426e44661c707f09bdb83592c16aea06e859409db6 + languageName: node + linkType: hard + +"postcss-normalize-charset@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-normalize-charset@npm:5.1.0" + peerDependencies: + postcss: ^8.2.15 + checksum: e79d92971fc05b8b3c9b72f3535a574e077d13c69bef68156a0965f397fdf157de670da72b797f57b0e3bac8f38155b5dd1735ecab143b9cc4032d72138193b4 + languageName: node + linkType: hard + +"postcss-normalize-display-values@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-normalize-display-values@npm:5.1.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: b6eb7b9b02c3bdd62bbc54e01e2b59733d73a1c156905d238e178762962efe0c6f5104544da39f32cade8a4fb40f10ff54b63a8ebfbdff51e8780afb9fbdcf86 + languageName: node + linkType: hard + +"postcss-normalize-positions@npm:^5.1.1": + version: 5.1.1 + resolution: "postcss-normalize-positions@npm:5.1.1" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: d9afc233729c496463c7b1cdd06732469f401deb387484c3a2422125b46ec10b4af794c101f8c023af56f01970b72b535e88373b9058ecccbbf88db81662b3c4 + languageName: node + linkType: hard + +"postcss-normalize-repeat-style@npm:^5.1.1": + version: 5.1.1 + resolution: "postcss-normalize-repeat-style@npm:5.1.1" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 2c6ad2b0ae10a1fda156b948c34f78c8f1e185513593de4d7e2480973586675520edfec427645fa168c337b0a6b3ceca26f92b96149741ca98a9806dad30d534 + languageName: node + linkType: hard + +"postcss-normalize-string@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-normalize-string@npm:5.1.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 6e549c6e5b2831e34c7bdd46d8419e2278f6af1d5eef6d26884a37c162844e60339340c57e5e06058cdbe32f27fc6258eef233e811ed2f71168ef2229c236ada + languageName: node + linkType: hard + +"postcss-normalize-timing-functions@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-normalize-timing-functions@npm:5.1.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: da550f50e90b0b23e17b67449a7d1efd1aa68288e66d4aa7614ca6f5cc012896be1972b7168eee673d27da36504faccf7b9f835c0f7e81243f966a42c8c030aa + languageName: node + linkType: hard + +"postcss-normalize-unicode@npm:^5.1.1": + version: 5.1.1 + resolution: "postcss-normalize-unicode@npm:5.1.1" + dependencies: + browserslist: ^4.21.4 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 4c24d26cc9f4b19a9397db4e71dd600dab690f1de8e14a3809e2aa1452dbc3791c208c38a6316bbc142f29e934fdf02858e68c94038c06174d78a4937e0f273c + languageName: node + linkType: hard + +"postcss-normalize-url@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-normalize-url@npm:5.1.0" + dependencies: + normalize-url: ^6.0.1 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 3bd4b3246d6600230bc827d1760b24cb3101827ec97570e3016cbe04dc0dd28f4dbe763245d1b9d476e182c843008fbea80823061f1d2219b96f0d5c724a24c0 + languageName: node + linkType: hard + +"postcss-normalize-whitespace@npm:^5.1.1": + version: 5.1.1 + resolution: "postcss-normalize-whitespace@npm:5.1.1" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 12d8fb6d1c1cba208cc08c1830959b7d7ad447c3f5581873f7e185f99a9a4230c43d3af21ca12c818e4690a5085a95b01635b762ad4a7bef69d642609b4c0e19 + languageName: node + linkType: hard + +"postcss-ordered-values@npm:^5.1.3": + version: 5.1.3 + resolution: "postcss-ordered-values@npm:5.1.3" + dependencies: + cssnano-utils: ^3.1.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 6f3ca85b6ceffc68aadaf319d9ee4c5ac16d93195bf8cba2d1559b631555ad61941461cda6d3909faab86e52389846b2b36345cff8f0c3f4eb345b1b8efadcf9 + languageName: node + linkType: hard + +"postcss-reduce-idents@npm:^5.2.0": + version: 5.2.0 + resolution: "postcss-reduce-idents@npm:5.2.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: f0d644c86e160dd36ee4dd924ab7d6feacac867c87702e2f98f96b409430a62de4fec2dfc3c8731bda4e14196e29a752b4558942f0af2a3e6cd7f1f4b173db8e + languageName: node + linkType: hard + +"postcss-reduce-initial@npm:^5.1.2": + version: 5.1.2 + resolution: "postcss-reduce-initial@npm:5.1.2" + dependencies: + browserslist: ^4.21.4 + caniuse-api: ^3.0.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 55db697f85231a81f1969d54c894e4773912d9ddb914f9b03d2e73abc4030f2e3bef4d7465756d0c1acfcc2c2d69974bfb50a972ab27546a7d68b5a4fc90282b + languageName: node + linkType: hard + +"postcss-reduce-transforms@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-reduce-transforms@npm:5.1.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 0c6af2cba20e3ff63eb9ad045e634ddfb9c3e5c0e614c020db2a02f3aa20632318c4ede9e0c995f9225d9a101e673de91c0a6e10bb2fa5da6d6c75d15a55882f + languageName: node + linkType: hard + +"postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9": + version: 6.0.13 + resolution: "postcss-selector-parser@npm:6.0.13" + dependencies: + cssesc: ^3.0.0 + util-deprecate: ^1.0.2 + checksum: f89163338a1ce3b8ece8e9055cd5a3165e79a15e1c408e18de5ad8f87796b61ec2d48a2902d179ae0c4b5de10fccd3a325a4e660596549b040bc5ad1b465f096 + languageName: node + linkType: hard + +"postcss-sort-media-queries@npm:^4.2.1": + version: 4.4.1 + resolution: "postcss-sort-media-queries@npm:4.4.1" + dependencies: + sort-css-media-queries: 2.1.0 + peerDependencies: + postcss: ^8.4.16 + checksum: 70b42e479bb1d15d8628678eefefd547d309e33e64262fe437630fe62d8e4b3adcae7f2b48ef8da9d3173576d4af109a9ffa9514573db1281deef324f5ea166f + languageName: node + linkType: hard + +"postcss-svgo@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-svgo@npm:5.1.0" + dependencies: + postcss-value-parser: ^4.2.0 + svgo: ^2.7.0 + peerDependencies: + postcss: ^8.2.15 + checksum: d86eb5213d9f700cf5efe3073799b485fb7cacae0c731db3d7749c9c2b1c9bc85e95e0baeca439d699ff32ea24815fc916c4071b08f67ed8219df229ce1129bd + languageName: node + linkType: hard + +"postcss-unique-selectors@npm:^5.1.1": + version: 5.1.1 + resolution: "postcss-unique-selectors@npm:5.1.1" + dependencies: + postcss-selector-parser: ^6.0.5 + peerDependencies: + postcss: ^8.2.15 + checksum: 637e7b786e8558265775c30400c54b6b3b24d4748923f4a39f16a65fd0e394f564ccc9f0a1d3c0e770618a7637a7502ea1d0d79f731d429cb202255253c23278 + languageName: node + linkType: hard + +"postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": + version: 4.2.0 + resolution: "postcss-value-parser@npm:4.2.0" + checksum: 819ffab0c9d51cf0acbabf8996dffbfafbafa57afc0e4c98db88b67f2094cb44488758f06e5da95d7036f19556a4a732525e84289a425f4f6fd8e412a9d7442f + languageName: node + linkType: hard + +"postcss-zindex@npm:^5.1.0": + version: 5.1.0 + resolution: "postcss-zindex@npm:5.1.0" + peerDependencies: + postcss: ^8.2.15 + checksum: 8581e0ee552622489dcb9fb9609a3ccc261a67a229ba91a70bd138fe102a2d04cedb14642b82b673d4cac7b559ef32574f2dafde2ff7816eecac024d231c5ead + languageName: node + linkType: hard + +"postcss@npm:^8.3.11, postcss@npm:^8.4.14, postcss@npm:^8.4.17, postcss@npm:^8.4.21": + version: 8.4.31 + resolution: "postcss@npm:8.4.31" + dependencies: + nanoid: ^3.3.6 + picocolors: ^1.0.0 + source-map-js: ^1.0.2 + checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea languageName: node linkType: hard @@ -7105,6 +13942,13 @@ __metadata: languageName: node linkType: hard +"prepend-http@npm:^2.0.0": + version: 2.0.0 + resolution: "prepend-http@npm:2.0.0" + checksum: 7694a9525405447662c1ffd352fcb41b6410c705b739b6f4e3a3e21cf5fdede8377890088e8934436b8b17ba55365a615f153960f30877bf0d0392f9e93503ea + languageName: node + linkType: hard + "prettier-linter-helpers@npm:^1.0.0": version: 1.0.0 resolution: "prettier-linter-helpers@npm:1.0.0" @@ -7123,6 +13967,16 @@ __metadata: languageName: node linkType: hard +"pretty-error@npm:^4.0.0": + version: 4.0.0 + resolution: "pretty-error@npm:4.0.0" + dependencies: + lodash: ^4.17.20 + renderkid: ^3.0.0 + checksum: a5b9137365690104ded6947dca2e33360bf55e62a4acd91b1b0d7baa3970e43754c628cc9e16eafbdd4e8f8bcb260a5865475d4fc17c3106ff2d61db4e72cdf3 + languageName: node + linkType: hard + "pretty-ms@npm:^8.0.0": version: 8.0.0 resolution: "pretty-ms@npm:8.0.0" @@ -7132,6 +13986,36 @@ __metadata: languageName: node linkType: hard +"pretty-time@npm:^1.1.0": + version: 1.1.0 + resolution: "pretty-time@npm:1.1.0" + checksum: a319e7009aadbc6cfedbd8b66861327d3a0c68bd3e8794bf5b86f62b40b01b9479c5a70c76bb368ad454acce52a1216daee460cc825766e2442c04f3a84a02c9 + languageName: node + linkType: hard + +"prism-react-renderer@npm:^1.3.5": + version: 1.3.5 + resolution: "prism-react-renderer@npm:1.3.5" + peerDependencies: + react: ">=0.14.9" + checksum: c18806dcbc4c0b4fd6fd15bd06b4f7c0a6da98d93af235c3e970854994eb9b59e23315abb6cfc29e69da26d36709a47e25da85ab27fed81b6812f0a52caf6dfa + languageName: node + linkType: hard + +"prismjs@npm:^1.28.0": + version: 1.29.0 + resolution: "prismjs@npm:1.29.0" + checksum: 007a8869d4456ff8049dc59404e32d5666a07d99c3b0e30a18bd3b7676dfa07d1daae9d0f407f20983865fd8da56de91d09cb08e6aa61f5bc420a27c0beeaf93 + languageName: node + linkType: hard + +"process-nextick-args@npm:~2.0.0": + version: 2.0.1 + resolution: "process-nextick-args@npm:2.0.1" + checksum: 1d38588e520dab7cea67cbbe2efdd86a10cc7a074c09657635e34f035277b59fbb57d09d8638346bf7090f8e8ebc070c96fa5fd183b777fff4f5edff5e9466cf + languageName: node + linkType: hard + "progress@npm:2.0.3": version: 2.0.3 resolution: "progress@npm:2.0.3" @@ -7149,7 +14033,56 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:1.1.0": +"promise@npm:^7.1.1": + version: 7.3.1 + resolution: "promise@npm:7.3.1" + dependencies: + asap: ~2.0.3 + checksum: 475bb069130179fbd27ed2ab45f26d8862376a137a57314cf53310bdd85cc986a826fd585829be97ebc0aaf10e9d8e68be1bfe5a4a0364144b1f9eedfa940cf1 + languageName: node + linkType: hard + +"prompts@npm:^2.4.2": + version: 2.4.2 + resolution: "prompts@npm:2.4.2" + dependencies: + kleur: ^3.0.3 + sisteransi: ^1.0.5 + checksum: d8fd1fe63820be2412c13bfc5d0a01909acc1f0367e32396962e737cb2fc52d004f3302475d5ce7d18a1e8a79985f93ff04ee03007d091029c3f9104bffc007d + languageName: node + linkType: hard + +"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2": + version: 15.8.1 + resolution: "prop-types@npm:15.8.1" + dependencies: + loose-envify: ^1.4.0 + object-assign: ^4.1.1 + react-is: ^16.13.1 + checksum: c056d3f1c057cb7ff8344c645450e14f088a915d078dcda795041765047fa080d38e5d626560ccaac94a4e16e3aa15f3557c1a9a8d1174530955e992c675e459 + languageName: node + linkType: hard + +"property-information@npm:^5.0.0, property-information@npm:^5.3.0": + version: 5.6.0 + resolution: "property-information@npm:5.6.0" + dependencies: + xtend: ^4.0.0 + checksum: fcf87c6542e59a8bbe31ca0b3255a4a63ac1059b01b04469680288998bcfa97f341ca989566adbb63975f4d85339030b82320c324a511532d390910d1c583893 + languageName: node + linkType: hard + +"proxy-addr@npm:~2.0.7": + version: 2.0.7 + resolution: "proxy-addr@npm:2.0.7" + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + checksum: 29c6990ce9364648255454842f06f8c46fcd124d3e6d7c5066df44662de63cdc0bad032e9bf5a3d653ff72141cc7b6019873d685708ac8210c30458ad99f2b74 + languageName: node + linkType: hard + +"proxy-from-env@npm:1.1.0, proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 @@ -7177,6 +14110,13 @@ __metadata: languageName: node linkType: hard +"punycode@npm:^1.3.2": + version: 1.4.1 + resolution: "punycode@npm:1.4.1" + checksum: fa6e698cb53db45e4628559e557ddaf554103d2a96a1d62892c8f4032cd3bc8871796cae9eabc1bc700e2b6677611521ce5bb1d9a27700086039965d0cf34518 + languageName: node + linkType: hard + "punycode@npm:^2.1.0, punycode@npm:^2.1.1": version: 2.3.0 resolution: "punycode@npm:2.3.0" @@ -7184,6 +14124,15 @@ __metadata: languageName: node linkType: hard +"pupa@npm:^2.1.1": + version: 2.1.1 + resolution: "pupa@npm:2.1.1" + dependencies: + escape-goat: ^2.0.0 + checksum: 49529e50372ffdb0cccf0efa0f3b3cb0a2c77805d0d9cc2725bd2a0f6bb414631e61c93a38561b26be1259550b7bb6c2cb92315aa09c8bf93f3bdcb49f2b2fb7 + languageName: node + linkType: hard + "puppeteer-core@npm:^19.8.1": version: 19.11.1 resolution: "puppeteer-core@npm:19.11.1" @@ -7208,60 +14157,470 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.5.2": - version: 6.11.2 - resolution: "qs@npm:6.11.2" +"pure-color@npm:^1.2.0": + version: 1.3.0 + resolution: "pure-color@npm:1.3.0" + checksum: 646d8bed6e6eab89affdd5e2c11f607a85b631a7fb03c061dfa658eb4dc4806881a15feed2ac5fd8c0bad8c00c632c640d5b1cb8b9a972e6e947393a1329371b + languageName: node + linkType: hard + +"qs@npm:6.11.0": + version: 6.11.0 + resolution: "qs@npm:6.11.0" + dependencies: + side-channel: ^1.0.4 + checksum: 6e1f29dd5385f7488ec74ac7b6c92f4d09a90408882d0c208414a34dd33badc1a621019d4c799a3df15ab9b1d0292f97c1dd71dc7c045e69f81a8064e5af7297 + languageName: node + linkType: hard + +"qs@npm:^6.5.2": + version: 6.11.2 + resolution: "qs@npm:6.11.2" + dependencies: + side-channel: ^1.0.4 + checksum: e812f3c590b2262548647d62f1637b6989cc56656dc960b893fe2098d96e1bd633f36576f4cd7564dfbff9db42e17775884db96d846bebe4f37420d073ecdc0b + languageName: node + linkType: hard + +"queue-microtask@npm:^1.2.2, queue-microtask@npm:^1.2.3": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 + languageName: node + linkType: hard + +"queue@npm:6.0.2": + version: 6.0.2 + resolution: "queue@npm:6.0.2" + dependencies: + inherits: ~2.0.3 + checksum: ebc23639248e4fe40a789f713c20548e513e053b3dc4924b6cb0ad741e3f264dcff948225c8737834dd4f9ec286dbc06a1a7c13858ea382d9379f4303bcc0916 + languageName: node + linkType: hard + +"randombytes@npm:^2.1.0": + version: 2.1.0 + resolution: "randombytes@npm:2.1.0" + dependencies: + safe-buffer: ^5.1.0 + checksum: d779499376bd4cbb435ef3ab9a957006c8682f343f14089ed5f27764e4645114196e75b7f6abf1cbd84fd247c0cb0651698444df8c9bf30e62120fbbc52269d6 + languageName: node + linkType: hard + +"range-parser@npm:1.2.0": + version: 1.2.0 + resolution: "range-parser@npm:1.2.0" + checksum: bdf397f43fedc15c559d3be69c01dedf38444ca7a1610f5bf5955e3f3da6057a892f34691e7ebdd8c7e1698ce18ef6c4d4811f70e658dda3ff230ef741f8423a + languageName: node + linkType: hard + +"range-parser@npm:^1.2.1, range-parser@npm:~1.2.1": + version: 1.2.1 + resolution: "range-parser@npm:1.2.1" + checksum: 0a268d4fea508661cf5743dfe3d5f47ce214fd6b7dec1de0da4d669dd4ef3d2144468ebe4179049eff253d9d27e719c88dae55be64f954e80135a0cada804ec9 + languageName: node + linkType: hard + +"raw-body@npm:2.5.1": + version: 2.5.1 + resolution: "raw-body@npm:2.5.1" + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + checksum: 5362adff1575d691bb3f75998803a0ffed8c64eabeaa06e54b4ada25a0cd1b2ae7f4f5ec46565d1bec337e08b5ac90c76eaa0758de6f72a633f025d754dec29e + languageName: node + linkType: hard + +"raw-body@npm:^2.3.3, raw-body@npm:^2.4.1": + version: 2.5.2 + resolution: "raw-body@npm:2.5.2" + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + checksum: ba1583c8d8a48e8fbb7a873fdbb2df66ea4ff83775421bfe21ee120140949ab048200668c47d9ae3880012f6e217052690628cf679ddfbd82c9fc9358d574676 + languageName: node + linkType: hard + +"rc@npm:1.2.8, rc@npm:^1.2.8": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: ^0.6.0 + ini: ~1.3.0 + minimist: ^1.2.0 + strip-json-comments: ~2.0.1 + bin: + rc: ./cli.js + checksum: 2e26e052f8be2abd64e6d1dabfbd7be03f80ec18ccbc49562d31f617d0015fbdbcf0f9eed30346ea6ab789e0fdfe4337f033f8016efdbee0df5354751842080e + languageName: node + linkType: hard + +"react-base16-styling@npm:^0.6.0": + version: 0.6.0 + resolution: "react-base16-styling@npm:0.6.0" + dependencies: + base16: ^1.0.0 + lodash.curry: ^4.0.1 + lodash.flow: ^3.3.0 + pure-color: ^1.2.0 + checksum: 00a12dddafc8a9025cca933b0dcb65fca41c81fa176d1fc3a6a9d0242127042e2c0a604f4c724a3254dd2c6aeb5ef55095522ff22f5462e419641c1341a658e4 + languageName: node + linkType: hard + +"react-dev-utils@npm:^12.0.1": + version: 12.0.1 + resolution: "react-dev-utils@npm:12.0.1" + dependencies: + "@babel/code-frame": ^7.16.0 + address: ^1.1.2 + browserslist: ^4.18.1 + chalk: ^4.1.2 + cross-spawn: ^7.0.3 + detect-port-alt: ^1.1.6 + escape-string-regexp: ^4.0.0 + filesize: ^8.0.6 + find-up: ^5.0.0 + fork-ts-checker-webpack-plugin: ^6.5.0 + global-modules: ^2.0.0 + globby: ^11.0.4 + gzip-size: ^6.0.0 + immer: ^9.0.7 + is-root: ^2.1.0 + loader-utils: ^3.2.0 + open: ^8.4.0 + pkg-up: ^3.1.0 + prompts: ^2.4.2 + react-error-overlay: ^6.0.11 + recursive-readdir: ^2.2.2 + shell-quote: ^1.7.3 + strip-ansi: ^6.0.1 + text-table: ^0.2.0 + checksum: 2c6917e47f03d9595044770b0f883a61c6b660fcaa97b8ba459a1d57c9cca9aa374cd51296b22d461ff5e432105dbe6f04732dab128e52729c79239e1c23ab56 + languageName: node + linkType: hard + +"react-dom@npm:^17.0.2": + version: 17.0.2 + resolution: "react-dom@npm:17.0.2" + dependencies: + loose-envify: ^1.1.0 + object-assign: ^4.1.1 + scheduler: ^0.20.2 + peerDependencies: + react: 17.0.2 + checksum: 1c1eaa3bca7c7228d24b70932e3d7c99e70d1d04e13bb0843bbf321582bc25d7961d6b8a6978a58a598af2af496d1cedcfb1bf65f6b0960a0a8161cb8dab743c + languageName: node + linkType: hard + +"react-error-overlay@npm:^6.0.11": + version: 6.0.11 + resolution: "react-error-overlay@npm:6.0.11" + checksum: ce7b44c38fadba9cedd7c095cf39192e632daeccf1d0747292ed524f17dcb056d16bc197ddee5723f9dd888f0b9b19c3b486c430319e30504289b9296f2d2c42 + languageName: node + linkType: hard + +"react-fast-compare@npm:^3.2.0": + version: 3.2.2 + resolution: "react-fast-compare@npm:3.2.2" + checksum: 2071415b4f76a3e6b55c84611c4d24dcb12ffc85811a2840b5a3f1ff2d1a99be1020d9437ee7c6e024c9f4cbb84ceb35e48cf84f28fcb00265ad2dfdd3947704 + languageName: node + linkType: hard + +"react-helmet-async@npm:*, react-helmet-async@npm:^1.3.0": + version: 1.3.0 + resolution: "react-helmet-async@npm:1.3.0" + dependencies: + "@babel/runtime": ^7.12.5 + invariant: ^2.2.4 + prop-types: ^15.7.2 + react-fast-compare: ^3.2.0 + shallowequal: ^1.1.0 + peerDependencies: + react: ^16.6.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + checksum: 7ca7e47f8af14ea186688b512a87ab912bf6041312b297f92516341b140b3f0f8aedf5a44d226d99e69ed067b0cc106e38aeb9c9b738ffcc63d10721c844db90 + languageName: node + linkType: hard + +"react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0": + version: 16.13.1 + resolution: "react-is@npm:16.13.1" + checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f + languageName: node + linkType: hard + +"react-json-view@npm:^1.21.3": + version: 1.21.3 + resolution: "react-json-view@npm:1.21.3" + dependencies: + flux: ^4.0.1 + react-base16-styling: ^0.6.0 + react-lifecycles-compat: ^3.0.4 + react-textarea-autosize: ^8.3.2 + peerDependencies: + react: ^17.0.0 || ^16.3.0 || ^15.5.4 + react-dom: ^17.0.0 || ^16.3.0 || ^15.5.4 + checksum: 5718bcd9210ad5b06eb9469cf8b9b44be9498845a7702e621343618e8251f26357e6e1c865532cf170db6165df1cb30202787e057309d8848c220bc600ec0d1a + languageName: node + linkType: hard + +"react-lifecycles-compat@npm:^3.0.4": + version: 3.0.4 + resolution: "react-lifecycles-compat@npm:3.0.4" + checksum: a904b0fc0a8eeb15a148c9feb7bc17cec7ef96e71188280061fc340043fd6d8ee3ff233381f0e8f95c1cf926210b2c4a31f38182c8f35ac55057e453d6df204f + languageName: node + linkType: hard + +"react-loadable-ssr-addon-v5-slorber@npm:^1.0.1": + version: 1.0.1 + resolution: "react-loadable-ssr-addon-v5-slorber@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.10.3 + peerDependencies: + react-loadable: "*" + webpack: ">=4.41.1 || 5.x" + checksum: 1cf7ceb488d329a5be15f891dae16727fb7ade08ef57826addd21e2c3d485e2440259ef8be94f4d54e9afb4bcbd2fcc22c3c5bad92160c9c06ae6ba7b5562497 + languageName: node + linkType: hard + +"react-router-config@npm:^5.1.1": + version: 5.1.1 + resolution: "react-router-config@npm:5.1.1" + dependencies: + "@babel/runtime": ^7.1.2 + peerDependencies: + react: ">=15" + react-router: ">=5" + checksum: bde7ee79444454bf7c3737fd9c5c268021012c8cc37bc19116b2e7daa28c4231598c275816c7f32c16f9f974dc707b91de279291a5e39efce2e1b1569355b87a + languageName: node + linkType: hard + +"react-router-dom@npm:^5.3.3": + version: 5.3.4 + resolution: "react-router-dom@npm:5.3.4" + dependencies: + "@babel/runtime": ^7.12.13 + history: ^4.9.0 + loose-envify: ^1.3.1 + prop-types: ^15.6.2 + react-router: 5.3.4 + tiny-invariant: ^1.0.2 + tiny-warning: ^1.0.0 + peerDependencies: + react: ">=15" + checksum: b86a6f2f5222f041e38adf4e4b32c7643d6735a1a915ef25855b2db285fd059d72ba8d62e5bcd5d822b8ef9520a80453209e55077f5a90d0f72e908979b8f535 + languageName: node + linkType: hard + +"react-router@npm:5.3.4, react-router@npm:^5.3.3": + version: 5.3.4 + resolution: "react-router@npm:5.3.4" + dependencies: + "@babel/runtime": ^7.12.13 + history: ^4.9.0 + hoist-non-react-statics: ^3.1.0 + loose-envify: ^1.3.1 + path-to-regexp: ^1.7.0 + prop-types: ^15.6.2 + react-is: ^16.6.0 + tiny-invariant: ^1.0.2 + tiny-warning: ^1.0.0 + peerDependencies: + react: ">=15" + checksum: 892d4e274a23bf4f39abc2efca54472fb646d3aed4b584020cf49654d2f50d09a2bacebe7c92b4ec7cb8925077376dfcd0664bad6442a73604397cefec9f01f9 + languageName: node + linkType: hard + +"react-textarea-autosize@npm:^8.3.2": + version: 8.5.3 + resolution: "react-textarea-autosize@npm:8.5.3" + dependencies: + "@babel/runtime": ^7.20.13 + use-composed-ref: ^1.3.0 + use-latest: ^1.2.1 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: b317c3763f37a89621bbafd0e6e2d068e7876790a5ae77f497adfd6ba9334ceea138c8a0b7d907bae0f79c765cb24e8b2ca2b8033b4144c0bce28571a3658921 + languageName: node + linkType: hard + +"react@npm:^17.0.2": + version: 17.0.2 + resolution: "react@npm:17.0.2" + dependencies: + loose-envify: ^1.1.0 + object-assign: ^4.1.1 + checksum: b254cc17ce3011788330f7bbf383ab653c6848902d7936a87b09d835d091e3f295f7e9dd1597c6daac5dc80f90e778c8230218ba8ad599f74adcc11e33b9d61b + languageName: node + linkType: hard + +"readable-stream@npm:^2.0.1": + version: 2.3.8 + resolution: "readable-stream@npm:2.3.8" + dependencies: + core-util-is: ~1.0.0 + inherits: ~2.0.3 + isarray: ~1.0.0 + process-nextick-args: ~2.0.0 + safe-buffer: ~5.1.1 + string_decoder: ~1.1.1 + util-deprecate: ~1.0.1 + checksum: 65645467038704f0c8aaf026a72fbb588a9e2ef7a75cd57a01702ee9db1c4a1e4b03aaad36861a6a0926546a74d174149c8c207527963e0c2d3eee2f37678a42 + languageName: node + linkType: hard + +"readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: ^2.0.3 + string_decoder: ^1.1.1 + util-deprecate: ^1.0.1 + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + languageName: node + linkType: hard + +"readdirp@npm:~3.6.0": + version: 3.6.0 + resolution: "readdirp@npm:3.6.0" + dependencies: + picomatch: ^2.2.1 + checksum: 1ced032e6e45670b6d7352d71d21ce7edf7b9b928494dcaba6f11fba63180d9da6cd7061ebc34175ffda6ff529f481818c962952004d273178acd70f7059b320 + languageName: node + linkType: hard + +"reading-time@npm:^1.5.0": + version: 1.5.0 + resolution: "reading-time@npm:1.5.0" + checksum: e27bc5a70ba0f4ac337896b18531b914d38f4bee67cbad48029d0c11dd0a7a847b2a6bba895ab7ce2ad3e7ecb86912bdc477d8fa2d48405a3deda964be54d09b + languageName: node + linkType: hard + +"rechoir@npm:^0.6.2": + version: 0.6.2 + resolution: "rechoir@npm:0.6.2" + dependencies: + resolve: ^1.1.6 + checksum: fe76bf9c21875ac16e235defedd7cbd34f333c02a92546142b7911a0f7c7059d2e16f441fe6fb9ae203f459c05a31b2bcf26202896d89e390eda7514d5d2702b + languageName: node + linkType: hard + +"recursive-readdir@npm:^2.2.2": + version: 2.2.3 + resolution: "recursive-readdir@npm:2.2.3" + dependencies: + minimatch: ^3.0.5 + checksum: 88ec96e276237290607edc0872b4f9842837b95cfde0cdbb1e00ba9623dfdf3514d44cdd14496ab60a0c2dd180a6ef8a3f1c34599e6cf2273afac9b72a6fb2b5 + languageName: node + linkType: hard + +"regenerate-unicode-properties@npm:^10.1.0": + version: 10.1.1 + resolution: "regenerate-unicode-properties@npm:10.1.1" + dependencies: + regenerate: ^1.4.2 + checksum: b80958ef40f125275824c2c47d5081dfaefebd80bff26c76761e9236767c748a4a95a69c053fe29d2df881177f2ca85df4a71fe70a82360388b31159ef19adcf + languageName: node + linkType: hard + +"regenerate@npm:^1.4.2": + version: 1.4.2 + resolution: "regenerate@npm:1.4.2" + checksum: 3317a09b2f802da8db09aa276e469b57a6c0dd818347e05b8862959c6193408242f150db5de83c12c3fa99091ad95fb42a6db2c3329bfaa12a0ea4cbbeb30cb0 + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.14.0": + version: 0.14.0 + resolution: "regenerator-runtime@npm:0.14.0" + checksum: 1c977ad82a82a4412e4f639d65d22be376d3ebdd30da2c003eeafdaaacd03fc00c2320f18120007ee700900979284fc78a9f00da7fb593f6e6eeebc673fba9a3 + languageName: node + linkType: hard + +"regenerator-transform@npm:^0.15.2": + version: 0.15.2 + resolution: "regenerator-transform@npm:0.15.2" dependencies: - side-channel: ^1.0.4 - checksum: e812f3c590b2262548647d62f1637b6989cc56656dc960b893fe2098d96e1bd633f36576f4cd7564dfbff9db42e17775884db96d846bebe4f37420d073ecdc0b + "@babel/runtime": ^7.8.4 + checksum: 20b6f9377d65954980fe044cfdd160de98df415b4bff38fbade67b3337efaf078308c4fed943067cd759827cc8cfeca9cb28ccda1f08333b85d6a2acbd022c27 languageName: node linkType: hard -"queue-microtask@npm:^1.2.2, queue-microtask@npm:^1.2.3": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 +"regexpu-core@npm:^5.3.1": + version: 5.3.2 + resolution: "regexpu-core@npm:5.3.2" + dependencies: + "@babel/regjsgen": ^0.8.0 + regenerate: ^1.4.2 + regenerate-unicode-properties: ^10.1.0 + regjsparser: ^0.9.1 + unicode-match-property-ecmascript: ^2.0.0 + unicode-match-property-value-ecmascript: ^2.1.0 + checksum: 95bb97088419f5396e07769b7de96f995f58137ad75fac5811fb5fe53737766dfff35d66a0ee66babb1eb55386ef981feaef392f9df6d671f3c124812ba24da2 languageName: node linkType: hard -"randombytes@npm:^2.1.0": - version: 2.1.0 - resolution: "randombytes@npm:2.1.0" +"registry-auth-token@npm:^4.0.0": + version: 4.2.2 + resolution: "registry-auth-token@npm:4.2.2" dependencies: - safe-buffer: ^5.1.0 - checksum: d779499376bd4cbb435ef3ab9a957006c8682f343f14089ed5f27764e4645114196e75b7f6abf1cbd84fd247c0cb0651698444df8c9bf30e62120fbbc52269d6 + rc: 1.2.8 + checksum: c5030198546ecfdcbcb0722cbc3e260c4f5f174d8d07bdfedd4620e79bfdf17a2db735aa230d600bd388fce6edd26c0a9ed2eb7e9b4641ec15213a28a806688b languageName: node linkType: hard -"raw-body@npm:^2.3.3, raw-body@npm:^2.4.1": - version: 2.5.2 - resolution: "raw-body@npm:2.5.2" +"registry-url@npm:^5.0.0": + version: 5.1.0 + resolution: "registry-url@npm:5.1.0" dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - checksum: ba1583c8d8a48e8fbb7a873fdbb2df66ea4ff83775421bfe21ee120140949ab048200668c47d9ae3880012f6e217052690628cf679ddfbd82c9fc9358d574676 + rc: ^1.2.8 + checksum: bcea86c84a0dbb66467b53187fadebfea79017cddfb4a45cf27530d7275e49082fe9f44301976eb0164c438e395684bcf3dae4819b36ff9d1640d8cc60c73df9 languageName: node linkType: hard -"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" +"regjsparser@npm:^0.9.1": + version: 0.9.1 + resolution: "regjsparser@npm:0.9.1" dependencies: - inherits: ^2.0.3 - string_decoder: ^1.1.1 - util-deprecate: ^1.0.1 - checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + jsesc: ~0.5.0 + bin: + regjsparser: bin/parser + checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc languageName: node linkType: hard -"readdirp@npm:~3.6.0": - version: 3.6.0 - resolution: "readdirp@npm:3.6.0" +"rehype-katex@npm:^5.0.0": + version: 5.0.0 + resolution: "rehype-katex@npm:5.0.0" dependencies: - picomatch: ^2.2.1 - checksum: 1ced032e6e45670b6d7352d71d21ce7edf7b9b928494dcaba6f11fba63180d9da6cd7061ebc34175ffda6ff529f481818c962952004d273178acd70f7059b320 + "@types/katex": ^0.11.0 + hast-util-to-text: ^2.0.0 + katex: ^0.13.0 + rehype-parse: ^7.0.0 + unified: ^9.0.0 + unist-util-visit: ^2.0.0 + checksum: b20e24c5326a718581619761057a30d03615519eccd0693ada2c7c710064dceaf08f038ae3a1131550f1f7c47ca54a254ba8e45547da384867e956ceca73f6bf + languageName: node + linkType: hard + +"rehype-parse@npm:^7.0.0": + version: 7.0.1 + resolution: "rehype-parse@npm:7.0.1" + dependencies: + hast-util-from-parse5: ^6.0.0 + parse5: ^6.0.0 + checksum: c3c914aa9281853290eff6b09e0bed6843934e788b957e25219e91f0bf244a183d2f5e042c7d21543276571f9b49a6bae90f4640b8f885f2773392ffa57baf4b + languageName: node + linkType: hard + +"relateurl@npm:^0.2.7": + version: 0.2.7 + resolution: "relateurl@npm:0.2.7" + checksum: 5891e792eae1dfc3da91c6fda76d6c3de0333a60aa5ad848982ebb6dccaa06e86385fb1235a1582c680a3d445d31be01c6bfc0804ebbcab5aaf53fa856fde6b6 languageName: node linkType: hard @@ -7274,6 +14633,100 @@ __metadata: languageName: unknown linkType: soft +"remark-emoji@npm:^2.2.0": + version: 2.2.0 + resolution: "remark-emoji@npm:2.2.0" + dependencies: + emoticon: ^3.2.0 + node-emoji: ^1.10.0 + unist-util-visit: ^2.0.3 + checksum: 638d4be72eb4110a447f389d4b8c454921f188c0acabf1b6579f3ddaa301ee91010173d6eebd975ea622ae3de7ed4531c0315a4ffd4f9653d80c599ef9ec21a8 + languageName: node + linkType: hard + +"remark-footnotes@npm:2.0.0": + version: 2.0.0 + resolution: "remark-footnotes@npm:2.0.0" + checksum: f2f87ffd6fe25892373c7164d6584a7cb03ab0ea4f186af493a73df519e24b72998a556e7f16cb996f18426cdb80556b95ff252769e252cf3ccba0fd2ca20621 + languageName: node + linkType: hard + +"remark-math@npm:^3.0.1": + version: 3.0.1 + resolution: "remark-math@npm:3.0.1" + checksum: 690256f27f2b42dadcf41806fec443056e09592454622ae77f03b1a8474e8c83cc7610e694be7e17de92c96cc272c61209e59a6e7a24e3af6ede47d48b185ccd + languageName: node + linkType: hard + +"remark-mdx@npm:1.6.22": + version: 1.6.22 + resolution: "remark-mdx@npm:1.6.22" + dependencies: + "@babel/core": 7.12.9 + "@babel/helper-plugin-utils": 7.10.4 + "@babel/plugin-proposal-object-rest-spread": 7.12.1 + "@babel/plugin-syntax-jsx": 7.12.1 + "@mdx-js/util": 1.6.22 + is-alphabetical: 1.0.4 + remark-parse: 8.0.3 + unified: 9.2.0 + checksum: 45e62f8a821c37261f94448d54f295de1c5c393f762ff96cd4d4b730715037fafeb6c89ef94adf6a10a09edfa72104afe1431b93b5ae5e40ce2a7677e133c3d9 + languageName: node + linkType: hard + +"remark-parse@npm:8.0.3": + version: 8.0.3 + resolution: "remark-parse@npm:8.0.3" + dependencies: + ccount: ^1.0.0 + collapse-white-space: ^1.0.2 + is-alphabetical: ^1.0.0 + is-decimal: ^1.0.0 + is-whitespace-character: ^1.0.0 + is-word-character: ^1.0.0 + markdown-escapes: ^1.0.0 + parse-entities: ^2.0.0 + repeat-string: ^1.5.4 + state-toggle: ^1.0.0 + trim: 0.0.1 + trim-trailing-lines: ^1.0.0 + unherit: ^1.0.4 + unist-util-remove-position: ^2.0.0 + vfile-location: ^3.0.0 + xtend: ^4.0.1 + checksum: 2dfea250e7606ddfc9e223b9f41e0b115c5c701be4bd35181beaadd46ee59816bc00aadc6085a420f8df00b991ada73b590ea7fd34ace14557de4a0a41805be5 + languageName: node + linkType: hard + +"remark-squeeze-paragraphs@npm:4.0.0": + version: 4.0.0 + resolution: "remark-squeeze-paragraphs@npm:4.0.0" + dependencies: + mdast-squeeze-paragraphs: ^4.0.0 + checksum: 2071eb74d0ecfefb152c4932690a9fd950c3f9f798a676f1378a16db051da68fb20bf288688cc153ba5019dded35408ff45a31dfe9686eaa7a9f1df9edbb6c81 + languageName: node + linkType: hard + +"renderkid@npm:^3.0.0": + version: 3.0.0 + resolution: "renderkid@npm:3.0.0" + dependencies: + css-select: ^4.1.3 + dom-converter: ^0.2.0 + htmlparser2: ^6.1.0 + lodash: ^4.17.21 + strip-ansi: ^6.0.1 + checksum: 77162b62d6f33ab81f337c39efce0439ff0d1f6d441e29c35183151f83041c7850774fb904da163d6c844264d440d10557714e6daa0b19e4561a5cd4ef305d41 + languageName: node + linkType: hard + +"repeat-string@npm:^1.0.0, repeat-string@npm:^1.5.4": + version: 1.6.1 + resolution: "repeat-string@npm:1.6.1" + checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 + languageName: node + linkType: hard + "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -7281,13 +14734,27 @@ __metadata: languageName: node linkType: hard -"require-from-string@npm:^2.0.0": +"require-from-string@npm:^2.0.0, require-from-string@npm:^2.0.2": version: 2.0.2 resolution: "require-from-string@npm:2.0.2" checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b languageName: node linkType: hard +"require-like@npm:>= 0.1.1": + version: 0.1.2 + resolution: "require-like@npm:0.1.2" + checksum: edb8331f05fd807381a75b76f6cca9f0ce8acaa2e910b7e116541799aa970bfbc64fde5fd6adb3a6917dba346f8386ebbddb81614c24e8dad1b4290c7af9535e + languageName: node + linkType: hard + +"requires-port@npm:^1.0.0": + version: 1.0.0 + resolution: "requires-port@npm:1.0.0" + checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff + languageName: node + linkType: hard + "resolve-cwd@npm:^3.0.0": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0" @@ -7321,6 +14788,13 @@ __metadata: languageName: node linkType: hard +"resolve-pathname@npm:^3.0.0": + version: 3.0.0 + resolution: "resolve-pathname@npm:3.0.0" + checksum: 6147241ba42c423dbe83cb067a2b4af4f60908c3af57e1ea567729cc71416c089737fe2a73e9e79e7a60f00f66c91e4b45ad0d37cd4be2d43fec44963ef14368 + languageName: node + linkType: hard + "resolve@npm:1.17.0": version: 1.17.0 resolution: "resolve@npm:1.17.0" @@ -7330,6 +14804,19 @@ __metadata: languageName: node linkType: hard +"resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.3.2": + version: 1.22.8 + resolution: "resolve@npm:1.22.8" + dependencies: + is-core-module: ^2.13.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: f8a26958aa572c9b064562750b52131a37c29d072478ea32e129063e2da7f83e31f7f11e7087a18225a8561cfe8d2f0df9dbea7c9d331a897571c0a2527dbb4c + languageName: node + linkType: hard + "resolve@npm:^1.19.0": version: 1.22.6 resolution: "resolve@npm:1.22.6" @@ -7352,6 +14839,19 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.3.2#~builtin": + version: 1.22.8 + resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d" + dependencies: + is-core-module: ^2.13.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 5479b7d431cacd5185f8db64bfcb7286ae5e31eb299f4c4f404ad8aa6098b77599563ac4257cb2c37a42f59dfc06a1bec2bcf283bb448f319e37f0feb9a09847 + languageName: node + linkType: hard + "resolve@patch:resolve@^1.19.0#~builtin": version: 1.22.6 resolution: "resolve@patch:resolve@npm%3A1.22.6#~builtin::version=1.22.6&hash=c3c19d" @@ -7365,6 +14865,15 @@ __metadata: languageName: node linkType: hard +"responselike@npm:^1.0.2": + version: 1.0.2 + resolution: "responselike@npm:1.0.2" + dependencies: + lowercase-keys: ^1.0.0 + checksum: 2e9e70f1dcca3da621a80ce71f2f9a9cad12c047145c6ece20df22f0743f051cf7c73505e109814915f23f9e34fb0d358e22827723ee3d56b623533cab8eafcd + languageName: node + linkType: hard + "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -7382,6 +14891,13 @@ __metadata: languageName: node linkType: hard +"retry@npm:^0.13.1": + version: 0.13.1 + resolution: "retry@npm:0.13.1" + checksum: 47c4d5be674f7c13eee4cfe927345023972197dbbdfba5d3af7e461d13b44de1bfd663bfc80d2f601f8ef3fc8164c16dd99655a221921954a65d044a2fc1233b + languageName: node + linkType: hard + "reusify@npm:^1.0.4": version: 1.0.4 resolution: "reusify@npm:1.0.4" @@ -7446,6 +14962,27 @@ __metadata: languageName: node linkType: hard +"rtl-detect@npm:^1.0.4": + version: 1.0.4 + resolution: "rtl-detect@npm:1.0.4" + checksum: d562535baa0db62f57f0a1d4676297bff72fd6b94e88f0f0900d5c3e810ab512c5c4cadffd3e05fbe8d9c74310c919afa3ea8c1001c244e5555e8eef12d02d6f + languageName: node + linkType: hard + +"rtlcss@npm:^3.5.0": + version: 3.5.0 + resolution: "rtlcss@npm:3.5.0" + dependencies: + find-up: ^5.0.0 + picocolors: ^1.0.0 + postcss: ^8.3.11 + strip-json-comments: ^3.1.1 + bin: + rtlcss: bin/rtlcss.js + checksum: a3763cad2cb58ce1b950de155097c3c294e7aefc8bf328b58d0cc8d5efb88bf800865edc158a78ace6d1f7f99fea6fd66fb4a354d859b172dadd3dab3e0027b3 + languageName: node + linkType: hard + "run-applescript@npm:^5.0.0": version: 5.0.0 resolution: "run-applescript@npm:5.0.0" @@ -7480,6 +15017,15 @@ __metadata: languageName: node linkType: hard +"rxjs@npm:^7.5.4": + version: 7.8.1 + resolution: "rxjs@npm:7.8.1" + dependencies: + tslib: ^2.1.0 + checksum: de4b53db1063e618ec2eca0f7965d9137cabe98cf6be9272efe6c86b47c17b987383df8574861bcced18ebd590764125a901d5506082be84a8b8e364bf05f119 + languageName: node + linkType: hard + "sade@npm:^1.7.3": version: 1.8.1 resolution: "sade@npm:1.8.1" @@ -7489,20 +15035,20 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 - languageName: node - linkType: hard - -"safe-buffer@npm:~5.1.1": +"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": version: 5.1.2 resolution: "safe-buffer@npm:5.1.2" checksum: f2f1f7943ca44a594893a852894055cf619c1fbcb611237fc39e461ae751187e7baf4dc391a72125e0ac4fb2d8c5c0b3c71529622e6a58f46b960211e704903c languageName: node linkType: hard +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + languageName: node + linkType: hard + "safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -7510,6 +15056,68 @@ __metadata: languageName: node linkType: hard +"sax@npm:^1.2.4": + version: 1.3.0 + resolution: "sax@npm:1.3.0" + checksum: 238ab3a9ba8c8f8aaf1c5ea9120386391f6ee0af52f1a6a40bbb6df78241dd05d782f2359d614ac6aae08c4c4125208b456548a6cf68625aa4fe178486e63ecd + languageName: node + linkType: hard + +"scheduler@npm:^0.20.2": + version: 0.20.2 + resolution: "scheduler@npm:0.20.2" + dependencies: + loose-envify: ^1.1.0 + object-assign: ^4.1.1 + checksum: c4b35cf967c8f0d3e65753252d0f260271f81a81e427241295c5a7b783abf4ea9e905f22f815ab66676f5313be0a25f47be582254db8f9241b259213e999b8fc + languageName: node + linkType: hard + +"schema-utils@npm:2.7.0": + version: 2.7.0 + resolution: "schema-utils@npm:2.7.0" + dependencies: + "@types/json-schema": ^7.0.4 + ajv: ^6.12.2 + ajv-keywords: ^3.4.1 + checksum: 8889325b0ee1ae6a8f5d6aaa855c71e136ebbb7fd731b01a9d3ec8225dcb245f644c47c50104db4c741983b528cdff8558570021257d4d397ec6aaecd9172a8e + languageName: node + linkType: hard + +"schema-utils@npm:^2.6.5": + version: 2.7.1 + resolution: "schema-utils@npm:2.7.1" + dependencies: + "@types/json-schema": ^7.0.5 + ajv: ^6.12.4 + ajv-keywords: ^3.5.2 + checksum: 32c62fc9e28edd101e1bd83453a4216eb9bd875cc4d3775e4452b541908fa8f61a7bbac8ffde57484f01d7096279d3ba0337078e85a918ecbeb72872fb09fb2b + languageName: node + linkType: hard + +"schema-utils@npm:^3.0.0, schema-utils@npm:^3.1.1, schema-utils@npm:^3.2.0": + version: 3.3.0 + resolution: "schema-utils@npm:3.3.0" + dependencies: + "@types/json-schema": ^7.0.8 + ajv: ^6.12.5 + ajv-keywords: ^3.5.2 + checksum: ea56971926fac2487f0757da939a871388891bc87c6a82220d125d587b388f1704788f3706e7f63a7b70e49fc2db974c41343528caea60444afd5ce0fe4b85c0 + languageName: node + linkType: hard + +"schema-utils@npm:^4.0.0": + version: 4.2.0 + resolution: "schema-utils@npm:4.2.0" + dependencies: + "@types/json-schema": ^7.0.9 + ajv: ^8.9.0 + ajv-formats: ^2.1.1 + ajv-keywords: ^5.1.0 + checksum: 26a0463d47683258106e6652e9aeb0823bf0b85843039e068b57da1892f7ae6b6b1094d48e9ed5ba5cbe9f7166469d880858b9d91abe8bd249421eb813850cde + languageName: node + linkType: hard + "scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0": version: 3.0.1 resolution: "scrypt-js@npm:3.0.1" @@ -7529,7 +15137,42 @@ __metadata: languageName: node linkType: hard -"semver@npm:^5.5.0": +"section-matter@npm:^1.0.0": + version: 1.0.0 + resolution: "section-matter@npm:1.0.0" + dependencies: + extend-shallow: ^2.0.1 + kind-of: ^6.0.0 + checksum: 3cc4131705493b2955729b075dcf562359bba66183debb0332752dc9cad35616f6da7a23e42b6cab45cd2e4bb5cda113e9e84c8f05aee77adb6b0289a0229101 + languageName: node + linkType: hard + +"select-hose@npm:^2.0.0": + version: 2.0.0 + resolution: "select-hose@npm:2.0.0" + checksum: d7e5fcc695a4804209d232a1b18624a5134be334d4e1114b0721f7a5e72bd73da483dcf41528c1af4f4f4892ad7cfd6a1e55c8ffb83f9c9fe723b738db609dbb + languageName: node + linkType: hard + +"selfsigned@npm:^2.1.1": + version: 2.1.1 + resolution: "selfsigned@npm:2.1.1" + dependencies: + node-forge: ^1 + checksum: aa9ce2150a54838978d5c0aee54d7ebe77649a32e4e690eb91775f71fdff773874a4fbafd0ac73d8ec3b702ff8a395c604df4f8e8868528f36fd6c15076fb43a + languageName: node + linkType: hard + +"semver-diff@npm:^3.1.1": + version: 3.1.1 + resolution: "semver-diff@npm:3.1.1" + dependencies: + semver: ^6.3.0 + checksum: 8bbe5a5d7add2d5e51b72314a9215cd294d71f41cdc2bf6bd59ee76411f3610b576172896f1d191d0d7294cb9f2f847438d2ee158adacc0c224dca79052812fe + languageName: node + linkType: hard + +"semver@npm:^5.4.1, semver@npm:^5.5.0": version: 5.7.2 resolution: "semver@npm:5.7.2" bin: @@ -7538,7 +15181,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.3.0": +"semver@npm:^6.0.0, semver@npm:^6.2.0, semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" bin: @@ -7547,7 +15190,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4": +"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:^7.5.4": version: 7.5.4 resolution: "semver@npm:7.5.4" dependencies: @@ -7558,6 +15201,27 @@ __metadata: languageName: node linkType: hard +"send@npm:0.18.0": + version: 0.18.0 + resolution: "send@npm:0.18.0" + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + etag: ~1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: ~1.2.1 + statuses: 2.0.1 + checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 + languageName: node + linkType: hard + "serialize-error@npm:^7.0.1": version: 7.0.1 resolution: "serialize-error@npm:7.0.1" @@ -7576,6 +15240,58 @@ __metadata: languageName: node linkType: hard +"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.1": + version: 6.0.1 + resolution: "serialize-javascript@npm:6.0.1" + dependencies: + randombytes: ^2.1.0 + checksum: 3c4f4cb61d0893b988415bdb67243637333f3f574e9e9cc9a006a2ced0b390b0b3b44aef8d51c951272a9002ec50885eefdc0298891bc27eb2fe7510ea87dc4f + languageName: node + linkType: hard + +"serve-handler@npm:^6.1.3": + version: 6.1.5 + resolution: "serve-handler@npm:6.1.5" + dependencies: + bytes: 3.0.0 + content-disposition: 0.5.2 + fast-url-parser: 1.1.3 + mime-types: 2.1.18 + minimatch: 3.1.2 + path-is-inside: 1.0.2 + path-to-regexp: 2.2.1 + range-parser: 1.2.0 + checksum: 7a98ca9cbf8692583b6cde4deb3941cff900fa38bf16adbfccccd8430209bab781e21d9a1f61c9c03e226f9f67689893bbce25941368f3ddaf985fc3858b49dc + languageName: node + linkType: hard + +"serve-index@npm:^1.9.1": + version: 1.9.1 + resolution: "serve-index@npm:1.9.1" + dependencies: + accepts: ~1.3.4 + batch: 0.6.1 + debug: 2.6.9 + escape-html: ~1.0.3 + http-errors: ~1.6.2 + mime-types: ~2.1.17 + parseurl: ~1.3.2 + checksum: e2647ce13379485b98a53ba2ea3fbad4d44b57540d00663b02b976e426e6194d62ac465c0d862cb7057f65e0de8ab8a684aa095427a4b8612412eca0d300d22f + languageName: node + linkType: hard + +"serve-static@npm:1.15.0": + version: 1.15.0 + resolution: "serve-static@npm:1.15.0" + dependencies: + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + parseurl: ~1.3.3 + send: 0.18.0 + checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d + languageName: node + linkType: hard + "set-blocking@npm:^2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0" @@ -7616,6 +15332,22 @@ __metadata: languageName: node linkType: hard +"shallow-clone@npm:^3.0.0": + version: 3.0.1 + resolution: "shallow-clone@npm:3.0.1" + dependencies: + kind-of: ^6.0.2 + checksum: 39b3dd9630a774aba288a680e7d2901f5c0eae7b8387fc5c8ea559918b29b3da144b7bdb990d7ccd9e11be05508ac9e459ce51d01fd65e583282f6ffafcba2e7 + languageName: node + linkType: hard + +"shallowequal@npm:^1.1.0": + version: 1.1.0 + resolution: "shallowequal@npm:1.1.0" + checksum: f4c1de0837f106d2dbbfd5d0720a5d059d1c66b42b580965c8f06bb1db684be8783538b684092648c981294bf817869f743a066538771dbecb293df78f765e00 + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -7632,6 +15364,26 @@ __metadata: languageName: node linkType: hard +"shell-quote@npm:^1.7.3, shell-quote@npm:^1.8.1": + version: 1.8.1 + resolution: "shell-quote@npm:1.8.1" + checksum: 5f01201f4ef504d4c6a9d0d283fa17075f6770bfbe4c5850b074974c68062f37929ca61700d95ad2ac8822e14e8c4b990ca0e6e9272e64befd74ce5e19f0736b + languageName: node + linkType: hard + +"shelljs@npm:^0.8.5": + version: 0.8.5 + resolution: "shelljs@npm:0.8.5" + dependencies: + glob: ^7.0.0 + interpret: ^1.0.0 + rechoir: ^0.6.2 + bin: + shjs: bin/shjs + checksum: 7babc46f732a98f4c054ec1f048b55b9149b98aa2da32f6cf9844c434b43c6251efebd6eec120937bd0999e13811ebd45efe17410edb3ca938f82f9381302748 + languageName: node + linkType: hard + "side-channel@npm:^1.0.4": version: 1.0.4 resolution: "side-channel@npm:1.0.4" @@ -7657,6 +15409,38 @@ __metadata: languageName: node linkType: hard +"sirv@npm:^2.0.3": + version: 2.0.3 + resolution: "sirv@npm:2.0.3" + dependencies: + "@polka/url": ^1.0.0-next.20 + mrmime: ^1.0.0 + totalist: ^3.0.0 + checksum: e2dfd4c97735a6ad6d842d0eec2cd9e3919ff0e46f0d228248c5753ad4b70b832711e77e1259c031c439cdb08303cc54d923685c92b0e890145cc733af7c5568 + languageName: node + linkType: hard + +"sisteransi@npm:^1.0.5": + version: 1.0.5 + resolution: "sisteransi@npm:1.0.5" + checksum: aba6438f46d2bfcef94cf112c835ab395172c75f67453fe05c340c770d3c402363018ae1ab4172a1026a90c47eaccf3af7b6ff6fa749a680c2929bd7fa2b37a4 + languageName: node + linkType: hard + +"sitemap@npm:^7.1.1": + version: 7.1.1 + resolution: "sitemap@npm:7.1.1" + dependencies: + "@types/node": ^17.0.5 + "@types/sax": ^1.2.1 + arg: ^5.0.0 + sax: ^1.2.4 + bin: + sitemap: dist/cli.js + checksum: 87a6d21b0d4a33b8c611d3bb8543d02b813c0ebfce014213ef31849b5c1439005644f19ad1593ec89815f6101355f468c9a02c251d09aa03f6fddd17e23c4be4 + languageName: node + linkType: hard + "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" @@ -7706,6 +15490,17 @@ __metadata: languageName: node linkType: hard +"sockjs@npm:^0.3.24": + version: 0.3.24 + resolution: "sockjs@npm:0.3.24" + dependencies: + faye-websocket: ^0.11.3 + uuid: ^8.3.2 + websocket-driver: ^0.7.4 + checksum: 355309b48d2c4e9755349daa29cea1c0d9ee23e49b983841c6bf7a20276b00d3c02343f9f33f26d2ee8b261a5a02961b52a25c8da88b2538c5b68d3071b4934c + languageName: node + linkType: hard + "socks-proxy-agent@npm:^7.0.0": version: 7.0.0 resolution: "socks-proxy-agent@npm:7.0.0" @@ -7746,7 +15541,21 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:^0.5.13": +"sort-css-media-queries@npm:2.1.0": + version: 2.1.0 + resolution: "sort-css-media-queries@npm:2.1.0" + checksum: 25cb8f08b148a2ed83d0bc1cf20ddb888d3dee2a3c986896099a21b28b999d5cca3e46a9ef64381bb36fca0fc820471713f2e8af2729ecc6e108ab2b3b315ea9 + languageName: node + linkType: hard + +"source-map-js@npm:^1.0.2": + version: 1.0.2 + resolution: "source-map-js@npm:1.0.2" + checksum: c049a7fc4deb9a7e9b481ae3d424cc793cb4845daa690bc5a05d428bf41bf231ced49b4cf0c9e77f9d42fdb3d20d6187619fc586605f5eabe995a316da8d377c + languageName: node + linkType: hard + +"source-map-support@npm:^0.5.13, source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" dependencies: @@ -7756,7 +15565,14 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.6.0": +"source-map@npm:^0.5.0": + version: 0.5.7 + resolution: "source-map@npm:0.5.7" + checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d + languageName: node + linkType: hard + +"source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0": version: 0.6.1 resolution: "source-map@npm:0.6.1" checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 @@ -7770,6 +15586,40 @@ __metadata: languageName: node linkType: hard +"space-separated-tokens@npm:^1.0.0": + version: 1.1.5 + resolution: "space-separated-tokens@npm:1.1.5" + checksum: 8ef68f1cfa8ccad316b7f8d0df0919d0f1f6d32101e8faeee34ea3a923ce8509c1ad562f57388585ee4951e92d27afa211ed0a077d3d5995b5ba9180331be708 + languageName: node + linkType: hard + +"spdy-transport@npm:^3.0.0": + version: 3.0.0 + resolution: "spdy-transport@npm:3.0.0" + dependencies: + debug: ^4.1.0 + detect-node: ^2.0.4 + hpack.js: ^2.1.6 + obuf: ^1.1.2 + readable-stream: ^3.0.6 + wbuf: ^1.7.3 + checksum: 0fcaad3b836fb1ec0bdd39fa7008b9a7a84a553f12be6b736a2512613b323207ffc924b9551cef0378f7233c85916cff1118652e03a730bdb97c0e042243d56c + languageName: node + linkType: hard + +"spdy@npm:^4.0.2": + version: 4.0.2 + resolution: "spdy@npm:4.0.2" + dependencies: + debug: ^4.1.0 + handle-thing: ^2.0.0 + http-deceiver: ^1.2.7 + select-hose: ^2.0.0 + spdy-transport: ^3.0.0 + checksum: 2c739d0ff6f56ad36d2d754d0261d5ec358457bea7cbf77b1b05b0c6464f2ce65b85f196305f50b7bd9120723eb94bae9933466f28e67e5cd8cde4e27f1d75f8 + languageName: node + linkType: hard + "split@npm:0.3": version: 0.3.3 resolution: "split@npm:0.3.3" @@ -7795,6 +15645,13 @@ __metadata: languageName: node linkType: hard +"stable@npm:^0.1.8": + version: 0.1.8 + resolution: "stable@npm:0.1.8" + checksum: 2ff482bb100285d16dd75cd8f7c60ab652570e8952c0bfa91828a2b5f646a0ff533f14596ea4eabd48bb7f4aeea408dce8f8515812b975d958a4cc4fa6b9dfeb + languageName: node + linkType: hard + "stack-utils@npm:^2.0.6": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" @@ -7813,6 +15670,13 @@ __metadata: languageName: node linkType: hard +"state-toggle@npm:^1.0.0": + version: 1.0.3 + resolution: "state-toggle@npm:1.0.3" + checksum: 17398af928413e8d8b866cf0c81fd1b1348bb7d65d8983126ff6ff2317a80d6ee023484fba0c54d8169f5aa544f125434a650ae3a71eddc935cae307d4692b4f + languageName: node + linkType: hard + "statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" @@ -7827,6 +15691,13 @@ __metadata: languageName: node linkType: hard +"std-env@npm:^3.0.1": + version: 3.4.3 + resolution: "std-env@npm:3.4.3" + checksum: bef186fb2baddda31911234b1e58fa18f181eb6930616aaec3b54f6d5db65f2da5daaa5f3b326b98445a7d50ca81d6fe8809ab4ebab85ecbe4a802f1b40921bf + languageName: node + linkType: hard + "stream-combiner@npm:~0.0.4": version: 0.0.4 resolution: "stream-combiner@npm:0.0.4" @@ -7852,7 +15723,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -7883,6 +15754,26 @@ __metadata: languageName: node linkType: hard +"string_decoder@npm:~1.1.1": + version: 1.1.1 + resolution: "string_decoder@npm:1.1.1" + dependencies: + safe-buffer: ~5.1.0 + checksum: 9ab7e56f9d60a28f2be697419917c50cac19f3e8e6c28ef26ed5f4852289fe0de5d6997d29becf59028556f2c62983790c1d9ba1e2a3cc401768ca12d5183a5b + languageName: node + linkType: hard + +"stringify-object@npm:^3.3.0": + version: 3.3.0 + resolution: "stringify-object@npm:3.3.0" + dependencies: + get-own-enumerable-property-symbols: ^3.0.0 + is-obj: ^1.0.1 + is-regexp: ^1.0.0 + checksum: 6827a3f35975cfa8572e8cd3ed4f7b262def260af18655c6fde549334acdac49ddba69f3c861ea5a6e9c5a4990fe4ae870b9c0e6c31019430504c94a83b7a154 + languageName: node + linkType: hard + "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -7901,6 +15792,13 @@ __metadata: languageName: node linkType: hard +"strip-bom-string@npm:^1.0.0": + version: 1.0.0 + resolution: "strip-bom-string@npm:1.0.0" + checksum: 5635a3656d8512a2c194d6c8d5dee7ef0dde6802f7be9413b91e201981ad4132506656d9cf14137f019fd50f0269390d91c7f6a2601b1bee039a4859cfce4934 + languageName: node + linkType: hard + "strip-final-newline@npm:^2.0.0": version: 2.0.0 resolution: "strip-final-newline@npm:2.0.0" @@ -7931,6 +15829,34 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 1074ccb63270d32ca28edfb0a281c96b94dc679077828135141f27d52a5a398ef5e78bcf22809d23cadc2b81dfbe345eb5fd8699b385c8b1128907dec4a7d1e1 + languageName: node + linkType: hard + +"style-to-object@npm:0.3.0, style-to-object@npm:^0.3.0": + version: 0.3.0 + resolution: "style-to-object@npm:0.3.0" + dependencies: + inline-style-parser: 0.1.1 + checksum: 4d7084015207f2a606dfc10c29cb5ba569f2fe8005551df7396110dd694d6ff650f2debafa95bd5d147dfb4ca50f57868e2a7f91bf5d11ef734fe7ccbd7abf59 + languageName: node + linkType: hard + +"stylehacks@npm:^5.1.1": + version: 5.1.1 + resolution: "stylehacks@npm:5.1.1" + dependencies: + browserslist: ^4.21.4 + postcss-selector-parser: ^6.0.4 + peerDependencies: + postcss: ^8.2.15 + checksum: 11175366ef52de65bf06cefba0ddc9db286dc3a1451fd2989e74c6ea47091a02329a4bf6ce10b1a36950056927b6bbbe47c5ab3a1f4c7032df932d010fbde5a2 + languageName: node + linkType: hard + "superstruct@npm:^1.0.3": version: 1.0.3 resolution: "superstruct@npm:1.0.3" @@ -7950,7 +15876,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:8.1.1": +"supports-color@npm:8.1.1, supports-color@npm:^8.0.0": version: 8.1.1 resolution: "supports-color@npm:8.1.1" dependencies: @@ -7984,6 +15910,30 @@ __metadata: languageName: node linkType: hard +"svg-parser@npm:^2.0.4": + version: 2.0.4 + resolution: "svg-parser@npm:2.0.4" + checksum: b3de6653048212f2ae7afe4a423e04a76ec6d2d06e1bf7eacc618a7c5f7df7faa5105561c57b94579ec831fbbdbf5f190ba56a9205ff39ed13eabdf8ab086ddf + languageName: node + linkType: hard + +"svgo@npm:^2.7.0, svgo@npm:^2.8.0": + version: 2.8.0 + resolution: "svgo@npm:2.8.0" + dependencies: + "@trysound/sax": 0.2.0 + commander: ^7.2.0 + css-select: ^4.1.3 + css-tree: ^1.1.3 + csso: ^4.2.0 + picocolors: ^1.0.0 + stable: ^0.1.8 + bin: + svgo: bin/svgo + checksum: b92f71a8541468ffd0b81b8cdb36b1e242eea320bf3c1a9b2c8809945853e9d8c80c19744267eb91cabf06ae9d5fff3592d677df85a31be4ed59ff78534fa420 + languageName: node + linkType: hard + "synckit@npm:^0.8.5": version: 0.8.5 resolution: "synckit@npm:0.8.5" @@ -8011,6 +15961,20 @@ __metadata: languageName: node linkType: hard +"tapable@npm:^1.0.0": + version: 1.1.3 + resolution: "tapable@npm:1.1.3" + checksum: 53ff4e7c3900051c38cc4faab428ebfd7e6ad0841af5a7ac6d5f3045c5b50e88497bfa8295b4b3fbcadd94993c9e358868b78b9fb249a76cb8b018ac8dccafd7 + languageName: node + linkType: hard + +"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0": + version: 2.2.1 + resolution: "tapable@npm:2.2.1" + checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51 + languageName: node + linkType: hard + "tar-fs@npm:2.1.1": version: 2.1.1 resolution: "tar-fs@npm:2.1.1" @@ -8057,6 +16021,42 @@ __metadata: languageName: node linkType: hard +"terser-webpack-plugin@npm:^5.3.3, terser-webpack-plugin@npm:^5.3.7": + version: 5.3.9 + resolution: "terser-webpack-plugin@npm:5.3.9" + dependencies: + "@jridgewell/trace-mapping": ^0.3.17 + jest-worker: ^27.4.5 + schema-utils: ^3.1.1 + serialize-javascript: ^6.0.1 + terser: ^5.16.8 + peerDependencies: + webpack: ^5.1.0 + peerDependenciesMeta: + "@swc/core": + optional: true + esbuild: + optional: true + uglify-js: + optional: true + checksum: 41705713d6f9cb83287936b21e27c658891c78c4392159f5148b5623f0e8c48559869779619b058382a4c9758e7820ea034695e57dc7c474b4962b79f553bc5f + languageName: node + linkType: hard + +"terser@npm:^5.10.0, terser@npm:^5.16.8": + version: 5.21.0 + resolution: "terser@npm:5.21.0" + dependencies: + "@jridgewell/source-map": ^0.3.3 + acorn: ^8.8.2 + commander: ^2.20.0 + source-map-support: ~0.5.20 + bin: + terser: bin/terser + checksum: 130f1567af1ffa4ddb067651bb284a01b45b5c83e82b3a072a5ff94b0b00ac35090f89c8714631a4a45972f65187bc149fc7144380611f437e1e3d9e174b136b + languageName: node + linkType: hard + "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" @@ -8071,6 +16071,13 @@ __metadata: languageName: node linkType: hard +"thunky@npm:^1.0.2": + version: 1.1.0 + resolution: "thunky@npm:1.1.0" + checksum: 993096c472b6b8f30e29dc777a8d17720e4cab448375041f20c0cb802a09a7fb2217f2a3e8cdc11851faa71c957e2db309357367fc9d7af3cb7a4d00f4b66034 + languageName: node + linkType: hard + "time-zone@npm:^1.0.0": version: 1.0.0 resolution: "time-zone@npm:1.0.0" @@ -8078,6 +16085,20 @@ __metadata: languageName: node linkType: hard +"tiny-invariant@npm:^1.0.2": + version: 1.3.1 + resolution: "tiny-invariant@npm:1.3.1" + checksum: 872dbd1ff20a21303a2fd20ce3a15602cfa7fcf9b228bd694a52e2938224313b5385a1078cb667ed7375d1612194feaca81c4ecbe93121ca1baebe344de4f84c + languageName: node + linkType: hard + +"tiny-warning@npm:^1.0.0": + version: 1.0.3 + resolution: "tiny-warning@npm:1.0.3" + checksum: da62c4acac565902f0624b123eed6dd3509bc9a8d30c06e017104bedcf5d35810da8ff72864400ad19c5c7806fc0a8323c68baf3e326af7cb7d969f846100d71 + languageName: node + linkType: hard + "titleize@npm:^3.0.0": version: 3.0.0 resolution: "titleize@npm:3.0.0" @@ -8094,6 +16115,20 @@ __metadata: languageName: node linkType: hard +"to-fast-properties@npm:^2.0.0": + version: 2.0.0 + resolution: "to-fast-properties@npm:2.0.0" + checksum: be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 + languageName: node + linkType: hard + +"to-readable-stream@npm:^1.0.0": + version: 1.0.0 + resolution: "to-readable-stream@npm:1.0.0" + checksum: 2bd7778490b6214a2c40276065dd88949f4cf7037ce3964c76838b8cb212893aeb9cceaaf4352a4c486e3336214c350270f3263e1ce7a0c38863a715a4d9aeb5 + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -8117,6 +16152,13 @@ __metadata: languageName: node linkType: hard +"totalist@npm:^3.0.0": + version: 3.0.1 + resolution: "totalist@npm:3.0.1" + checksum: 5132d562cf88ff93fd710770a92f31dbe67cc19b5c6ccae2efc0da327f0954d211bbfd9456389655d726c624f284b4a23112f56d1da931ca7cfabbe1f45e778a + languageName: node + linkType: hard + "tr46@npm:^3.0.0": version: 3.0.0 resolution: "tr46@npm:3.0.0" @@ -8133,6 +16175,27 @@ __metadata: languageName: node linkType: hard +"trim-trailing-lines@npm:^1.0.0": + version: 1.1.4 + resolution: "trim-trailing-lines@npm:1.1.4" + checksum: 5d39d21c0d4b258667012fcd784f73129e148ea1c213b1851d8904f80499fc91df6710c94c7dd49a486a32da2b9cb86020dda79f285a9a2586cfa622f80490c2 + languageName: node + linkType: hard + +"trim@npm:0.0.1": + version: 0.0.1 + resolution: "trim@npm:0.0.1" + checksum: 2b4646dff99a222e8e1526edd4e3a43bbd925af0b8e837c340455d250157e7deefaa4da49bb891ab841e5c27b1afc5e9e32d4b57afb875d2dfcabf4e319b8f7f + languageName: node + linkType: hard + +"trough@npm:^1.0.0": + version: 1.0.5 + resolution: "trough@npm:1.0.5" + checksum: d6c8564903ed00e5258bab92134b020724dbbe83148dc72e4bf6306c03ed8843efa1bcc773fa62410dd89161ecb067432dd5916501793508a9506cacbc408e25 + languageName: node + linkType: hard + "ts-api-utils@npm:^1.0.1": version: 1.0.3 resolution: "ts-api-utils@npm:1.0.3" @@ -8216,7 +16279,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0": +"tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad @@ -8302,7 +16365,14 @@ __metadata: languageName: node linkType: hard -"type-is@npm:^1.6.16": +"type-fest@npm:^2.5.0": + version: 2.19.0 + resolution: "type-fest@npm:2.19.0" + checksum: a4ef07ece297c9fba78fc1bd6d85dff4472fe043ede98bd4710d2615d15776902b595abf62bd78339ed6278f021235fb28a96361f8be86ed754f778973a0d278 + languageName: node + linkType: hard + +"type-is@npm:^1.6.16, type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" dependencies: @@ -8312,6 +16382,15 @@ __metadata: languageName: node linkType: hard +"typedarray-to-buffer@npm:^3.1.5": + version: 3.1.5 + resolution: "typedarray-to-buffer@npm:3.1.5" + dependencies: + is-typedarray: ^1.0.0 + checksum: 99c11aaa8f45189fcfba6b8a4825fd684a321caa9bd7a76a27cf0c7732c174d198b99f449c52c3818107430b5f41c0ccbbfb75cb2ee3ca4a9451710986d61a60 + languageName: node + linkType: hard + "typescript@npm:4.9.4": version: 4.9.4 resolution: "typescript@npm:4.9.4" @@ -8379,54 +16458,217 @@ __metadata: languageName: node linkType: hard -"typical@npm:^7.1.1": - version: 7.1.1 - resolution: "typical@npm:7.1.1" - checksum: 292c64a2e3d2296fd1b7a92bbe3a9ad683f643f3faa8c9b45f6911105da54246817a3e2a4f0fdd01bb4c49d2b940618ad30b6771ac1c94bf690a40c706f657fa +"typical@npm:^7.1.1": + version: 7.1.1 + resolution: "typical@npm:7.1.1" + checksum: 292c64a2e3d2296fd1b7a92bbe3a9ad683f643f3faa8c9b45f6911105da54246817a3e2a4f0fdd01bb4c49d2b940618ad30b6771ac1c94bf690a40c706f657fa + languageName: node + linkType: hard + +"ua-parser-js@npm:^1.0.33, ua-parser-js@npm:^1.0.35": + version: 1.0.36 + resolution: "ua-parser-js@npm:1.0.36" + checksum: 5b2c8a5e3443dfbba7624421805de946457c26ae167cb2275781a2729d1518f7067c9d5c74c3b0acac4b9ff3278cae4eace08ca6eecb63848bc3b2f6a63cc975 + languageName: node + linkType: hard + +"unbzip2-stream@npm:1.4.3": + version: 1.4.3 + resolution: "unbzip2-stream@npm:1.4.3" + dependencies: + buffer: ^5.2.1 + through: ^2.3.8 + checksum: 0e67c4a91f4fa0fc7b4045f8b914d3498c2fc2e8c39c359977708ec85ac6d6029840e97f508675fdbdf21fcb8d276ca502043406f3682b70f075e69aae626d1d + languageName: node + linkType: hard + +"undici@npm:^5.14.0": + version: 5.25.3 + resolution: "undici@npm:5.25.3" + dependencies: + "@fastify/busboy": ^2.0.0 + checksum: 65b814b7d8b06dab2d41c250d123663fe94edb78cf1a891cf3476569ea66dc425c7d4ba52b91d6f8ed6eba24613dd28e4a5070c372063532c3b997cd343ccc96 + languageName: node + linkType: hard + +"unherit@npm:^1.0.4": + version: 1.1.3 + resolution: "unherit@npm:1.1.3" + dependencies: + inherits: ^2.0.0 + xtend: ^4.0.0 + checksum: fd7922f84fc0bfb7c4df6d1f5a50b5b94a0218e3cda98a54dbbd209226ddd4072d742d3df44d0e295ab08d5ccfd304a1e193dfe31a86d2a91b7cb9fdac093194 + languageName: node + linkType: hard + +"unicode-canonical-property-names-ecmascript@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" + checksum: 39be078afd014c14dcd957a7a46a60061bc37c4508ba146517f85f60361acf4c7539552645ece25de840e17e293baa5556268d091ca6762747fdd0c705001a45 + languageName: node + linkType: hard + +"unicode-match-property-ecmascript@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-match-property-ecmascript@npm:2.0.0" + dependencies: + unicode-canonical-property-names-ecmascript: ^2.0.0 + unicode-property-aliases-ecmascript: ^2.0.0 + checksum: 1f34a7434a23df4885b5890ac36c5b2161a809887000be560f56ad4b11126d433c0c1c39baf1016bdabed4ec54829a6190ee37aa24919aa116dc1a5a8a62965a + languageName: node + linkType: hard + +"unicode-match-property-value-ecmascript@npm:^2.1.0": + version: 2.1.0 + resolution: "unicode-match-property-value-ecmascript@npm:2.1.0" + checksum: 8d6f5f586b9ce1ed0e84a37df6b42fdba1317a05b5df0c249962bd5da89528771e2d149837cad11aa26bcb84c35355cb9f58a10c3d41fa3b899181ece6c85220 + languageName: node + linkType: hard + +"unicode-property-aliases-ecmascript@npm:^2.0.0": + version: 2.1.0 + resolution: "unicode-property-aliases-ecmascript@npm:2.1.0" + checksum: 243524431893649b62cc674d877bd64ef292d6071dd2fd01ab4d5ad26efbc104ffcd064f93f8a06b7e4ec54c172bf03f6417921a0d8c3a9994161fe1f88f815b + languageName: node + linkType: hard + +"unified@npm:9.2.0": + version: 9.2.0 + resolution: "unified@npm:9.2.0" + dependencies: + bail: ^1.0.0 + extend: ^3.0.0 + is-buffer: ^2.0.0 + is-plain-obj: ^2.0.0 + trough: ^1.0.0 + vfile: ^4.0.0 + checksum: 0cac4ae119893fbd49d309b4db48595e4d4e9f0a2dc1dde4d0074059f9a46012a2905f37c1346715e583f30c970bc8078db8462675411d39ff5036ae18b4fb8a + languageName: node + linkType: hard + +"unified@npm:^9.0.0, unified@npm:^9.2.2": + version: 9.2.2 + resolution: "unified@npm:9.2.2" + dependencies: + bail: ^1.0.0 + extend: ^3.0.0 + is-buffer: ^2.0.0 + is-plain-obj: ^2.0.0 + trough: ^1.0.0 + vfile: ^4.0.0 + checksum: 7c24461be7de4145939739ce50d18227c5fbdf9b3bc5a29dabb1ce26dd3e8bd4a1c385865f6f825f3b49230953ee8b591f23beab3bb3643e3e9dc37aa8a089d5 + languageName: node + linkType: hard + +"unique-filename@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-filename@npm:3.0.0" + dependencies: + unique-slug: ^4.0.0 + checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df + languageName: node + linkType: hard + +"unique-slug@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: ^0.1.4 + checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 + languageName: node + linkType: hard + +"unique-string@npm:^2.0.0": + version: 2.0.0 + resolution: "unique-string@npm:2.0.0" + dependencies: + crypto-random-string: ^2.0.0 + checksum: ef68f639136bcfe040cf7e3cd7a8dff076a665288122855148a6f7134092e6ed33bf83a7f3a9185e46c98dddc445a0da6ac25612afa1a7c38b8b654d6c02498e + languageName: node + linkType: hard + +"unist-builder@npm:2.0.3, unist-builder@npm:^2.0.0": + version: 2.0.3 + resolution: "unist-builder@npm:2.0.3" + checksum: e946fdf77dbfc320feaece137ce4959ae2da6614abd1623bd39512dc741a9d5f313eb2ba79f8887d941365dccddec7fef4e953827475e392bf49b45336f597f6 + languageName: node + linkType: hard + +"unist-util-find-after@npm:^3.0.0": + version: 3.0.0 + resolution: "unist-util-find-after@npm:3.0.0" + dependencies: + unist-util-is: ^4.0.0 + checksum: daa9a28f6cdf533a72ce7ec4864dbe0f11f0fd3efd337b54c08a8a9a47cdc8d10a299cd984d7f512a57e97af012df052210a51aab7c9afd6b1e24da3b2d0a714 + languageName: node + linkType: hard + +"unist-util-generated@npm:^1.0.0": + version: 1.1.6 + resolution: "unist-util-generated@npm:1.1.6" + checksum: 86239ff88a08800d52198f2f0e15911f05bab2dad17cef95550f7c2728f15ebb0344694fcc3101d05762d88adaf86cb85aa7a3300fedabd0b6d7d00b41cdcb7f + languageName: node + linkType: hard + +"unist-util-is@npm:^4.0.0": + version: 4.1.0 + resolution: "unist-util-is@npm:4.1.0" + checksum: 726484cd2adc9be75a939aeedd48720f88294899c2e4a3143da413ae593f2b28037570730d5cf5fd910ff41f3bc1501e3d636b6814c478d71126581ef695f7ea + languageName: node + linkType: hard + +"unist-util-position@npm:^3.0.0": + version: 3.1.0 + resolution: "unist-util-position@npm:3.1.0" + checksum: 10b3952e32a1ffabbecad41c3946237f7059f5bb6436796da05531a285f50b97e4f37cfc2f7164676d041063f40fe1ad92fbb8ca38d3ae8747328ebe738d738f languageName: node linkType: hard -"ua-parser-js@npm:^1.0.33": - version: 1.0.36 - resolution: "ua-parser-js@npm:1.0.36" - checksum: 5b2c8a5e3443dfbba7624421805de946457c26ae167cb2275781a2729d1518f7067c9d5c74c3b0acac4b9ff3278cae4eace08ca6eecb63848bc3b2f6a63cc975 +"unist-util-remove-position@npm:^2.0.0": + version: 2.0.1 + resolution: "unist-util-remove-position@npm:2.0.1" + dependencies: + unist-util-visit: ^2.0.0 + checksum: 4149294969f1a78a367b5d03eb0a138aa8320a39e1b15686647a2bec5945af3df27f2936a1e9752ecbb4a82dc23bd86f7e5a0ee048e5eeaedc2deb9237872795 languageName: node linkType: hard -"unbzip2-stream@npm:1.4.3": - version: 1.4.3 - resolution: "unbzip2-stream@npm:1.4.3" +"unist-util-remove@npm:^2.0.0": + version: 2.1.0 + resolution: "unist-util-remove@npm:2.1.0" dependencies: - buffer: ^5.2.1 - through: ^2.3.8 - checksum: 0e67c4a91f4fa0fc7b4045f8b914d3498c2fc2e8c39c359977708ec85ac6d6029840e97f508675fdbdf21fcb8d276ca502043406f3682b70f075e69aae626d1d + unist-util-is: ^4.0.0 + checksum: 99e54f3ea0523f8cf957579a6e84e5b58427bffab929cc7f6aa5119581f929db683dd4691ea5483df0c272f486dda9dbd04f4ab74dca6cae1f3ebe8e4261a4d9 languageName: node linkType: hard -"undici@npm:^5.14.0": - version: 5.25.3 - resolution: "undici@npm:5.25.3" +"unist-util-stringify-position@npm:^2.0.0": + version: 2.0.3 + resolution: "unist-util-stringify-position@npm:2.0.3" dependencies: - "@fastify/busboy": ^2.0.0 - checksum: 65b814b7d8b06dab2d41c250d123663fe94edb78cf1a891cf3476569ea66dc425c7d4ba52b91d6f8ed6eba24613dd28e4a5070c372063532c3b997cd343ccc96 + "@types/unist": ^2.0.2 + checksum: f755cadc959f9074fe999578a1a242761296705a7fe87f333a37c00044de74ab4b184b3812989a57d4cd12211f0b14ad397b327c3a594c7af84361b1c25a7f09 languageName: node linkType: hard -"unique-filename@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-filename@npm:3.0.0" +"unist-util-visit-parents@npm:^3.0.0": + version: 3.1.1 + resolution: "unist-util-visit-parents@npm:3.1.1" dependencies: - unique-slug: ^4.0.0 - checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df + "@types/unist": ^2.0.0 + unist-util-is: ^4.0.0 + checksum: 1170e397dff88fab01e76d5154981666eb0291019d2462cff7a2961a3e76d3533b42eaa16b5b7e2d41ad42a5ea7d112301458283d255993e660511387bf67bc3 languageName: node linkType: hard -"unique-slug@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-slug@npm:4.0.0" +"unist-util-visit@npm:2.0.3, unist-util-visit@npm:^2.0.0, unist-util-visit@npm:^2.0.3": + version: 2.0.3 + resolution: "unist-util-visit@npm:2.0.3" dependencies: - imurmurhash: ^0.1.4 - checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 + "@types/unist": ^2.0.0 + unist-util-is: ^4.0.0 + unist-util-visit-parents: ^3.0.0 + checksum: 1fe19d500e212128f96d8c3cfa3312846e586b797748a1fd195fe6479f06bc90a6f6904deb08eefc00dd58e83a1c8a32fb8677252d2273ad7a5e624525b69b8f languageName: node linkType: hard @@ -8444,7 +16686,7 @@ __metadata: languageName: node linkType: hard -"unpipe@npm:1.0.0": +"unpipe@npm:1.0.0, unpipe@npm:~1.0.0": version: 1.0.0 resolution: "unpipe@npm:1.0.0" checksum: 4fa18d8d8d977c55cb09715385c203197105e10a6d220087ec819f50cb68870f02942244f1017565484237f1f8c5d3cd413631b1ae104d3096f24fdfde1b4aa2 @@ -8458,6 +16700,42 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.0.13": + version: 1.0.13 + resolution: "update-browserslist-db@npm:1.0.13" + dependencies: + escalade: ^3.1.1 + picocolors: ^1.0.0 + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 1e47d80182ab6e4ad35396ad8b61008ae2a1330221175d0abd37689658bdb61af9b705bfc41057fd16682474d79944fb2d86767c5ed5ae34b6276b9bed353322 + languageName: node + linkType: hard + +"update-notifier@npm:^5.1.0": + version: 5.1.0 + resolution: "update-notifier@npm:5.1.0" + dependencies: + boxen: ^5.0.0 + chalk: ^4.1.0 + configstore: ^5.0.1 + has-yarn: ^2.1.0 + import-lazy: ^2.1.0 + is-ci: ^2.0.0 + is-installed-globally: ^0.4.0 + is-npm: ^5.0.0 + is-yarn-global: ^0.3.0 + latest-version: ^5.1.0 + pupa: ^2.1.1 + semver: ^7.3.4 + semver-diff: ^3.1.1 + xdg-basedir: ^4.0.0 + checksum: 461e5e5b002419296d3868ee2abe0f9ab3e1846d9db642936d0c46f838872ec56069eddfe662c45ce1af0a8d6d5026353728de2e0a95ab2e3546a22ea077caf1 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -8467,13 +16745,104 @@ __metadata: languageName: node linkType: hard -"util-deprecate@npm:^1.0.1": +"url-loader@npm:^4.1.1": + version: 4.1.1 + resolution: "url-loader@npm:4.1.1" + dependencies: + loader-utils: ^2.0.0 + mime-types: ^2.1.27 + schema-utils: ^3.0.0 + peerDependencies: + file-loader: "*" + webpack: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + file-loader: + optional: true + checksum: c1122a992c6cff70a7e56dfc2b7474534d48eb40b2cc75467cde0c6972e7597faf8e43acb4f45f93c2473645dfd803bcbc20960b57544dd1e4c96e77f72ba6fd + languageName: node + linkType: hard + +"url-parse-lax@npm:^3.0.0": + version: 3.0.0 + resolution: "url-parse-lax@npm:3.0.0" + dependencies: + prepend-http: ^2.0.0 + checksum: 1040e357750451173132228036aff1fd04abbd43eac1fb3e4fca7495a078bcb8d33cb765fe71ad7e473d9c94d98fd67adca63bd2716c815a2da066198dd37217 + languageName: node + linkType: hard + +"use-composed-ref@npm:^1.3.0": + version: 1.3.0 + resolution: "use-composed-ref@npm:1.3.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: f771cbadfdc91e03b7ab9eb32d0fc0cc647755711801bf507e891ad38c4bbc5f02b2509acadf9c965ec9c5f2f642fd33bdfdfb17b0873c4ad0a9b1f5e5e724bf + languageName: node + linkType: hard + +"use-isomorphic-layout-effect@npm:^1.1.1": + version: 1.1.2 + resolution: "use-isomorphic-layout-effect@npm:1.1.2" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: a6532f7fc9ae222c3725ff0308aaf1f1ddbd3c00d685ef9eee6714fd0684de5cb9741b432fbf51e61a784e2955424864f7ea9f99734a02f237b17ad3e18ea5cb + languageName: node + linkType: hard + +"use-latest@npm:^1.2.1": + version: 1.2.1 + resolution: "use-latest@npm:1.2.1" + dependencies: + use-isomorphic-layout-effect: ^1.1.1 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: ed3f2ddddf6f21825e2ede4c2e0f0db8dcce5129802b69d1f0575fc1b42380436e8c76a6cd885d4e9aa8e292e60fb8b959c955f33c6a9123b83814a1a1875367 + languageName: node + linkType: hard + +"use-sync-external-store@npm:^1.2.0": + version: 1.2.0 + resolution: "use-sync-external-store@npm:1.2.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a + languageName: node + linkType: hard + +"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 languageName: node linkType: hard +"utila@npm:~0.4": + version: 0.4.0 + resolution: "utila@npm:0.4.0" + checksum: 97ffd3bd2bb80c773429d3fb8396469115cd190dded1e733f190d8b602bd0a1bcd6216b7ce3c4395ee3c79e3c879c19d268dbaae3093564cb169ad1212d436f4 + languageName: node + linkType: hard + +"utility-types@npm:^3.10.0": + version: 3.10.0 + resolution: "utility-types@npm:3.10.0" + checksum: 8f274415c6196ab62883b8bd98c9d2f8829b58016e4269aaa1ebd84184ac5dda7dc2ca45800c0d5e0e0650966ba063bf9a412aaeaea6850ca4440a391283d5c8 + languageName: node + linkType: hard + +"utils-merge@npm:1.0.1": + version: 1.0.1 + resolution: "utils-merge@npm:1.0.1" + checksum: c81095493225ecfc28add49c106ca4f09cdf56bc66731aa8dabc2edbbccb1e1bfe2de6a115e5c6a380d3ea166d1636410b62ef216bb07b3feb1cfde1d95d5080 + languageName: node + linkType: hard + "uuid@npm:^8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" @@ -8515,13 +16884,90 @@ __metadata: languageName: node linkType: hard -"vary@npm:^1.1.2": +"value-equal@npm:^1.0.1": + version: 1.0.1 + resolution: "value-equal@npm:1.0.1" + checksum: bb7ae1facc76b5cf8071aeb6c13d284d023fdb370478d10a5d64508e0e6e53bb459c4bbe34258df29d82e6f561f874f0105eba38de0e61fe9edd0bdce07a77a2 + languageName: node + linkType: hard + +"vary@npm:^1.1.2, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b languageName: node linkType: hard +"vfile-location@npm:^3.0.0, vfile-location@npm:^3.2.0": + version: 3.2.0 + resolution: "vfile-location@npm:3.2.0" + checksum: 9bb3df6d0be31b5dd2d8da0170c27b7045c64493a8ba7b6ff7af8596c524fc8896924b8dd85ae12d201eead2709217a0fbc44927b7264f4bbf0aa8027a78be9c + languageName: node + linkType: hard + +"vfile-message@npm:^2.0.0": + version: 2.0.4 + resolution: "vfile-message@npm:2.0.4" + dependencies: + "@types/unist": ^2.0.0 + unist-util-stringify-position: ^2.0.0 + checksum: 1bade499790f46ca5aba04bdce07a1e37c2636a8872e05cf32c26becc912826710b7eb063d30c5754fdfaeedc8a7658e78df10b3bc535c844890ec8a184f5643 + languageName: node + linkType: hard + +"vfile@npm:^4.0.0": + version: 4.2.1 + resolution: "vfile@npm:4.2.1" + dependencies: + "@types/unist": ^2.0.0 + is-buffer: ^2.0.0 + unist-util-stringify-position: ^2.0.0 + vfile-message: ^2.0.0 + checksum: ee5726e10d170472cde778fc22e0f7499caa096eb85babea5d0ce0941455b721037ee1c9e6ae506ca2803250acd313d0f464328ead0b55cfe7cb6315f1b462d6 + languageName: node + linkType: hard + +"wait-on@npm:^6.0.1": + version: 6.0.1 + resolution: "wait-on@npm:6.0.1" + dependencies: + axios: ^0.25.0 + joi: ^17.6.0 + lodash: ^4.17.21 + minimist: ^1.2.5 + rxjs: ^7.5.4 + bin: + wait-on: bin/wait-on + checksum: e4d62aa4145d99fe34747ccf7506d4b4d6e60dd677c0eb18a51e316d38116ace2d194e4b22a9eb7b767b0282f39878ddcc4ae9440dcb0c005c9150668747cf5b + languageName: node + linkType: hard + +"watchpack@npm:^2.4.0": + version: 2.4.0 + resolution: "watchpack@npm:2.4.0" + dependencies: + glob-to-regexp: ^0.4.1 + graceful-fs: ^4.1.2 + checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 + languageName: node + linkType: hard + +"wbuf@npm:^1.1.0, wbuf@npm:^1.7.3": + version: 1.7.3 + resolution: "wbuf@npm:1.7.3" + dependencies: + minimalistic-assert: ^1.0.0 + checksum: 2abc306c96930b757972a1c4650eb6b25b5d99f24088714957f88629e137db569368c5de0e57986c89ea70db2f1df9bba11a87cb6d0c8694b6f53a0159fab3bf + languageName: node + linkType: hard + +"web-namespaces@npm:^1.0.0": + version: 1.1.4 + resolution: "web-namespaces@npm:1.1.4" + checksum: 5149842ccbfbc56fe4f8758957b3f8c8616a281874a5bb84aa1b305e4436a9bad853d21c629a7b8f174902449e1489c7a6c724fccf60965077c5636bd8aed42b + languageName: node + linkType: hard + "web-streams-polyfill@npm:^3.0.3": version: 3.2.1 resolution: "web-streams-polyfill@npm:3.2.1" @@ -8543,6 +16989,181 @@ __metadata: languageName: node linkType: hard +"webpack-bundle-analyzer@npm:^4.5.0": + version: 4.9.1 + resolution: "webpack-bundle-analyzer@npm:4.9.1" + dependencies: + "@discoveryjs/json-ext": 0.5.7 + acorn: ^8.0.4 + acorn-walk: ^8.0.0 + commander: ^7.2.0 + escape-string-regexp: ^4.0.0 + gzip-size: ^6.0.0 + is-plain-object: ^5.0.0 + lodash.debounce: ^4.0.8 + lodash.escape: ^4.0.1 + lodash.flatten: ^4.4.0 + lodash.invokemap: ^4.6.0 + lodash.pullall: ^4.2.0 + lodash.uniqby: ^4.7.0 + opener: ^1.5.2 + picocolors: ^1.0.0 + sirv: ^2.0.3 + ws: ^7.3.1 + bin: + webpack-bundle-analyzer: lib/bin/analyzer.js + checksum: 7e891c28d5a903242893e55ecc714fa01d7ad6bedade143235c07091b235915349812fa048968462781d59187507962f38b6c61ed7d25fb836ba0ac0ee919a39 + languageName: node + linkType: hard + +"webpack-dev-middleware@npm:^5.3.1": + version: 5.3.3 + resolution: "webpack-dev-middleware@npm:5.3.3" + dependencies: + colorette: ^2.0.10 + memfs: ^3.4.3 + mime-types: ^2.1.31 + range-parser: ^1.2.1 + schema-utils: ^4.0.0 + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: dd332cc6da61222c43d25e5a2155e23147b777ff32fdf1f1a0a8777020c072fbcef7756360ce2a13939c3f534c06b4992a4d659318c4a7fe2c0530b52a8a6621 + languageName: node + linkType: hard + +"webpack-dev-server@npm:^4.9.3": + version: 4.15.1 + resolution: "webpack-dev-server@npm:4.15.1" + dependencies: + "@types/bonjour": ^3.5.9 + "@types/connect-history-api-fallback": ^1.3.5 + "@types/express": ^4.17.13 + "@types/serve-index": ^1.9.1 + "@types/serve-static": ^1.13.10 + "@types/sockjs": ^0.3.33 + "@types/ws": ^8.5.5 + ansi-html-community: ^0.0.8 + bonjour-service: ^1.0.11 + chokidar: ^3.5.3 + colorette: ^2.0.10 + compression: ^1.7.4 + connect-history-api-fallback: ^2.0.0 + default-gateway: ^6.0.3 + express: ^4.17.3 + graceful-fs: ^4.2.6 + html-entities: ^2.3.2 + http-proxy-middleware: ^2.0.3 + ipaddr.js: ^2.0.1 + launch-editor: ^2.6.0 + open: ^8.0.9 + p-retry: ^4.5.0 + rimraf: ^3.0.2 + schema-utils: ^4.0.0 + selfsigned: ^2.1.1 + serve-index: ^1.9.1 + sockjs: ^0.3.24 + spdy: ^4.0.2 + webpack-dev-middleware: ^5.3.1 + ws: ^8.13.0 + peerDependencies: + webpack: ^4.37.0 || ^5.0.0 + peerDependenciesMeta: + webpack: + optional: true + webpack-cli: + optional: true + bin: + webpack-dev-server: bin/webpack-dev-server.js + checksum: cd0063b068d2b938fd76c412d555374186ac2fa84bbae098265212ed50a5c15d6f03aa12a5a310c544a242943eb58c0bfde4c296d5c36765c182f53799e1bc71 + languageName: node + linkType: hard + +"webpack-merge@npm:^5.8.0": + version: 5.9.0 + resolution: "webpack-merge@npm:5.9.0" + dependencies: + clone-deep: ^4.0.1 + wildcard: ^2.0.0 + checksum: 64fe2c23aacc5f19684452a0e84ec02c46b990423aee6fcc5c18d7d471155bd14e9a6adb02bd3656eb3e0ac2532c8e97d69412ad14c97eeafe32fa6d10050872 + languageName: node + linkType: hard + +"webpack-sources@npm:^3.2.2, webpack-sources@npm:^3.2.3": + version: 3.2.3 + resolution: "webpack-sources@npm:3.2.3" + checksum: 989e401b9fe3536529e2a99dac8c1bdc50e3a0a2c8669cbafad31271eadd994bc9405f88a3039cd2e29db5e6d9d0926ceb7a1a4e7409ece021fe79c37d9c4607 + languageName: node + linkType: hard + +"webpack@npm:^5.73.0": + version: 5.89.0 + resolution: "webpack@npm:5.89.0" + dependencies: + "@types/eslint-scope": ^3.7.3 + "@types/estree": ^1.0.0 + "@webassemblyjs/ast": ^1.11.5 + "@webassemblyjs/wasm-edit": ^1.11.5 + "@webassemblyjs/wasm-parser": ^1.11.5 + acorn: ^8.7.1 + acorn-import-assertions: ^1.9.0 + browserslist: ^4.14.5 + chrome-trace-event: ^1.0.2 + enhanced-resolve: ^5.15.0 + es-module-lexer: ^1.2.1 + eslint-scope: 5.1.1 + events: ^3.2.0 + glob-to-regexp: ^0.4.1 + graceful-fs: ^4.2.9 + json-parse-even-better-errors: ^2.3.1 + loader-runner: ^4.2.0 + mime-types: ^2.1.27 + neo-async: ^2.6.2 + schema-utils: ^3.2.0 + tapable: ^2.1.1 + terser-webpack-plugin: ^5.3.7 + watchpack: ^2.4.0 + webpack-sources: ^3.2.3 + peerDependenciesMeta: + webpack-cli: + optional: true + bin: + webpack: bin/webpack.js + checksum: 43fe0dbc30e168a685ef5a86759d5016a705f6563b39a240aa00826a80637d4a3deeb8062e709d6a4b05c63e796278244c84b04174704dc4a37bedb0f565c5ed + languageName: node + linkType: hard + +"webpackbar@npm:^5.0.2": + version: 5.0.2 + resolution: "webpackbar@npm:5.0.2" + dependencies: + chalk: ^4.1.0 + consola: ^2.15.3 + pretty-time: ^1.1.0 + std-env: ^3.0.1 + peerDependencies: + webpack: 3 || 4 || 5 + checksum: 214a734b1d4d391eb8271ed1b11085f0efe6831e93f641229b292abfd6fea871422dce121612511c17ae8047522be6d65c1a2666cabb396c79549816a3612338 + languageName: node + linkType: hard + +"websocket-driver@npm:>=0.5.1, websocket-driver@npm:^0.7.4": + version: 0.7.4 + resolution: "websocket-driver@npm:0.7.4" + dependencies: + http-parser-js: ">=0.5.1" + safe-buffer: ">=5.1.0" + websocket-extensions: ">=0.1.1" + checksum: fffe5a33fe8eceafd21d2a065661d09e38b93877eae1de6ab5d7d2734c6ed243973beae10ae48c6613cfd675f200e5a058d1e3531bc9e6c5d4f1396ff1f0bfb9 + languageName: node + linkType: hard + +"websocket-extensions@npm:>=0.1.1": + version: 0.1.4 + resolution: "websocket-extensions@npm:0.1.4" + checksum: 5976835e68a86afcd64c7a9762ed85f2f27d48c488c707e67ba85e717b90fa066b98ab33c744d64255c9622d349eedecf728e65a5f921da71b58d0e9591b9038 + languageName: node + linkType: hard + "well-known-symbols@npm:^2.0.0": version: 2.0.0 resolution: "well-known-symbols@npm:2.0.0" @@ -8570,6 +17191,17 @@ __metadata: languageName: node linkType: hard +"which@npm:^1.3.1": + version: 1.3.1 + resolution: "which@npm:1.3.1" + dependencies: + isexe: ^2.0.0 + bin: + which: ./bin/which + checksum: f2e185c6242244b8426c9df1510e86629192d93c1a986a7d2a591f2c24869e7ffd03d6dac07ca863b2e4c06f59a4cc9916c585b72ee9fa1aa609d0124df15e04 + languageName: node + linkType: hard + "which@npm:^2.0.1, which@npm:^2.0.2": version: 2.0.2 resolution: "which@npm:2.0.2" @@ -8590,6 +17222,31 @@ __metadata: languageName: node linkType: hard +"widest-line@npm:^3.1.0": + version: 3.1.0 + resolution: "widest-line@npm:3.1.0" + dependencies: + string-width: ^4.0.0 + checksum: 03db6c9d0af9329c37d74378ff1d91972b12553c7d72a6f4e8525fe61563fa7adb0b9d6e8d546b7e059688712ea874edd5ded475999abdeedf708de9849310e0 + languageName: node + linkType: hard + +"widest-line@npm:^4.0.1": + version: 4.0.1 + resolution: "widest-line@npm:4.0.1" + dependencies: + string-width: ^5.0.1 + checksum: 64c48cf27171221be5f86fc54b94dd29879165bdff1a7aa92dde723d9a8c99fb108312768a5d62c8c2b80b701fa27bbd36a1ddc58367585cd45c0db7920a0cba + languageName: node + linkType: hard + +"wildcard@npm:^2.0.0": + version: 2.0.1 + resolution: "wildcard@npm:2.0.1" + checksum: e0c60a12a219e4b12065d1199802d81c27b841ed6ad6d9d28240980c73ceec6f856771d575af367cbec2982d9ae7838759168b551776577f155044f5a5ba843c + languageName: node + linkType: hard + "wordwrapjs@npm:^5.1.0": version: 5.1.0 resolution: "wordwrapjs@npm:5.1.0" @@ -8626,7 +17283,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^8.1.0": +"wrap-ansi@npm:^8.0.1, wrap-ansi@npm:^8.1.0": version: 8.1.0 resolution: "wrap-ansi@npm:8.1.0" dependencies: @@ -8644,6 +17301,18 @@ __metadata: languageName: node linkType: hard +"write-file-atomic@npm:^3.0.0": + version: 3.0.3 + resolution: "write-file-atomic@npm:3.0.3" + dependencies: + imurmurhash: ^0.1.4 + is-typedarray: ^1.0.0 + signal-exit: ^3.0.2 + typedarray-to-buffer: ^3.1.5 + checksum: c55b24617cc61c3a4379f425fc62a386cc51916a9b9d993f39734d005a09d5a4bb748bc251f1304e7abd71d0a26d339996c275955f527a131b1dcded67878280 + languageName: node + linkType: hard + "write-file-atomic@npm:^5.0.1": version: 5.0.1 resolution: "write-file-atomic@npm:5.0.1" @@ -8699,7 +17368,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^7.4.2, ws@npm:^7.4.6": +"ws@npm:^7.3.1, ws@npm:^7.4.2, ws@npm:^7.4.6": version: 7.5.9 resolution: "ws@npm:7.5.9" peerDependencies: @@ -8714,6 +17383,46 @@ __metadata: languageName: node linkType: hard +"ws@npm:^8.13.0": + version: 8.14.2 + resolution: "ws@npm:8.14.2" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 3ca0dad26e8cc6515ff392b622a1467430814c463b3368b0258e33696b1d4bed7510bc7030f7b72838b9fdeb8dbd8839cbf808367d6aae2e1d668ce741d4308b + languageName: node + linkType: hard + +"xdg-basedir@npm:^4.0.0": + version: 4.0.0 + resolution: "xdg-basedir@npm:4.0.0" + checksum: 0073d5b59a37224ed3a5ac0dd2ec1d36f09c49f0afd769008a6e9cd3cd666bd6317bd1c7ce2eab47e1de285a286bad11a9b038196413cd753b79770361855f3c + languageName: node + linkType: hard + +"xml-js@npm:^1.6.11": + version: 1.6.11 + resolution: "xml-js@npm:1.6.11" + dependencies: + sax: ^1.2.4 + bin: + xml-js: ./bin/cli.js + checksum: 24a55479919413687105fc2d8ab05e613ebedb1c1bc12258a108e07cff5ef793779297db854800a4edf0281303ebd1f177bc4a588442f5344e62b3dddda26c2b + languageName: node + linkType: hard + +"xtend@npm:^4.0.0, xtend@npm:^4.0.1": + version: 4.0.2 + resolution: "xtend@npm:4.0.2" + checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a + languageName: node + linkType: hard + "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" @@ -8735,6 +17444,13 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^1.10.0, yaml@npm:^1.10.2, yaml@npm:^1.7.2": + version: 1.10.2 + resolution: "yaml@npm:1.10.2" + checksum: ce4ada136e8a78a0b08dc10b4b900936912d15de59905b2bf415b4d33c63df1d555d23acb2a41b23cf9fb5da41c256441afca3d6509de7247daa062fd2c5ea5f + languageName: node + linkType: hard + "yaml@npm:^2.1.1": version: 2.3.2 resolution: "yaml@npm:2.3.2" @@ -8858,6 +17574,13 @@ __metadata: languageName: node linkType: hard +"zwitch@npm:^1.0.0": + version: 1.0.5 + resolution: "zwitch@npm:1.0.5" + checksum: 28a1bebacab3bc60150b6b0a2ba1db2ad033f068e81f05e4892ec0ea13ae63f5d140a1d692062ac0657840c8da076f35b94433b5f1c329d7803b247de80f064a + languageName: node + linkType: hard + "zx@npm:7.1.1": version: 7.1.1 resolution: "zx@npm:7.1.1"