diff --git a/.github/ISSUE_TEMPLATE/BUG-FORM.yml b/.github/ISSUE_TEMPLATE/BUG-FORM.yml new file mode 100644 index 0000000000..05c29428ca --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG-FORM.yml @@ -0,0 +1,56 @@ +name: Bug report +description: File a bug report +labels: ["T-bug", "T-needs-triage"] +body: + - type: markdown + attributes: + value: | + Please ensure that the bug has not already been filed in the issue tracker. + + Thanks for taking the time to report this bug in SP1! + - type: dropdown + attributes: + label: Component + description: What component is the bug in? + multiple: true + options: + - sp1-sdk + - sp1-zkvm + - cargo prove CLI/sp1up + - Other (please describe) + validations: + required: true + - type: checkboxes + attributes: + label: Have you ensured that all of these are up to date? + options: + - label: SP1 SDK + - label: cargo prove CLI/sp1up + - type: input + attributes: + label: What version of SP1 SDK are you on? + description: Leave empty if not relevant + placeholder: "Add the version from the Cargo.toml file here" + - type: input + attributes: + label: What version of the cargo prove CLI are you on? + description: Leave empty if not relevant + placeholder: "Run cargo prove --version and paste the output here" + - type: dropdown + attributes: + label: Operating System + description: What operating system are you on? + options: + - Windows + - macOS (Intel) + - macOS (Apple Silicon) + - Linux (Arch) + - Linux (Debian) + - Linux (Ubuntu) + - Linux (Other) + - type: textarea + attributes: + label: Describe the bug + description: Please include relevant Rust snippets/CLI commands as well if relevant. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/FEATURE-FORM.yml b/.github/ISSUE_TEMPLATE/FEATURE-FORM.yml new file mode 100644 index 0000000000..17a83d01da --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE-FORM.yml @@ -0,0 +1,32 @@ +name: Feature request +description: Suggest a feature +labels: ["T-feature", "T-needs-triage"] +body: + - type: markdown + attributes: + value: | + Please ensure that the feature has not already been requested in the issue tracker. + + Thanks for helping us improve SP1! + - type: dropdown + attributes: + label: Component + description: What component is the feature for? + multiple: true + options: + - sp1-sdk + - sp1-zkvm + - cargo prove CLI/sp1up + - Other (please describe) + validations: + required: true + - type: textarea + attributes: + label: Describe the feature you would like + description: Please also describe what the feature is aiming to solve, if relevant. + validations: + required: true + - type: textarea + attributes: + label: Additional context + description: Add any other context to the feature (like screenshots, resources) \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..3654e060fc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Support + url: https://t.me/+5q4kfeXaBE1hZjEx + about: This issue tracker is only for bugs and feature requests. Support is available on Telegram! \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..81d60ecec0 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,36 @@ + + + + +## Motivation + + + +## Solution + + + +## PR Checklist + +- [ ] Added Tests +- [ ] Added Documentation +- [ ] Breaking changes \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 911d5ffa43..81958dba2c 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -414,4 +414,39 @@ jobs: - name: Check build run: cargo check --target riscv32imac-unknown-none-elf --no-default-features -p sp1-verifier - \ No newline at end of file + + lock-files: + name: "Check lock files" + runs-on: + [ + runs-on, + runner=64cpu-linux-x64, + spot=false, + hdd=150, + "run-id=${{ github.run_id }}", + ] + env: + CARGO_NET_GIT_FETCH_WITH_CLI: "true" + steps: + - name: "Checkout sources" + uses: "actions/checkout@v4" + + - name: Setup CI + uses: ./.github/actions/setup + + - name: "Remove lock files" + run: | + find -name Cargo.lock -type f -exec rm {} \; + + - name: "Build SP1 without lock files" + run: | + cargo build --all --all-targets + + - name: Install SP1 toolchain + run: | + cargo run -p sp1-cli -- prove install-toolchain + + - name: "Build examples without lock files" + run: | + cd examples + cargo build --all --all-targets diff --git a/Cargo.lock b/Cargo.lock index 749e664748..2a9ba70be9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,9 +168,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31a0f0d51db8a1a30a4d98a9f90e090a94c8f44cb4d9eafc7e03aa6d00aae984" +checksum = "ded610181f3dad5810f6ff12d1a99994cf9b42d2fcb7709029352398a5da5ae6" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -228,9 +228,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8edae627382349b56cd6a7a2106f4fd69b243a9233e560c55c2e03cabb7e1d3c" +checksum = "fd58d377699e6cfeab52c4a9d28bdc4ef37e2bd235ff2db525071fe37a2e9af5" dependencies = [ "alloy-rlp", "bytes 1.8.0", @@ -238,7 +238,7 @@ dependencies = [ "const-hex", "derive_more", "foldhash", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "hex-literal", "indexmap 2.6.0", "itoa", @@ -273,7 +273,7 @@ checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -338,23 +338,23 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841eabaa4710f719fddbc24c95d386eae313f07e6da4babc25830ee37945be0c" +checksum = "8a1b42ac8f45e2f49f4bcdd72cbfde0bb148f5481d403774ffa546e48b83efc1" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6672337f19d837b9f7073c45853aeb528ed9f7dd6a4154ce683e9e5cb7794014" +checksum = "06318f1778e57f36333e850aa71bd1bb5e560c10279e236622faae0470c50412" dependencies = [ "alloy-sol-macro-input", "const-hex", @@ -363,31 +363,31 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dff37dd20bfb118b777c96eda83b2067f4226d2644c5cfa00187b3bc01770ba" +checksum = "eaebb9b0ad61a41345a22c9279975c0cdd231b97947b10d7aad1cf0a7181e4a5" dependencies = [ "const-hex", "dunce", "heck", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b853d42292dbb159671a3edae3b2750277ff130f32b726fe07dc2b17aa6f2b5" +checksum = "12c71028bfbfec210e24106a542aad3def7caf1a70e2c05710e92a98481980d3" dependencies = [ "serde", "winnow 0.6.20", @@ -395,9 +395,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa828bb1b9a6dc52208fbb18084fb9ce2c30facc2bfda6a5d922349b4990354f" +checksum = "374d7fb042d68ddfe79ccb23359de3007f6d4d53c13f703b64fb0db422132111" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -438,9 +438,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -767,7 +767,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -797,7 +797,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -827,7 +827,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -983,7 +983,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1124,7 +1124,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1203,9 +1203,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.31" +version = "1.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" dependencies = [ "jobserver", "libc", @@ -1323,7 +1323,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1632,7 +1632,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -1755,6 +1755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -1795,7 +1796,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "unicode-xid", ] @@ -1868,6 +1869,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -1918,6 +1930,7 @@ dependencies = [ "ff 0.13.0", "generic-array 0.14.7", "group 0.13.0", + "pem-rfc7468", "pkcs8", "rand_core 0.6.4", "sec1", @@ -1964,7 +1977,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2247,7 +2260,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -2497,9 +2510,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" dependencies = [ "allocator-api2", "equivalent", @@ -2703,9 +2716,9 @@ dependencies = [ [[package]] name = "hyper-timeout" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ "hyper", "hyper-util", @@ -2772,6 +2785,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -2780,12 +2911,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -2831,7 +2973,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "serde", ] @@ -3097,6 +3239,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -3122,7 +3270,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.0", + "hashbrown 0.15.1", ] [[package]] @@ -3469,7 +3617,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -3502,6 +3650,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.8", +] + [[package]] name = "p3-air" version = "0.1.0" @@ -3832,6 +3992,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -3876,7 +4045,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4006,7 +4175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4023,6 +4192,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -4072,7 +4250,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4137,7 +4315,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.86", + "syn 2.0.87", "tempfile", ] @@ -4151,7 +4329,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4206,9 +4384,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" dependencies = [ "cfg_aliases", "libc", @@ -4628,9 +4806,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" dependencies = [ "bitflags", "errno", @@ -4760,7 +4938,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4804,7 +4982,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -4919,7 +5097,7 @@ checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -5011,7 +5189,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -5284,6 +5462,7 @@ dependencies = [ "log", "num", "num_cpus", + "p256", "p3-air", "p3-baby-bear", "p3-challenger", @@ -5345,6 +5524,7 @@ dependencies = [ "itertools 0.13.0", "k256", "num", + "p256", "p3-field", "rand 0.8.5", "rug", @@ -5696,7 +5876,7 @@ dependencies = [ "num-traits", "sha2 0.10.8", "sp1-sdk", - "substrate-bn", + "substrate-bn-succinct", "thiserror-no-std", ] @@ -5747,6 +5927,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "standback" version = "0.2.17" @@ -5842,13 +6028,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] -name = "substrate-bn" +name = "substrate-bn-succinct" version = "0.6.0" -source = "git+https://github.com/sp1-patches/bn?tag=substrate_bn-v0.6.0-patch-v2#201cc196da216656044e61fea7f68707b6896662" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "114c855c26ad0594c830129cb868552fb41415603a6133276c2ecdd9e5ef4255" dependencies = [ "bytemuck", "byteorder", @@ -5903,9 +6090,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.86" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -5914,14 +6101,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16320d4a2021ba1a32470b3759676114a918885e9800e68ad60f2c67969fba62" +checksum = "edf42e81491fb8871b74df3d222c64ae8cbc1269ea509fa768a3ed3e1b0ac8cb" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -5939,6 +6126,17 @@ dependencies = [ "futures-core", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "sysinfo" version = "0.30.13" @@ -6024,22 +6222,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6161,6 +6359,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -6212,7 +6420,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6389,7 +6597,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", ] [[package]] @@ -6546,12 +6754,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" version = "1.0.13" @@ -6564,15 +6766,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-width" version = "0.1.14" @@ -6609,9 +6802,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", "idna", @@ -6625,6 +6818,18 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -6745,7 +6950,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -6779,7 +6984,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7097,6 +7302,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -7112,6 +7329,30 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -7130,7 +7371,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", ] [[package]] @@ -7150,7 +7412,29 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.86", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c557828e67..7f40570ec4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ version = "3.0.0" edition = "2021" license = "MIT OR Apache-2.0" +rust-version = "1.79" repository = "https://github.com/succinctlabs/sp1" keywords = ["sp1", "succinct", "zero-knowledge", "zkvm"] categories = ["cryptography"] @@ -139,5 +140,10 @@ p3-bn254-fr = { git = "https://github.com/Plonky3/Plonky3", branch = "sp1-v4" } [workspace.metadata.typos] # TODO: Fix in next version since CommitCommitedValuesDigest is retained since it's present in constraints.json -default.extend-ignore-re = ["Jo-Philipp Wich", "SubEIN", "DivEIN", "CommitCommitedValuesDigest"] +default.extend-ignore-re = [ + "Jo-Philipp Wich", + "SubEIN", + "DivEIN", + "CommitCommitedValuesDigest", +] default.extend-ignore-words-re = ["(?i)groth", "TRE"] diff --git a/README.md b/README.md index 177e542a90..efa9cf59fc 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@ To get started, make sure you have [Rust](https://www.rust-lang.org/tools/instal SP1 has undergone audits from [Veridise](https://www.veridise.com/), [Cantina](https://cantina.xyz/), and [KALOS](https://kalos.xyz/) and is recommended for production use. The audit reports are available [here](./audits). +## Supported Rust Versions (MSRV) + +The current MSRV (minimum supported Rust version) is 1.79. ## For Contributors diff --git a/audits/rkm0959.md b/audits/rkm0959.md new file mode 100644 index 0000000000..3fb90318af --- /dev/null +++ b/audits/rkm0959.md @@ -0,0 +1,446 @@ +# SP1 V3 Audit Report + +## 1. Various Challenger Issues + +### 1-1 [Informational] Challenger using full sponge state for output + +```rust +fn duplexing(&mut self, builder: &mut Builder) { + assert!(self.input_buffer.len() <= HASH_RATE); + + self.sponge_state[0..self.input_buffer.len()].copy_from_slice(self.input_buffer.as_slice()); + self.input_buffer.clear(); + + self.sponge_state = builder.poseidon2_permute_v2(self.sponge_state); + + self.output_buffer.clear(); + self.output_buffer.extend_from_slice(&self.sponge_state); + } +``` + +We are using the full sponge state for the output buffer. This is not an usual behavior for sponge constructions - only the rate part of the sponge state is used for the output usually. One possibility this opens up is that for valid hash result after a single permutation, it is easy to get the hash preimage. Note that this doesn't mean that it's easy to get the hash preimage for any desired hash output result, leading to the low severity. + +Note that this is also true for the `MultiFieldChallenger`. + +This is triggered when we continuously use many hash outputs before observing a new value, and for inner recursion this only happens when we are sampling FRI query indices. + +```rust + self.output_buffer.clear(); + for &pf_val in self.sponge_state.iter() { + let f_vals = split_32(builder, pf_val, self.num_f_elms); + for f_val in f_vals { + self.output_buffer.push(f_val); + } + } +``` + +### 1-2 [Medium, Plonky3] `MultiField32Challenger` overwrites the entire state + +```rust +pub fn observe(&mut self, builder: &mut Builder, value: Felt) { + self.output_buffer.clear(); + + self.input_buffer.push(value); + if self.input_buffer.len() == self.num_f_elms * SPONGE_SIZE { + self.duplexing(builder); + } + } +``` + +We are overwriting `SPONGE_STATE` values at once using the input buffer - which means we are overwriting the entire state. This means that hash collisions can be generated easily if we happen to overwrite the entire state. In this case, all the previous inputs to the challenger will be ignored. For this entire overwrite to happen, one would have to observe at least 9 Felts to the challenger before sampling any value from the challenger. + +Note that this vulnerability is also present for any user of previous versions of Plonky3, including previous versions of SP1. + +**Fix for Issue 1-2:** + +- Plonky3: https://github.com/Plonky3/Plonky3/blob/sp1-v3/challenger/src/multi_field_challenger.rs +- SP1: https://github.com/succinctlabs/sp1/pull/1575 + +## 2. [Informational] Plonky3 compress function uses a permutation + +Roughly speaking, our compression function is `Truncate(Permute(left || right))` - but this is not a typical one-way function. Indeed, it’s easy to find collisions for this compression by taking `rand` and using `left || right = Permute^-1(result || rand)`. However, note that we have no real control over the resulting `left` and `right`. This means that it is infeasible to find `left` and `right` alongside their hash preimages. Since our compression is done on hashes, (either `vk` hash or hash of opened values) this means that we cannot attack the system end-to-end currently. However, we cannot use the compression as an “usual merkle black box” - so we need to be aware of this in the future. + +## 3. [Low] Bits ↔ Felts ↔ Vars conversion technicalities + +### 3-1. [Informational] combining felts with base `2^32` to a `var` + +In `hash.rs`, we combine 8 felts to var using base `2^32`. + +```rust +fn hash(builder: &mut Builder, input: &[Felt<::F>]) -> Self::DigestVariable { + assert!(C::N::bits() == p3_bn254_fr::Bn254Fr::bits()); + assert!(C::F::bits() == p3_baby_bear::BabyBear::bits()); + let num_f_elms = C::N::bits() / C::F::bits(); // this is 8 + let mut state: [Var; SPONGE_SIZE] = + [builder.eval(C::N::zero()), builder.eval(C::N::zero()), builder.eval(C::N::zero())]; + for block_chunk in &input.iter().chunks(RATE) { + for (chunk_id, chunk) in (&block_chunk.chunks(num_f_elms)).into_iter().enumerate() { + let chunk = chunk.copied().collect::>(); + state[chunk_id] = reduce_32(builder, chunk.as_slice()); + } + builder.push_op(DslIr::CircuitPoseidon2Permute(state)) + } + + [state[0]; BN254_DIGEST_SIZE] +} + +pub fn reduce_32(builder: &mut Builder, vals: &[Felt]) -> Var { + let mut power = C::N::one(); + let result: Var = builder.eval(C::N::zero()); + for val in vals.iter() { + let val = builder.felt2var_circuit(*val); + builder.assign(result, result + val * power); + power *= C::N::from_canonical_u64(1u64 << 32); + } + result +} +``` + +The important thing here is for this sum of 8 felts doesn’t lead to a collision in BN254. The reason why this is true is actually very non-trivial - indeed, with base `2^31` combining it’s clear that different set of 8 felts would lead to different BN254 result as there is no chance for a BN254 wraparound (as `(2^31)^8 < BN254`), but for base `2^32` things are different. Indeed, it can be shown that for Mersenne31 prime, this will lead to a collision. + +We recommend to change this combining to be done with base `2^31`. + +This is already done in `felts_to_bn254_var` in `utils.rs` as shown below. + +```rust +#[allow(dead_code)] +pub fn felts_to_bn254_var( + builder: &mut Builder, + digest: &[Felt; DIGEST_SIZE], +) -> Var { + let var_2_31: Var<_> = builder.constant(C::N::from_canonical_u32(1 << 31)); + let result = builder.constant(C::N::zero()); + for (i, word) in digest.iter().enumerate() { + let word_bits = builder.num2bits_f_circuit(*word); + let word_var = builder.bits2num_v_circuit(&word_bits); + if i == 0 { + builder.assign(result, word_var); + } else { + builder.assign(result, result * var_2_31 + word_var); + } + } + result +} +``` + +We decided to not fix this, but give a proof of the fact that no collision exist. + +Basically, we have to check that, with $p$ being BabyBear and $q$ being BN254, + +$$ +\sum_{i=0}^7 2^{32i} x_i \not\equiv \sum_{i=0}^7 2^{32i} y_i \pmod{q} +$$ + +where $0 \le x_i, y_i < p$, and $(x_0, \cdots, x_7) \neq (y_0, \cdots, y_7)$ holds. + +This will ensure that the compression of 8 BabyBears to a single Var is injective. + +To check this, it suffices to show that + +$$ +\sum_{i=0}^7 2^{32i} z_i \not\equiv 0 \pmod{q} +$$ + +where $-p < z_i < p$ and not all $z_i$ is equal to zero. + +For this, we first note that, within the size boundaries, we have + +$$ +-1000q < \sum_{i=0}^7 2^{32i} z_i < 1000q +$$ + +So we can just check that + +$$ +\sum_{i=0}^{7} 2^{32i} z_i \neq kq +$$ + +for each $-1000 < k < 1000$. Now, note that we can derive $z_0$, as we know that + +$$ +z_0 \equiv kq \pmod{2^{32}} +$$ + +and there’s only one such $z_0$ within the range $(-p, p)$. We can continue this on for each limb, and then check whether the condition holds. This logic can be implemented easily. + +### 3-2. [Low] bitwise decomposition on felts may not be canonical + +For inner recursion, to convert a felt to bits, we use the following. + +```rust +/// Converts a felt to bits inside a circuit. +fn num2bits_v2_f(&mut self, num: Felt, num_bits: usize) -> Vec> { + let output = std::iter::from_fn(|| Some(self.uninit())).take(num_bits).collect::>(); + self.push_op(DslIr::CircuitV2HintBitsF(output.clone(), num)); + + let x: SymbolicFelt<_> = output + .iter() + .enumerate() + .map(|(i, &bit)| { + self.assert_felt_eq(bit * (bit - C::F::one()), C::F::zero()); + bit * C::F::from_wrapped_u32(1 << i) + }) + .sum(); + + self.assert_felt_eq(x, num); + + output +} +``` + +which means that when `num_bits = 31` (which is the case for `sample_bits`), it’s allowed for the 31 bits to represent the felt in a non-canonical way (i.e. use `p + 1` for `1`). + +We note that for the outer recursion, this is explicitly checked as follows. + +```rust +/// Converts a felt to bits inside a circuit. + pub fn num2bits_f_circuit(&mut self, num: Felt) -> Vec> { + let mut output = Vec::new(); + for _ in 0..NUM_BITS { + output.push(self.uninit()); + } + + self.push_op(DslIr::CircuitNum2BitsF(num, output.clone())); + + let output_array = self.vec(output.clone()); + self.less_than_bb_modulus(output_array); + + output + } +``` + +This is actually unnecessary, as `CircuitNum2BitsF` uses `ReduceSlow` to enforce the result to be within BabyBear range (canonical) then uses `ToBinary` API of GNARK to decompose the result into 32 bits. Note that the bitwise decomposition here is unique as the equality check is over BN254 (after we reduce everything to BabyBear range via `ReduceSlow`). + +This affects `sample_bits` - which is used for PoW grinding check and FRI query index generation. While not critical (this allows one additional representation for 1/15 (i.e. less than 2^27) of the BabyBear elements, which is not much) this may decrease the security parameter of our setup. Also, it’s bad to allow non-canonical things to be possible. + +**Fix for Issue 3-2:** https://github.com/succinctlabs/sp1/pull/1555 + +## 4. [High] Merkle Root of valid `vk` not loaded as constant + +```rust + /// Verify the proof shape phase of the compress stage. +pub fn verify( + builder: &mut Builder, + machine: &StarkMachine, + input: SP1CompressWithVKeyWitnessVariable, + value_assertions: bool, +) { + let values = + input.compress_var.vks_and_proofs.iter().map(|(vk, _)| vk.hash(builder)).collect_vec(); + SP1MerkleProofVerifier::verify(builder, values, input.merkle_var, value_assertions); + SP1CompressVerifier::verify(builder, machine, input.compress_var); +} +``` + +We handle multiple shapes of proofs as follows. We generate a set of valid `vk`'s, then compute the merkle tree/root of them. Then, in the recursive verifier, we check that each `vk` is valid by providing a merkle proof of inclusion. One of the challenges is how to make sure that this merkle root is correct within the verifier. If the merkle tree root is simply loaded as a variable, then an attacker can just put arbitrary merkle root, which is an issue. + +We handled this problem throughout multiple commits, and we briefly explain our solution. At the "top" of the recursion we assert that our `vk_root` variable is equal to the fixed, precomputed constant merkle root of all valid `vk`. + +```rust + // Attest that the merkle tree root is correct. + let root = input.merkle_var.root; + for (val, expected) in root.iter().zip(self.vk_root.iter()) { + builder.assert_felt_eq(*val, *expected); + } +``` + +Then, as we move "down" the recursion tree, we assert that +- all the child node's `vk` has merkle inclusion proof in the `vk_root` +- all the child node's public value `vk_root` is equal to the parent node's `vk_root` + +This means that our `vk_root` check "propagates downwards" the tree. + +## 5. [Medium] `cumulative_sum` needs to be observed when we observe the `permutation_commit` + +Currently, the `cumulative_sum` is never observed when sampling `zeta`, which allows us to use incorrect values of `cumulative_sum` to force the constraints to be true. + +We can fix this by incorporating `cumulative_sum` into the challenger, and this can be done while we are observing the `permutation_commit`. Note that you need to know the `permutation_challenge` before you observe the `cumulative_sum`. + +Note that this vulnerability is theoretically present in previous versions of SP1, although exploiting this is a quite difficult task, as the `cumulative_sum` one can get from this is essentially random, and their sum still has to be zero. While possible, it requires practically infeasible amount of computation and deep knowledge of cryptographic attacks to carry out. + +**Fix for Issue 5:** https://github.com/succinctlabs/sp1/pull/1556 + +## 6. [High] no check of `cumulative_sum` being zero when respective `InteractionScope` has no interactions + +In `permutation.rs`, if there's no sends/receives for a certain `InteractionScope`, then there's no constraints that the `cumulative_sum`  corresponding to that scope is zero. This is because we don't allocate any columns when there's no `sends` or `receives`, and we also just don't apply any constraints in that case as well. Therefore, we can use any value. + +```rust +if sends.is_empty() && receives.is_empty() { + continue; +} +``` + +This breaks the entire cumulative sum logic. + +To fix, we need to make sure that scopes with no interactions lead to cumulative sum being constrained to zero. For reference, the previous implementation of permutation was fine, as at least 1 column was allocated even when there’s no send/receive - and this column (the “partial sum”) was constrained with the sum of empty vector of expressions. + +**Fix for Issue 6**: https://github.com/succinctlabs/sp1/pull/1556 + +## 7. [Medium] Incorrect `exit_code` verification + + in `machine/core.rs` of the circuit-v2, there's a check that all exit code is zero. However, we aren't checking that `public_values.exit_code` is zero, but that `exit_code` is zero. This `exit_code` is actually just the first (`i == 0`) shard's public value exit code, so we aren't checking the exit code for all shards. + + We can fix this by checking all the `public_values.exit_code`. + +```rust +// Exit code constraints. +{ + // Assert that the exit code is zero (success) for all proofs. + builder.assert_felt_eq(exit_code, C::F::zero()); +} + +``` + +**Fix for Issue 7**: +https://github.com/succinctlabs/sp1/pull/1577 +https://github.com/succinctlabs/sp1/commit/bc187d5bc + + +## 8. [Medium] Syscall Chip’s commit scope is Local, despite them contributing to the global cumulative sum + +For the Fiat-Shamir to work out, we need to observe every chip that contributes to the global cumulative sum before we actually sample the global permutation challenge. + +All the syscall chips (ed25519, weierstrass, fp, sha256, etc) do contribute to the global cumulative sum, but their `commit_scope` is `InteractionScope::Local`. + +This allows us to break the permutation check within the global interactions. + +**Fix for Issue 8**: https://github.com/succinctlabs/sp1/pull/1582 + +Added an extra syscall table in global scope at each precompile shard that handles receiving the global syscall. Then there is a local lookup with the actual precompile table. + +## 9. [Medium] verifier uses prover-provided chip_scope, which allows incorrect Fiat-Shamir for global commits + +```rust + let ShardProof { + commitment, + opened_values, + opening_proof, + chip_ordering, + chip_scopes, + public_values, + .. + } = proof; + + // ... + + // Split the main_domains_points_and_opens to the global and local chips. + let mut global_trace_points_and_openings = Vec::new(); + let mut local_trace_points_and_openings = Vec::new(); + for (i, points_and_openings) in + main_domains_points_and_opens.clone().into_iter().enumerate() + { + let scope = chip_scopes[i]; + if scope == InteractionScope::Global { + global_trace_points_and_openings.push(points_and_openings); + } else { + local_trace_points_and_openings.push(points_and_openings); + } + } +``` + +The verifier does have access to chip scope information, as it is in `MachineAir`, yet the verifier uses the `chip_scopes` data that is inside the `ShardProof`. This `chip_scopes` has no prior checks. This allows the prover to fool a global commit as a local commit, which allows Fiat-Shamir break for the global permutation challenge. This can be fixed by using verifier’s chip info. This doesn’t hurt the recursive verifier, as our vkey’s are built using the correct chip scopes in mind. However, this hurts users who uses the “raw” rust verifier. + +**Fix for Issue 9**: https://github.com/succinctlabs/sp1/pull/1642/files + +## 10. [High] local cumulative sum check is missing + +There wasn’t a check that the local cumulative sum was zero for each shard in the recursion circuit, even though there was such a check in the direct rust stark verifier. + +**Fix for Issue 10:** https://github.com/succinctlabs/sp1/pull/1531 + +## 11. [High] incorrect constraints in exp_reverse_bits + +```rust +builder + .when(local_prepr.is_real) + .when_not(local_prepr.is_last) + .assert_eq(local.accum, local.prev_accum_squared_times_multiplier); +``` + +This should use `when_not(local_prepr.is_first)` instead. The fix PR is ready. + +**Fix for Issue 11:** https://github.com/succinctlabs/sp1/pull/1482 + +## 12. [Informational] minor issues connecting `committed_value_digest` and `deferred_proofs_digest` in `core.rs` and `compress.rs` + +In core, what we do is, given a list of consecutive shard proofs + +- check that once `committed_value_digest` is non-zero, it doesn't change +- check that if it's not a shard with CPU, the `committed_value_digest` doesn't change + - i.e, can't change even when the `committed_value_digest` is zero +- take the final `committed_value_digest` and put it in `RecursionPublicValues` + +Then, in compress we check that, given a list of proofs + +- once `committed_value_digest` is non-zero, it doesn't change +- the final `committed_value_digest` is in compressed `RecursionPublicValues` + +There are two ideas. to explain, let's think of the following scenario. + +- there are four shards: shard 1, 2, 3, 4 +- in `core.rs`, the proof #1 handles shard 1, 2 and proof #2 handles shard 3, 4 +- then the proof #1 and proof #2 are compressed in `compress.rs` + +**Idea 1**. One idea is to have committed value digest the shards be + +- shard 1 and 3's committed_value_digest = `0` +- shard 2 and 4's committed_value_digest = `x` + +this passes each core verification, and since the RecursionPublicValue of proof #1 and proof #2 are both `x` , this will also pass the compress proof. However, the `committed_value_digest` of these four shards will go `0, x, 0, x`, which is not what's supposed to happen. However, it's still true that the non-zero `committed_value_digests` must be equal over all the shards, so the attack surface is very limited. + +**Idea 2**. Assume that shard 3 has no CPU chip. We can actually do + +- shard 1, 2's committed_value_digest = `0` +- shard 3, 4's committed_value_digest = `x` + +this passes each core verification, as proof #2 thinks shard 3 is its "first" shard - so it actually thinks that the `committed_value_digest` didn't change. This means that the whole "no cpu chip means `commited_value_digest` equal" thing actually just passes. Then, in the compress verification, we'll just see the committed_value_digest go from `0` to `x`, which is also completely fine. However, the committed_value_digest will go `0, 0, x, x`, where the change occurs on a shard without cpu chip - which isn't supposed to happen. + +While this is a slight incompatibility, the main invariant (if nonzero, public digest can only be one non-zero value) is preserved. Therefore, we did not fix this observation. + +## 13. [Informational] execution shard witness gen + +Additionally, one small observation regarding our `execution_shard` connection checks in `compress.rs`. so, our `execution_shard` is initialized with the first proof (`i == 0`)'s `start_execution_shard`. Then, for each shard, it + +- is checked to be the `start_execution_shard` of the current shard + - (if it contains any execution_shard) +- remains the same if the shard doesn't contain any execution_shard +- changes to the `next_execution_shard` of the current shard + - (if it contains any execution_shard) + +This means that the `start_execution_shard` of the first proof (`i == 0`) must actually be the `start_execution_shard` of the proof which contains an execution shard for the first time in this compress proof. For example, if I have + +- shard 5, 6, 7, 8 exist, proof #1 handles shard 5, 6, proof #2 handles shard 7, 8 (in core) +- then proof #1 and proof #2 will be compressed (in compress) +- shard 5, 6 has no cpu, and shard 7, 8 has cpu + +then we actually need proof #1 to have `start_execution_shard` assigned to the `start_execution_shard` value for proof #2. This is because when compressing proof #1 and proof #2, `execution_shard` will be initialized with proof #1's `start_execution_shard`, and then later will be checked that this is equal to proof #2's (which contains an execution shard) `start_execution_shard`. This is fine in terms of constraints, but we do need to make sure that our witness generation accounts for this, as our usual mindset of execution shards is that we don't care what they are if the shard doesn't have a cpu table. + +**Fix for Issue 13**: https://github.com/succinctlabs/sp1/pull/1576 + +## 14. [Optimization] `Felt2Var` can be used in `felts_to_bn254_var` + +In `circuit-v2/src/utils.rs` + +```rust +pub fn felts_to_bn254_var( + builder: &mut Builder, + digest: &[Felt; DIGEST_SIZE], +) -> Var { + let var_2_31: Var<_> = builder.constant(C::N::from_canonical_u32(1 << 31)); + let result = builder.constant(C::N::zero()); + for (i, word) in digest.iter().enumerate() { + let word_bits = builder.num2bits_f_circuit(*word); + let word_var = builder.bits2num_v_circuit(&word_bits); + if i == 0 { + builder.assign(result, word_var); + } else { + builder.assign(result, result * var_2_31 + word_var); + } + } + result +} +``` + +We do the num2bits + bits2num thing here. We can do this via the felts to var conversion, (`CircuitFelt2Var`) which is an optimization we already used for 2.0.0 release. + +**Optimization PR**: https://github.com/succinctlabs/sp1/pull/1553 \ No newline at end of file diff --git a/book/SUMMARY.md b/book/SUMMARY.md index 53f0c71efe..55ec23f628 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -57,13 +57,14 @@ - [FAQ](./generating-proofs/sp1-sdk-faq.md) -# Onchain Verification +# Verification -- [Setup](./onchain-verification/getting-started.md) +- [On-chain Verification](./verification/onchain/getting-started.md) -- [Solidity Verifier](./onchain-verification/solidity-sdk.md) + - [Solidity Verifier](./verification/onchain/solidity-sdk.md) + - [Contract Addresses](./verification/onchain/contract-addresses.md) -- [Contract Addresses](./onchain-verification/contract-addresses.md) +- [Off-chain Verification](./verification/off-chain-verification.md) # Developers diff --git a/book/developers/common-issues.md b/book/developers/common-issues.md index 5d0a50e808..5b06ec3b43 100644 --- a/book/developers/common-issues.md +++ b/book/developers/common-issues.md @@ -51,7 +51,7 @@ This is likely due to two different versions of `alloy_sol_types` being used. To ```toml [dependencies] -sp1-sdk = { version = "2.0.0", default-features = false } +sp1-sdk = { version = "3.0.0", default-features = false } ``` This will configure out the `network` feature which will remove the dependency on `alloy_sol_types` and configure out the `NetworkProver`. diff --git a/book/developers/usage-in-ci.md b/book/developers/usage-in-ci.md index 33da5e45f9..ac4b1ba3cf 100644 --- a/book/developers/usage-in-ci.md +++ b/book/developers/usage-in-ci.md @@ -1,5 +1,7 @@ # Usage in CI +## Getting started + You may want to use SP1 in your [Github Actions](https://docs.github.com/en/actions) CI workflow. You first need to have Rust installed, and you can use @@ -25,3 +27,45 @@ And then you can install the SP1 toolchain: ~/.sp1/bin/sp1up ~/.sp1/bin/cargo-prove prove --version ``` + +You might experience rate limiting from sp1up. Using a Github +[Personal Access Token (PAT)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token) will help. + +Try setting a github actions secret to your PAT, and then passing it into the `sp1up` command: + +```yaml +- name: Install SP1 toolchain + run: | + curl -L https://sp1.succinct.xyz | bash + ~/.sp1/bin/sp1up --token "${{ secrets.GH_PAT }}" + ~/.sp1/bin/cargo-prove prove --version +``` + +## Speeding up your CI workflow + +### Caching + +To speed up your CI workflow, you can cache the Rust toolchain and Succinct toolchain. See this example +from SP1's CI workflow, which caches the `~/.cargo` and parts of the `~/.sp1` directories. + +```yaml +- name: rust-cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + ~/.rustup/ + ~/.sp1/circuits/plonk/ # Cache these if you're generating plonk proofs with docker in CI. + ~/.sp1/circuits/groth16/ # Cache these if you're generating groth16 proofs with docker in CI. + key: rust-1.81.0-${{ hashFiles('**/Cargo.toml') }} + restore-keys: rust-1.81.0- +``` + +### `runs-on` for bigger instances + +Since SP1 is a fairly large repository, it might be useful to use [`runs-on`](https://github.com/runs-on/runs-on) +to specify a larger instance type. diff --git a/book/generating-proofs/advanced.md b/book/generating-proofs/advanced.md index 4b1f30c544..76f8ac67d5 100644 --- a/book/generating-proofs/advanced.md +++ b/book/generating-proofs/advanced.md @@ -48,7 +48,7 @@ RUSTFLAGS='-C target-cpu=native' cargo run --release Currently there is support for AVX512 and NEON SIMD instructions. For NEON, you must also enable the `sp1-sdk` feature `neon` in your script crate's `Cargo.toml` file. ```toml -sp1-sdk = { version = "2.0.0", features = ["neon"] } +sp1-sdk = { version = "3.0.0", features = ["neon"] } ``` ## Performance diff --git a/book/generating-proofs/proof-types.md b/book/generating-proofs/proof-types.md index 7ebd300acf..72dd9a41cd 100644 --- a/book/generating-proofs/proof-types.md +++ b/book/generating-proofs/proof-types.md @@ -4,7 +4,7 @@ There are a few different types of proofs that can be generated by the SP1 zkVM. The `ProverClient` follows a "builder" pattern that allows you to configure the proof type and other options after creating a `ProverClient` and calling `prove` on it. -For a full list of options, see the following [docs](https://docs.rs/sp1-sdk/1.2.0/sp1_sdk/action/struct.Prove.html). +For a full list of options, see the following [docs](https://docs.rs/sp1-sdk/latest/sp1_sdk/action/struct.Prove.html). ## Core (Default) @@ -30,7 +30,7 @@ client.prove(&pk, stdin).compressed().run().unwrap(); The Groth16 prover mode generates a SNARK proof that is ~260 bytes large and can be verified onchain for around ~270k gas. -The trusted setup for the Groth16 circuit keys uses the [Aztec Ignition ceremony](https://github.com/AztecProtocol/ignition-verification) + entropy contributions from members of the Succinct team. +The trusted setup for the Groth16 circuit keys uses the [Aztec Ignition ceremony](https://github.com/AztecProtocol/ignition-verification) + entropy contributions from members of the Succinct team. If you are uncomfortable with the security assumptions of the ceremony, you can use the PLONK proof type instead. ```rust,noplayground let client = ProverClient::new(); @@ -41,7 +41,7 @@ client.prove(&pk, stdin).groth16().run().unwrap(); The PLONK prover mode generates a SNARK proof that is ~868 bytes large and can also be verified onchain for around ~300k gas. Plonk proofs take about ~1m30s longer to generate over a compressed proof. -PLONK does not require a trusted setup. +PLONK does not require a trusted setup and reuses contributions from the Aztec Ignition ceremony. ```rust,noplayground let client = ProverClient::new(); diff --git a/book/generating-proofs/prover-network.md b/book/generating-proofs/prover-network.md index f5b61d2204..4274d8202f 100644 --- a/book/generating-proofs/prover-network.md +++ b/book/generating-proofs/prover-network.md @@ -7,3 +7,5 @@ Succinct [has been building](https://blog.succinct.xyz/succinct-network/) the Su To get started, **[FILL OUT THIS FORM](https://forms.gle/rTUvhstS8PFfv9B3A)** to gain access to the Succinct Network. Completing this form requires you to complete the [key setup](./prover-network/key-setup.md) steps below. + +**Note:** The Succinct Prover Network requires access to your program and entire input, so that provers can generate a proof, meaning your input does not remain private to provers on the network. If you are using SP1 for its zero-knowledge properties, you should either run proof generation on a local machine (recommended), or understand the honesty assumptions required of provers of the network. \ No newline at end of file diff --git a/book/generating-proofs/prover-network/versions.md b/book/generating-proofs/prover-network/versions.md index 31503adb80..4190b713fe 100644 --- a/book/generating-proofs/prover-network/versions.md +++ b/book/generating-proofs/prover-network/versions.md @@ -17,14 +17,14 @@ You must switch to a supported version before submitting a proof. To do so, repl ```toml [dependencies] -sp1-zkvm = "2.0.0" +sp1-zkvm = "3.0.0" ``` replace the `sp1-sdk` version in your script's `Cargo.toml`: ```toml [dependencies] -sp1-sdk = "2.0.0" +sp1-sdk = "3.0.0" ``` Re-build your program and script, and then try again. diff --git a/book/generating-proofs/setup.md b/book/generating-proofs/setup.md index 88db15fb8e..0e33666215 100644 --- a/book/generating-proofs/setup.md +++ b/book/generating-proofs/setup.md @@ -32,7 +32,7 @@ name = "script" edition = "2021" [dependencies] -sp1-sdk = "2.0.0" +sp1-sdk = "3.0.0" ``` The `sp1-sdk` crate includes the necessary utilities to generate, save, and verify proofs. diff --git a/book/verification/off-chain-verification.md b/book/verification/off-chain-verification.md new file mode 100644 index 0000000000..3dd4bc601f --- /dev/null +++ b/book/verification/off-chain-verification.md @@ -0,0 +1,49 @@ +# Offchain Verification + +## Rust `no_std` Verification + +You can verify SP1 Groth16 and Plonk proofs in `no_std` environments with [`sp1-verifier`](https://docs.rs/sp1-verifier/latest/sp1_verifier/). + +`sp1-verifier` is also patched to verify Groth16 and Plonk proofs within the SP1 ZKVM, using +[bn254](https://blog.succinct.xyz/succinctshipsprecompiles/) precompiles. For an example of this, see +the [Groth16 Example](https://github.com/succinctlabs/sp1/tree/main/examples/groth16/). + +### Installation + +Import the following dependency in your `Cargo.toml`. Note that the `sp1-verifier` crate was added in version `3.2.1`. + +```toml +sp1-verifier = {version = "3.2.1", default-features = false} +``` + +### Usage + +`sp1-verifier`'s interface is very similar to the solidity verifier's. It exposes two public functions: +[`Groth16Verifier::verify_proof`](https://docs.rs/sp1-verifier/latest/sp1_verifier/struct.Groth16Verifier.html) +and [`PlonkVerifier::verify_proof`](https://docs.rs/sp1-verifier/latest/sp1_verifier/struct.PlonkVerifier.html). + +`sp1-verifier` also exposes the Groth16 and Plonk verifying keys as constants, `GROTH16_VK_BYTES` and `PLONK_VK_BYTES`. These +keys correspond to the current SP1 version's official Groth16 and Plonk verifying keys, which are used for verifying proofs generated +using docker or the prover network. + +First, generate your groth16/plonk proof with the SP1 SDK. See [here](./onchain/getting-started.md#generating-sp1-proofs-for-onchain-verification) +for more information -- `sp1-verifier` and the solidity verifier expect inputs in the same format. + +Next, verify the proof with `sp1-verifier`. The following snippet is from the [Groth16 example program](https://github.com/succinctlabs/sp1/tree/dev/examples/groth16/), which verifies a Groth16 proof within SP1 using `sp1-verifier`. + +```rust,noplayground +{{#include ../../examples/groth16/program/src/main.rs}} +``` + +Here, the proof, public inputs, and vkey hash are read from stdin. See the following snippet to see how these values are generated. + +```rust,noplayground +{{#include ../../examples/groth16/script/src/main.rs:12:34}} +``` + +> Note that the SP1 SDK itself is *not* `no_std` compatible. + +## Wasm Verification + +The [`example-sp1-wasm-verifier`](https://github.com/succinctlabs/example-sp1-wasm-verifier) demonstrates how to +verify SP1 proofs in wasm. For a more detailed explanation of the process, please see the [README](https://github.com/succinctlabs/example-sp1-wasm-verifier/blob/main/README.md). diff --git a/book/onchain-verification/contract-addresses.md b/book/verification/onchain/contract-addresses.md similarity index 98% rename from book/onchain-verification/contract-addresses.md rename to book/verification/onchain/contract-addresses.md index 0a23f6ab2e..6986d7cee8 100644 --- a/book/onchain-verification/contract-addresses.md +++ b/book/verification/onchain/contract-addresses.md @@ -1,5 +1,9 @@ # Contract Addresses +> The current officially supported version of SP1 is **V3.0.0**. +> +> All previous versions are deprecated and may not work as expected on the gateways. + To verify SP1 proofs on-chain, we recommend using our deployed canonical verifier gateways. The [SP1VerifierGateway](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol) will automatically route your SP1 proof to the correct verifier based on the SP1 version used. diff --git a/book/onchain-verification/getting-started.md b/book/verification/onchain/getting-started.md similarity index 97% rename from book/onchain-verification/getting-started.md rename to book/verification/onchain/getting-started.md index 834a23dc18..8519d620a8 100644 --- a/book/onchain-verification/getting-started.md +++ b/book/verification/onchain/getting-started.md @@ -29,5 +29,5 @@ You can run the above script with `RUST_LOG=info cargo run --bin groth16_bn254 - If you would like to run the Groth16 or PLONK prover directly without Docker, you must have Go 1.22 installed and enable the `native-gnark` feature in `sp1-sdk`. This path is not recommended and may require additional native dependencies. ```toml -sp1-sdk = { version = "2.0.0", features = ["native-gnark"] } +sp1-sdk = { version = "3.0.0", features = ["native-gnark"] } ``` diff --git a/book/onchain-verification/solidity-sdk.md b/book/verification/onchain/solidity-sdk.md similarity index 100% rename from book/onchain-verification/solidity-sdk.md rename to book/verification/onchain/solidity-sdk.md diff --git a/book/writing-programs/compiling.md b/book/writing-programs/compiling.md index f1acd49b0d..6a1fdc56b4 100644 --- a/book/writing-programs/compiling.md +++ b/book/writing-programs/compiling.md @@ -61,7 +61,7 @@ The path passed in to `build_program` should point to the directory containing t ```toml [build-dependencies] -sp1-build = "2.0.0" +sp1-build = "3.0.0" ``` You will see output like the following from the build script if the program has changed, indicating that the program was rebuilt: @@ -80,7 +80,7 @@ The above output was generated by running `RUST_LOG=info cargo run --release -vv ### Advanced Build Options -To configure the build process when using the `sp1-build` crate, you can pass a [`BuildArgs`](https://docs.rs/sp1-build/1.2.0/sp1_build/struct.BuildArgs.html) struct to to the [`build_program_with_args`](https://docs.rs/sp1-build/1.2.0/sp1_build/fn.build_program_with_args.html) function. The build arguments are the same as the ones available from the `cargo prove build` command. +To configure the build process when using the `sp1-build` crate, you can pass a [`BuildArgs`](https://docs.rs/sp1-build/latest/sp1_build/struct.BuildArgs.html) struct to to the [`build_program_with_args`](https://docs.rs/sp1-build/latest/sp1_build/fn.build_program_with_args.html) function. The build arguments are the same as the ones available from the `cargo prove build` command. As an example, you could use the following code to build the Fibonacci example with the `docker` flag set to `true` and a custom output directory for the generated ELF: diff --git a/book/writing-programs/cycle-tracking.md b/book/writing-programs/cycle-tracking.md index c560f28ae5..e7168c5723 100644 --- a/book/writing-programs/cycle-tracking.md +++ b/book/writing-programs/cycle-tracking.md @@ -14,7 +14,7 @@ Note that to use the macro, you must add the `sp1-derive` crate to your dependen ```toml [dependencies] -sp1-derive = "2.0.0" +sp1-derive = "3.0.0" ``` In the script for proof generation, setup the logger with `utils::setup_logger()` and run the script with `RUST_LOG=info cargo run --release`. You should see the following output: diff --git a/book/writing-programs/proof-aggregation.md b/book/writing-programs/proof-aggregation.md index f9bc1c1068..36ee28e1ce 100644 --- a/book/writing-programs/proof-aggregation.md +++ b/book/writing-programs/proof-aggregation.md @@ -15,10 +15,10 @@ Note that by itself, SP1 can already prove arbitrarily large programs by chunkin ## Verifying Proofs inside the zkVM -To verify a proof inside the zkVM, you can use the `sp1_zkvm::lib::verify::verify_proof` function. +To verify a proof inside the zkVM, you can use the `sp1_zkvm::lib::verify::verify_sp1_proof` function. ```rust,noplayground -sp1_zkvm::lib::verify::verify_proof(vkey, public_values_digest); +sp1_zkvm::lib::verify::verify_sp1_proof(vkey, public_values_digest); ``` **You do not need to pass in the proof as input into the syscall, as the proof will automatically be read for the proof input stream by the prover.** diff --git a/book/writing-programs/setup.md b/book/writing-programs/setup.md index aa3f4a2cca..a7545b0a49 100644 --- a/book/writing-programs/setup.md +++ b/book/writing-programs/setup.md @@ -32,7 +32,7 @@ name = "program" edition = "2021" [dependencies] -sp1-zkvm = "2.0.0" +sp1-zkvm = "3.0.0" ``` The `sp1-zkvm` crate includes necessary utilities for your program, including handling inputs and outputs, diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000000..d3577adf2d --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +msrv = "1.79" \ No newline at end of file diff --git a/crates/core/executor/src/events/precompiles/ec.rs b/crates/core/executor/src/events/precompiles/ec.rs index 995aacb73f..da76a33356 100644 --- a/crates/core/executor/src/events/precompiles/ec.rs +++ b/crates/core/executor/src/events/precompiles/ec.rs @@ -2,7 +2,10 @@ use serde::{Deserialize, Serialize}; use sp1_curves::{ params::{NumLimbs, NumWords}, - weierstrass::{bls12_381::bls12381_decompress, secp256k1::secp256k1_decompress}, + weierstrass::{ + bls12_381::bls12381_decompress, secp256k1::secp256k1_decompress, + secp256r1::secp256r1_decompress, + }, AffinePoint, CurveType, EllipticCurve, }; use sp1_primitives::consts::{bytes_to_words_le_vec, words_to_bytes_le_vec}; @@ -204,6 +207,7 @@ pub fn create_ec_decompress_event( let decompress_fn = match E::CURVE_TYPE { CurveType::Secp256k1 => secp256k1_decompress::, + CurveType::Secp256r1 => secp256r1_decompress::, CurveType::Bls12381 => bls12381_decompress::, _ => panic!("Unsupported curve"), }; diff --git a/crates/core/executor/src/events/precompiles/mod.rs b/crates/core/executor/src/events/precompiles/mod.rs index cc4f54ed7d..d55a2093b2 100644 --- a/crates/core/executor/src/events/precompiles/mod.rs +++ b/crates/core/executor/src/events/precompiles/mod.rs @@ -40,6 +40,12 @@ pub enum PrecompileEvent { Secp256k1Double(EllipticCurveDoubleEvent), /// Secp256k1 curve decompress precompile event. Secp256k1Decompress(EllipticCurveDecompressEvent), + /// Secp256r1 curve add precompile event. + Secp256r1Add(EllipticCurveAddEvent), + /// Secp256r1 curve double precompile event. + Secp256r1Double(EllipticCurveDoubleEvent), + /// Secp256r1 curve decompress precompile event. + Secp256r1Decompress(EllipticCurveDecompressEvent), /// K256 curve decompress precompile event. K256Decompress(EllipticCurveDecompressEvent), /// Bn254 curve add precompile event. @@ -93,17 +99,20 @@ impl PrecompileLocalMemory for Vec<(SyscallEvent, PrecompileEvent)> { iterators.push(e.local_mem_access.iter()); } PrecompileEvent::Secp256k1Add(e) + | PrecompileEvent::Secp256r1Add(e) | PrecompileEvent::EdAdd(e) | PrecompileEvent::Bn254Add(e) | PrecompileEvent::Bls12381Add(e) => { iterators.push(e.local_mem_access.iter()); } PrecompileEvent::Secp256k1Double(e) + | PrecompileEvent::Secp256r1Double(e) | PrecompileEvent::Bn254Double(e) | PrecompileEvent::Bls12381Double(e) => { iterators.push(e.local_mem_access.iter()); } PrecompileEvent::Secp256k1Decompress(e) + | PrecompileEvent::Secp256r1Decompress(e) | PrecompileEvent::K256Decompress(e) | PrecompileEvent::Bls12381Decompress(e) => { iterators.push(e.local_mem_access.iter()); diff --git a/crates/core/executor/src/executor.rs b/crates/core/executor/src/executor.rs index 3fc3403fba..e80d894bbe 100644 --- a/crates/core/executor/src/executor.rs +++ b/crates/core/executor/src/executor.rs @@ -1669,8 +1669,8 @@ mod tests { use sp1_stark::SP1CoreOpts; use crate::programs::tests::{ - fibonacci_program, panic_program, simple_memory_program, simple_program, - ssz_withdrawals_program, + fibonacci_program, panic_program, secp256r1_add_program, secp256r1_double_program, + simple_memory_program, simple_program, ssz_withdrawals_program, }; use crate::Register; @@ -1699,6 +1699,20 @@ mod tests { runtime.run().unwrap(); } + #[test] + fn test_secp256r1_add_program_run() { + let program = secp256r1_add_program(); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); + runtime.run().unwrap(); + } + + #[test] + fn test_secp256r1_double_program_run() { + let program = secp256r1_double_program(); + let mut runtime = Executor::new(program, SP1CoreOpts::default()); + runtime.run().unwrap(); + } + #[test] fn test_ssz_withdrawals_program_run() { let program = ssz_withdrawals_program(); diff --git a/crates/core/executor/src/hook.rs b/crates/core/executor/src/hook.rs index 3e54eca71c..e5479f623f 100644 --- a/crates/core/executor/src/hook.rs +++ b/crates/core/executor/src/hook.rs @@ -4,14 +4,17 @@ use std::sync::{Arc, RwLock, RwLockWriteGuard}; use hashbrown::HashMap; use sp1_curves::k256::{Invert, RecoveryId, Signature, VerifyingKey}; +use sp1_curves::p256::Signature as p256Signature; use crate::Executor; /// A runtime hook, wrapped in a smart pointer. pub type BoxedHook<'a> = Arc>; -/// The file descriptor through which to access `hook_ecrecover`. -pub const FD_ECRECOVER_HOOK: u32 = 5; +/// The file descriptor through which to access `hook_k1_ecrecover`. +pub const K1_ECRECOVER_HOOK: u32 = 5; +/// The file descriptor through which to access `hook_r1_ecrecover`. +pub const R1_ECRECOVER_HOOK: u32 = 6; /// A runtime hook. May be called during execution by writing to a specified file descriptor, /// accepting and returning arbitrary data. @@ -75,7 +78,8 @@ impl<'a> Default for HookRegistry<'a> { let table = HashMap::from([ // Note: To ensure any `fd` value is synced with `zkvm/precompiles/src/io.rs`, // add an assertion to the test `hook_fds_match` below. - (FD_ECRECOVER_HOOK, hookify(hook_ecrecover)), + (K1_ECRECOVER_HOOK, hookify(hook_k1_ecrecover)), + (R1_ECRECOVER_HOOK, hookify(hook_r1_ecrecover)), ]); Self { table } @@ -117,7 +121,7 @@ pub struct HookEnv<'a, 'b: 'a> { /// WARNING: This function is used to recover the public key outside of the zkVM context. These /// values must be constrained by the zkVM for correctness. #[must_use] -pub fn hook_ecrecover(_: HookEnv, buf: &[u8]) -> Vec> { +pub fn hook_k1_ecrecover(_: HookEnv, buf: &[u8]) -> Vec> { assert_eq!(buf.len(), 65 + 32, "ecrecover input should have length 65 + 32"); let (sig, msg_hash) = buf.split_at(65); let sig: &[u8; 65] = sig.try_into().unwrap(); @@ -141,6 +145,27 @@ pub fn hook_ecrecover(_: HookEnv, buf: &[u8]) -> Vec> { vec![bytes.to_vec(), s_inverse.to_bytes().to_vec()] } +/// Recovers s inverse from the signature using the secp256r1 crate. +/// +/// # Arguments +/// +/// * `env` - The environment in which the hook is invoked. +/// * `buf` - The buffer containing the signature. +/// - The signature is 64 bytes. +/// +/// The result is a single 32 byte vector containing s inverse. +#[must_use] +pub fn hook_r1_ecrecover(_: HookEnv, buf: &[u8]) -> Vec> { + assert_eq!(buf.len(), 64, "ecrecover input should have length 64"); + let sig: &[u8; 64] = buf.try_into().unwrap(); + let sig = p256Signature::from_slice(sig).unwrap(); + + let (_, s) = sig.split_scalars(); + let s_inverse = s.invert(); + + vec![s_inverse.to_bytes().to_vec()] +} + #[cfg(test)] pub mod tests { use super::*; @@ -148,7 +173,8 @@ pub mod tests { #[test] pub fn hook_fds_match() { use sp1_zkvm::lib::io; - assert_eq!(FD_ECRECOVER_HOOK, io::FD_ECRECOVER_HOOK); + assert_eq!(K1_ECRECOVER_HOOK, io::K1_ECRECOVER_HOOK); + assert_eq!(R1_ECRECOVER_HOOK, io::R1_ECRECOVER_HOOK); } #[test] diff --git a/crates/core/executor/src/programs.rs b/crates/core/executor/src/programs.rs index b20cade70e..3212e32d4e 100644 --- a/crates/core/executor/src/programs.rs +++ b/crates/core/executor/src/programs.rs @@ -60,6 +60,12 @@ pub mod tests { pub const SECP256K1_DOUBLE_ELF: &[u8] = include_bytes!("../../../../tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf"); + pub const SECP256R1_ADD_ELF: &[u8] = + include_bytes!("../../../../tests/secp256r1-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256R1_DOUBLE_ELF: &[u8] = + include_bytes!("../../../../tests/secp256r1-double/elf/riscv32im-succinct-zkvm-elf"); + pub const SHA_COMPRESS_ELF: &[u8] = include_bytes!("../../../../tests/sha-compress/elf/riscv32im-succinct-zkvm-elf"); @@ -140,6 +146,26 @@ pub mod tests { Program::from(FIBONACCI_ELF).unwrap() } + /// Get the secp256r1 add program. + /// + /// # Panics + /// + /// This function will panic if the program fails to load. + #[must_use] + pub fn secp256r1_add_program() -> Program { + Program::from(SECP256R1_ADD_ELF).unwrap() + } + + /// Get the secp256r1 double program. + /// + /// # Panics + /// + /// This function will panic if the program fails to load. + #[must_use] + pub fn secp256r1_double_program() -> Program { + Program::from(SECP256R1_DOUBLE_ELF).unwrap() + } + /// Get the SSZ withdrawals program. /// /// # Panics diff --git a/crates/core/executor/src/syscalls/code.rs b/crates/core/executor/src/syscalls/code.rs index ece5a06e99..1891a3f742 100644 --- a/crates/core/executor/src/syscalls/code.rs +++ b/crates/core/executor/src/syscalls/code.rs @@ -128,6 +128,15 @@ pub enum SyscallCode { /// Executes the `BN254_FP2_MUL` precompile. BN254_FP2_MUL = 0x00_01_01_2B, + + /// Executes the `SECP256R1_ADD` precompile. + SECP256R1_ADD = 0x00_01_01_2C, + + /// Executes the `SECP256R1_DOUBLE` precompile. + SECP256R1_DOUBLE = 0x00_00_01_2D, + + /// Executes the `SECP256R1_DECOMPRESS` precompile. + SECP256R1_DECOMPRESS = 0x00_00_01_2E, } impl SyscallCode { @@ -170,6 +179,9 @@ impl SyscallCode { 0x00_01_01_2A => SyscallCode::BN254_FP2_SUB, 0x00_01_01_2B => SyscallCode::BN254_FP2_MUL, 0x00_00_01_1C => SyscallCode::BLS12381_DECOMPRESS, + 0x00_01_01_2C => SyscallCode::SECP256R1_ADD, + 0x00_00_01_2D => SyscallCode::SECP256R1_DOUBLE, + 0x00_00_01_2E => SyscallCode::SECP256R1_DECOMPRESS, _ => panic!("invalid syscall number: {value}"), } } diff --git a/crates/core/executor/src/syscalls/mod.rs b/crates/core/executor/src/syscalls/mod.rs index 6633633102..43811050b3 100644 --- a/crates/core/executor/src/syscalls/mod.rs +++ b/crates/core/executor/src/syscalls/mod.rs @@ -39,6 +39,7 @@ use sp1_curves::{ bls12_381::{Bls12381, Bls12381BaseField}, bn254::{Bn254, Bn254BaseField}, secp256k1::Secp256k1, + secp256r1::Secp256r1, }, }; use unconstrained::{EnterUnconstrainedSyscall, ExitUnconstrainedSyscall}; @@ -109,6 +110,21 @@ pub fn default_syscall_map() -> HashMap> { Arc::new(WeierstrassDecompressSyscall::::new()), ); + syscall_map.insert( + SyscallCode::SECP256R1_ADD, + Arc::new(WeierstrassAddAssignSyscall::::new()), + ); + + syscall_map.insert( + SyscallCode::SECP256R1_DOUBLE, + Arc::new(WeierstrassDoubleAssignSyscall::::new()), + ); + + syscall_map.insert( + SyscallCode::SECP256R1_DECOMPRESS, + Arc::new(WeierstrassDecompressSyscall::::new()), + ); + syscall_map .insert(SyscallCode::BN254_ADD, Arc::new(WeierstrassAddAssignSyscall::::new())); diff --git a/crates/core/executor/src/syscalls/precompiles/weierstrass/add.rs b/crates/core/executor/src/syscalls/precompiles/weierstrass/add.rs index f643196a77..0b6713f4dd 100644 --- a/crates/core/executor/src/syscalls/precompiles/weierstrass/add.rs +++ b/crates/core/executor/src/syscalls/precompiles/weierstrass/add.rs @@ -47,6 +47,11 @@ impl Syscall for WeierstrassAddAssignSyscall { syscall_event, PrecompileEvent::Bls12381Add(event), ), + CurveType::Secp256r1 => rt.record_mut().add_precompile_event( + syscall_code, + syscall_event, + PrecompileEvent::Secp256r1Add(event), + ), _ => panic!("Unsupported curve"), } None diff --git a/crates/core/executor/src/syscalls/precompiles/weierstrass/decompress.rs b/crates/core/executor/src/syscalls/precompiles/weierstrass/decompress.rs index 3c2069e118..8ad8fd5dfd 100644 --- a/crates/core/executor/src/syscalls/precompiles/weierstrass/decompress.rs +++ b/crates/core/executor/src/syscalls/precompiles/weierstrass/decompress.rs @@ -35,7 +35,12 @@ impl Syscall for WeierstrassDecompressSyscall { syscall_event, PrecompileEvent::Secp256k1Decompress(event), ), - CurveType::Bls12381 => rt.add_precompile_event( + CurveType::Secp256r1 => rt.record_mut().add_precompile_event( + syscall_code, + syscall_event, + PrecompileEvent::Secp256r1Decompress(event), + ), + CurveType::Bls12381 => rt.record_mut().add_precompile_event( syscall_code, syscall_event, PrecompileEvent::Bls12381Decompress(event), diff --git a/crates/core/executor/src/syscalls/precompiles/weierstrass/double.rs b/crates/core/executor/src/syscalls/precompiles/weierstrass/double.rs index 26d3090310..c88f381939 100644 --- a/crates/core/executor/src/syscalls/precompiles/weierstrass/double.rs +++ b/crates/core/executor/src/syscalls/precompiles/weierstrass/double.rs @@ -37,6 +37,11 @@ impl Syscall for WeierstrassDoubleAssignSyscall { PrecompileEvent::Secp256k1Double(event), ); } + CurveType::Secp256r1 => rt.record_mut().add_precompile_event( + syscall_code, + syscall_event, + PrecompileEvent::Secp256r1Double(event), + ), CurveType::Bn254 => { rt.add_precompile_event( syscall_code, diff --git a/crates/core/machine/Cargo.toml b/crates/core/machine/Cargo.toml index 60ae3da008..3bbd29d0b9 100644 --- a/crates/core/machine/Cargo.toml +++ b/crates/core/machine/Cargo.toml @@ -36,6 +36,8 @@ typenum = "1.17.0" elliptic-curve = "0.13.8" hex = "0.4.3" k256 = { version = "0.13.3", features = ["expose-field"] } +p256 = { version = "0.13.2", features = ["expose-field"] } + num_cpus = "1.16.0" size = "0.4.1" tempfile = "3.10.1" diff --git a/crates/core/machine/src/operations/field/field_den.rs b/crates/core/machine/src/operations/field/field_den.rs index 3c61a08e1d..b9bb80b306 100644 --- a/crates/core/machine/src/operations/field/field_den.rs +++ b/crates/core/machine/src/operations/field/field_den.rs @@ -1,6 +1,7 @@ use std::fmt::Debug; use num::BigUint; +use p3_air::AirBuilder; use p3_field::PrimeField32; use sp1_core_executor::events::ByteRecord; use sp1_curves::params::{FieldParameters, Limbs}; @@ -106,10 +107,10 @@ where ) where V: Into, { - let p_a = Polynomial::from(*a); - let p_b = (*b).into(); - let p_result = self.result.into(); - let p_carry = self.carry.into(); + let p_a: Polynomial<::Expr> = (*a).into(); + let p_b: Polynomial<::Expr> = (*b).into(); + let p_result: Polynomial<::Expr> = self.result.into(); + let p_carry: Polynomial<::Expr> = self.carry.into(); // Compute the vanishing polynomial: // lhs(x) = sign * (b(x) * result(x) + result(x)) + (1 - sign) * (b(x) * result(x) + @@ -120,9 +121,11 @@ where let p_equation_rhs = if sign { p_a } else { p_result }; let p_lhs_minus_rhs = &p_equation_lhs - &p_equation_rhs; - let p_limbs = Polynomial::from_iter(P::modulus_field_iter::().map(AB::Expr::from)); + let p_limbs: Polynomial<::Expr> = + Polynomial::from_iter(P::modulus_field_iter::().map(AB::Expr::from)); - let p_vanishing = p_lhs_minus_rhs - &p_carry * &p_limbs; + let p_vanishing: Polynomial<::Expr> = + p_lhs_minus_rhs - &p_carry * &p_limbs; let p_witness_low = self.witness_low.0.iter().into(); let p_witness_high = self.witness_high.0.iter().into(); diff --git a/crates/core/machine/src/operations/field/field_inner_product.rs b/crates/core/machine/src/operations/field/field_inner_product.rs index 6d2e7cb1db..30f2610e74 100644 --- a/crates/core/machine/src/operations/field/field_inner_product.rs +++ b/crates/core/machine/src/operations/field/field_inner_product.rs @@ -1,6 +1,7 @@ use std::fmt::Debug; use num::{BigUint, Zero}; +use p3_air::AirBuilder; use p3_field::{AbstractField, PrimeField32}; use sp1_core_executor::events::ByteRecord; use sp1_curves::params::{FieldParameters, Limbs}; @@ -93,16 +94,16 @@ where pub fn eval>( &self, builder: &mut AB, - a: &[Limbs], - b: &[Limbs], + a: &[impl Into> + Clone], + b: &[impl Into> + Clone], is_real: impl Into + Clone, ) where V: Into, { - let p_a_vec: Vec> = a.iter().map(|x| (*x).into()).collect(); - let p_b_vec: Vec> = b.iter().map(|x| (*x).into()).collect(); - let p_result = self.result.into(); - let p_carry = self.carry.into(); + let p_a_vec: Vec> = a.iter().cloned().map(|x| x.into()).collect(); + let p_b_vec: Vec> = b.iter().cloned().map(|x| x.into()).collect(); + let p_result: Polynomial<::Expr> = self.result.into(); + let p_carry: Polynomial<::Expr> = self.carry.into(); let p_zero = Polynomial::::new(vec![AB::Expr::zero()]); diff --git a/crates/core/machine/src/riscv/cost.rs b/crates/core/machine/src/riscv/cost.rs index 27469ee00a..db8f464c2f 100644 --- a/crates/core/machine/src/riscv/cost.rs +++ b/crates/core/machine/src/riscv/cost.rs @@ -55,6 +55,11 @@ impl CostEstimator for ExecutionReport { (k256_decompress_events as u64) * costs[&RiscvAirDiscriminants::K256Decompress]; total_chips += 1; + let p256_decompress_events = self.syscall_counts[SyscallCode::SECP256R1_DECOMPRESS]; + total_area += + (p256_decompress_events as u64) * costs[&RiscvAirDiscriminants::P256Decompress]; + total_chips += 1; + let secp256k1_add_events = self.syscall_counts[SyscallCode::SECP256K1_ADD]; total_area += (secp256k1_add_events as u64) * costs[&RiscvAirDiscriminants::Secp256k1Add]; total_chips += 1; @@ -64,6 +69,15 @@ impl CostEstimator for ExecutionReport { (secp256k1_double_events as u64) * costs[&RiscvAirDiscriminants::Secp256k1Double]; total_chips += 1; + let secp256r1_add_events = self.syscall_counts[SyscallCode::SECP256R1_ADD]; + total_area += (secp256r1_add_events as u64) * costs[&RiscvAirDiscriminants::Secp256r1Add]; + total_chips += 1; + + let secp256r1_double_events = self.syscall_counts[SyscallCode::SECP256R1_DOUBLE]; + total_area += + (secp256r1_double_events as u64) * costs[&RiscvAirDiscriminants::Secp256r1Double]; + total_chips += 1; + let keccak256_permute_events = self.syscall_counts[SyscallCode::KECCAK_PERMUTE]; total_area += (keccak256_permute_events as u64) * costs[&RiscvAirDiscriminants::KeccakP]; total_chips += 1; diff --git a/crates/core/machine/src/riscv/mod.rs b/crates/core/machine/src/riscv/mod.rs index 8865c937a7..6812eadbbe 100644 --- a/crates/core/machine/src/riscv/mod.rs +++ b/crates/core/machine/src/riscv/mod.rs @@ -55,7 +55,7 @@ pub(crate) mod riscv_chips { edwards::{ed25519::Ed25519Parameters, EdwardsCurve}, weierstrass::{ bls12_381::Bls12381Parameters, bn254::Bn254Parameters, secp256k1::Secp256k1Parameters, - SwCurve, + secp256r1::Secp256r1Parameters, SwCurve, }, }; } @@ -110,10 +110,16 @@ pub enum RiscvAir { Ed25519Decompress(EdDecompressChip), /// A precompile for decompressing a point on the K256 curve. K256Decompress(WeierstrassDecompressChip>), + /// A precompile for decompressing a point on the P256 curve. + P256Decompress(WeierstrassDecompressChip>), /// A precompile for addition on the Elliptic curve secp256k1. Secp256k1Add(WeierstrassAddAssignChip>), /// A precompile for doubling a point on the Elliptic curve secp256k1. Secp256k1Double(WeierstrassDoubleAssignChip>), + /// A precompile for addition on the Elliptic curve secp256r1. + Secp256r1Add(WeierstrassAddAssignChip>), + /// A precompile for doubling a point on the Elliptic curve secp256r1. + Secp256r1Double(WeierstrassDoubleAssignChip>), /// A precompile for the Keccak permutation. KeccakP(KeccakPermuteChip), /// A precompile for addition on the Elliptic curve bn254. @@ -218,6 +224,25 @@ impl RiscvAir { costs.insert(RiscvAirDiscriminants::Secp256k1Double, secp256k1_double_assign.cost()); chips.push(secp256k1_double_assign); + let p256_decompress = Chip::new(RiscvAir::P256Decompress(WeierstrassDecompressChip::< + SwCurve, + >::with_lsb_rule())); + costs.insert(RiscvAirDiscriminants::P256Decompress, p256_decompress.cost()); + chips.push(p256_decompress); + + let secp256r1_add_assign = Chip::new(RiscvAir::Secp256r1Add(WeierstrassAddAssignChip::< + SwCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Secp256r1Add, secp256r1_add_assign.cost()); + chips.push(secp256r1_add_assign); + + let secp256r1_double_assign = + Chip::new(RiscvAir::Secp256r1Double(WeierstrassDoubleAssignChip::< + SwCurve, + >::new())); + costs.insert(RiscvAirDiscriminants::Secp256r1Double, secp256r1_double_assign.cost()); + chips.push(secp256r1_double_assign); + let keccak_permute = Chip::new(RiscvAir::KeccakP(KeccakPermuteChip::new())); costs.insert(RiscvAirDiscriminants::KeccakP, 24 * keccak_permute.cost()); chips.push(keccak_permute); @@ -472,11 +497,14 @@ impl RiscvAir { Self::KeccakP(_) => SyscallCode::KECCAK_PERMUTE, Self::Secp256k1Add(_) => SyscallCode::SECP256K1_ADD, Self::Secp256k1Double(_) => SyscallCode::SECP256K1_DOUBLE, + Self::Secp256r1Add(_) => SyscallCode::SECP256R1_ADD, + Self::Secp256r1Double(_) => SyscallCode::SECP256R1_DOUBLE, Self::Sha256Compress(_) => SyscallCode::SHA_COMPRESS, Self::Sha256Extend(_) => SyscallCode::SHA_EXTEND, Self::Uint256Mul(_) => SyscallCode::UINT256_MUL, Self::Bls12381Decompress(_) => SyscallCode::BLS12381_DECOMPRESS, Self::K256Decompress(_) => SyscallCode::SECP256K1_DECOMPRESS, + Self::P256Decompress(_) => SyscallCode::SECP256R1_DECOMPRESS, Self::Bls12381Double(_) => SyscallCode::BLS12381_DOUBLE, Self::Bls12381Fp(_) => SyscallCode::BLS12381_FP_ADD, Self::Bls12381Fp2Mul(_) => SyscallCode::BLS12381_FP2_MUL, diff --git a/crates/core/machine/src/runtime/syscall.rs b/crates/core/machine/src/runtime/syscall.rs index 789b073b46..1d15ddf727 100644 --- a/crates/core/machine/src/runtime/syscall.rs +++ b/crates/core/machine/src/runtime/syscall.rs @@ -73,6 +73,15 @@ pub enum SyscallCode { /// Executes the `SECP256K1_DECOMPRESS` precompile. SECP256K1_DECOMPRESS = 0x00_00_01_0C, + /// Executes the `SECP256R1_ADD` precompile. + SECP256R1_ADD = 0x00_01_01_2C, + + /// Executes the `SECP256R1_DOUBLE` precompile. + SECP256R1_DOUBLE = 0x00_00_01_2D, + + /// Executes the `SECP256R1_DECOMPRESS` precompile. + SECP256R1_DECOMPRESS = 0x00_00_01_2E, + /// Executes the `BN254_ADD` precompile. BN254_ADD = 0x00_01_01_0E, @@ -159,6 +168,9 @@ impl SyscallCode { 0x00_01_01_0A => SyscallCode::SECP256K1_ADD, 0x00_00_01_0B => SyscallCode::SECP256K1_DOUBLE, 0x00_00_01_0C => SyscallCode::SECP256K1_DECOMPRESS, + 0x00_01_01_2C => SyscallCode::SECP256R1_ADD, + 0x00_00_01_2D => SyscallCode::SECP256R1_DOUBLE, + 0x00_00_01_2E => SyscallCode::SECP256R1_DECOMPRESS, 0x00_01_01_0E => SyscallCode::BN254_ADD, 0x00_00_01_0F => SyscallCode::BN254_DOUBLE, 0x00_01_01_1E => SyscallCode::BLS12381_ADD, @@ -336,22 +348,12 @@ pub fn default_syscall_map() -> HashMap> { syscall_map.insert(SyscallCode::HALT, Arc::new(SyscallHalt {})); syscall_map.insert(SyscallCode::SHA_EXTEND, Arc::new(ShaExtendChip::new())); syscall_map.insert(SyscallCode::SHA_COMPRESS, Arc::new(ShaCompressChip::new())); - syscall_map.insert( - SyscallCode::ED_ADD, - Arc::new(EdAddAssignChip::::new()), - ); - syscall_map.insert( - SyscallCode::ED_DECOMPRESS, - Arc::new(EdDecompressChip::::new()), - ); - syscall_map.insert( - SyscallCode::KECCAK_PERMUTE, - Arc::new(KeccakPermuteChip::new()), - ); - syscall_map.insert( - SyscallCode::SECP256K1_ADD, - Arc::new(WeierstrassAddAssignChip::::new()), - ); + syscall_map.insert(SyscallCode::ED_ADD, Arc::new(EdAddAssignChip::::new())); + syscall_map + .insert(SyscallCode::ED_DECOMPRESS, Arc::new(EdDecompressChip::::new())); + syscall_map.insert(SyscallCode::KECCAK_PERMUTE, Arc::new(KeccakPermuteChip::new())); + syscall_map + .insert(SyscallCode::SECP256K1_ADD, Arc::new(WeierstrassAddAssignChip::::new())); syscall_map.insert( SyscallCode::SECP256K1_DOUBLE, Arc::new(WeierstrassDoubleAssignChip::::new()), @@ -360,18 +362,21 @@ pub fn default_syscall_map() -> HashMap> { SyscallCode::SECP256K1_DECOMPRESS, Arc::new(WeierstrassDecompressChip::::with_lsb_rule()), ); + syscall_map + .insert(SyscallCode::SECP256R1_ADD, Arc::new(WeierstrassAddAssignChip::::new())); syscall_map.insert( - SyscallCode::BN254_ADD, - Arc::new(WeierstrassAddAssignChip::::new()), - ); - syscall_map.insert( - SyscallCode::BN254_DOUBLE, - Arc::new(WeierstrassDoubleAssignChip::::new()), + SyscallCode::SECP256R1_DOUBLE, + Arc::new(WeierstrassDoubleAssignChip::::new()), ); syscall_map.insert( - SyscallCode::BLS12381_ADD, - Arc::new(WeierstrassAddAssignChip::::new()), + SyscallCode::SECP256R1_DECOMPRESS, + Arc::new(WeierstrassDecompressChip::::with_lsb_rule()), ); + syscall_map.insert(SyscallCode::BN254_ADD, Arc::new(WeierstrassAddAssignChip::::new())); + syscall_map + .insert(SyscallCode::BN254_DOUBLE, Arc::new(WeierstrassDoubleAssignChip::::new())); + syscall_map + .insert(SyscallCode::BLS12381_ADD, Arc::new(WeierstrassAddAssignChip::::new())); syscall_map.insert( SyscallCode::BLS12381_DOUBLE, Arc::new(WeierstrassDoubleAssignChip::::new()), @@ -391,15 +396,11 @@ pub fn default_syscall_map() -> HashMap> { ); syscall_map.insert( SyscallCode::BLS12381_FP2_ADD, - Arc::new(Fp2AddSubSyscall::::new( - FieldOperation::Add, - )), + Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Add)), ); syscall_map.insert( SyscallCode::BLS12381_FP2_SUB, - Arc::new(Fp2AddSubSyscall::::new( - FieldOperation::Sub, - )), + Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Sub)), ); syscall_map.insert( SyscallCode::BLS12381_FP2_MUL, @@ -425,28 +426,15 @@ pub fn default_syscall_map() -> HashMap> { SyscallCode::BN254_FP2_SUB, Arc::new(Fp2AddSubSyscall::::new(FieldOperation::Sub)), ); - syscall_map.insert( - SyscallCode::BN254_FP2_MUL, - Arc::new(Fp2MulAssignChip::::new()), - ); - syscall_map.insert( - SyscallCode::ENTER_UNCONSTRAINED, - Arc::new(SyscallEnterUnconstrained::new()), - ); - syscall_map.insert( - SyscallCode::EXIT_UNCONSTRAINED, - Arc::new(SyscallExitUnconstrained::new()), - ); + syscall_map + .insert(SyscallCode::BN254_FP2_MUL, Arc::new(Fp2MulAssignChip::::new())); + syscall_map + .insert(SyscallCode::ENTER_UNCONSTRAINED, Arc::new(SyscallEnterUnconstrained::new())); + syscall_map.insert(SyscallCode::EXIT_UNCONSTRAINED, Arc::new(SyscallExitUnconstrained::new())); syscall_map.insert(SyscallCode::WRITE, Arc::new(SyscallWrite::new())); syscall_map.insert(SyscallCode::COMMIT, Arc::new(SyscallCommit::new())); - syscall_map.insert( - SyscallCode::COMMIT_DEFERRED_PROOFS, - Arc::new(SyscallCommitDeferred::new()), - ); - syscall_map.insert( - SyscallCode::VERIFY_SP1_PROOF, - Arc::new(SyscallVerifySP1Proof::new()), - ); + syscall_map.insert(SyscallCode::COMMIT_DEFERRED_PROOFS, Arc::new(SyscallCommitDeferred::new())); + syscall_map.insert(SyscallCode::VERIFY_SP1_PROOF, Arc::new(SyscallVerifySP1Proof::new())); syscall_map.insert(SyscallCode::HINT_LEN, Arc::new(SyscallHintLen::new())); syscall_map.insert(SyscallCode::HINT_READ, Arc::new(SyscallHintRead::new())); syscall_map.insert( @@ -513,9 +501,15 @@ mod tests { SyscallCode::SECP256K1_ADD => { assert_eq!(code as u32, sp1_zkvm::syscalls::SECP256K1_ADD) } + SyscallCode::SECP256R1_ADD => { + assert_eq!(code as u32, sp1_zkvm::syscalls::SECP256R1_ADD) + } SyscallCode::SECP256K1_DOUBLE => { assert_eq!(code as u32, sp1_zkvm::syscalls::SECP256K1_DOUBLE) } + SyscallCode::SECP256R1_DOUBLE => { + assert_eq!(code as u32, sp1_zkvm::syscalls::SECP256R1_DOUBLE) + } SyscallCode::BLS12381_ADD => { assert_eq!(code as u32, sp1_zkvm::syscalls::BLS12381_ADD) } @@ -525,6 +519,9 @@ mod tests { SyscallCode::SECP256K1_DECOMPRESS => { assert_eq!(code as u32, sp1_zkvm::syscalls::SECP256K1_DECOMPRESS) } + SyscallCode::SECP256R1_DECOMPRESS => { + assert_eq!(code as u32, sp1_zkvm::syscalls::SECP256R1_DECOMPRESS) + } SyscallCode::BN254_ADD => assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_ADD), SyscallCode::BN254_DOUBLE => { assert_eq!(code as u32, sp1_zkvm::syscalls::BN254_DOUBLE) diff --git a/crates/core/machine/src/syscall/precompiles/edwards/ed_add.rs b/crates/core/machine/src/syscall/precompiles/edwards/ed_add.rs index 45c69af419..94e81e20cb 100644 --- a/crates/core/machine/src/syscall/precompiles/edwards/ed_add.rs +++ b/crates/core/machine/src/syscall/precompiles/edwards/ed_add.rs @@ -20,7 +20,7 @@ use sp1_core_executor::{ }; use sp1_curves::{ edwards::{ed25519::Ed25519BaseField, EdwardsParameters, NUM_LIMBS, WORDS_CURVE_POINT}, - params::FieldParameters, + params::{FieldParameters, Limbs, NumLimbs}, AffinePoint, EllipticCurve, }; use sp1_derive::AlignedBorrow; @@ -262,10 +262,14 @@ where builder.when_first_row().assert_zero(local.nonce); builder.when_transition().assert_eq(local.nonce + AB::Expr::one(), next.nonce); - let x1 = limbs_from_prev_access(&local.p_access[0..8]); - let x2 = limbs_from_prev_access(&local.q_access[0..8]); - let y1 = limbs_from_prev_access(&local.p_access[8..16]); - let y2 = limbs_from_prev_access(&local.q_access[8..16]); + let x1: Limbs::Limbs> = + limbs_from_prev_access(&local.p_access[0..8]); + let x2: Limbs::Limbs> = + limbs_from_prev_access(&local.q_access[0..8]); + let y1: Limbs::Limbs> = + limbs_from_prev_access(&local.p_access[8..16]); + let y2: Limbs::Limbs> = + limbs_from_prev_access(&local.q_access[8..16]); // x3_numerator = x1 * y2 + x2 * y1. local.x3_numerator.eval(builder, &[x1, x2], &[y2, y1], local.is_real); diff --git a/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_add.rs index 65e03f1c17..d678f93086 100644 --- a/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -150,6 +150,7 @@ impl MachineAir fn name(&self) -> String { match E::CURVE_TYPE { CurveType::Secp256k1 => "Secp256k1AddAssign".to_string(), + CurveType::Secp256r1 => "Secp256r1AddAssign".to_string(), CurveType::Bn254 => "Bn254AddAssign".to_string(), CurveType::Bls12381 => "Bls12381AddAssign".to_string(), _ => panic!("Unsupported curve"), @@ -159,6 +160,7 @@ impl MachineAir fn generate_dependencies(&self, input: &Self::Record, output: &mut Self::Record) { let events = match E::CURVE_TYPE { CurveType::Secp256k1 => &input.get_precompile_events(SyscallCode::SECP256K1_ADD), + CurveType::Secp256r1 => &input.get_precompile_events(SyscallCode::SECP256R1_ADD), CurveType::Bn254 => &input.get_precompile_events(SyscallCode::BN254_ADD), CurveType::Bls12381 => &input.get_precompile_events(SyscallCode::BLS12381_ADD), _ => panic!("Unsupported curve"), @@ -174,6 +176,7 @@ impl MachineAir let mut blu = Vec::new(); ops.iter().for_each(|(_, op)| match op { PrecompileEvent::Secp256k1Add(event) + | PrecompileEvent::Secp256r1Add(event) | PrecompileEvent::Bn254Add(event) | PrecompileEvent::Bls12381Add(event) => { let mut row = zeroed_f_vec(num_cols); @@ -199,6 +202,7 @@ impl MachineAir ) -> RowMajorMatrix { let events = match E::CURVE_TYPE { CurveType::Secp256k1 => input.get_precompile_events(SyscallCode::SECP256K1_ADD), + CurveType::Secp256r1 => input.get_precompile_events(SyscallCode::SECP256R1_ADD), CurveType::Bn254 => input.get_precompile_events(SyscallCode::BN254_ADD), CurveType::Bls12381 => input.get_precompile_events(SyscallCode::BLS12381_ADD), _ => panic!("Unsupported curve"), @@ -234,6 +238,7 @@ impl MachineAir let cols: &mut WeierstrassAddAssignCols = row.borrow_mut(); match &events[idx].1 { PrecompileEvent::Secp256k1Add(event) + | PrecompileEvent::Secp256r1Add(event) | PrecompileEvent::Bn254Add(event) | PrecompileEvent::Bls12381Add(event) => { Self::populate_row(event, cols, &mut new_byte_lookup_events); @@ -269,6 +274,9 @@ impl MachineAir CurveType::Secp256k1 => { !shard.get_precompile_events(SyscallCode::SECP256K1_ADD).is_empty() } + CurveType::Secp256r1 => { + !shard.get_precompile_events(SyscallCode::SECP256R1_ADD).is_empty() + } CurveType::Bn254 => !shard.get_precompile_events(SyscallCode::BN254_ADD).is_empty(), CurveType::Bls12381 => { !shard.get_precompile_events(SyscallCode::BLS12381_ADD).is_empty() @@ -397,6 +405,9 @@ where CurveType::Secp256k1 => { AB::F::from_canonical_u32(SyscallCode::SECP256K1_ADD.syscall_id()) } + CurveType::Secp256r1 => { + AB::F::from_canonical_u32(SyscallCode::SECP256R1_ADD.syscall_id()) + } CurveType::Bn254 => AB::F::from_canonical_u32(SyscallCode::BN254_ADD.syscall_id()), CurveType::Bls12381 => { AB::F::from_canonical_u32(SyscallCode::BLS12381_ADD.syscall_id()) @@ -460,7 +471,7 @@ mod tests { run_test, setup_logger, tests::{ BLS12381_ADD_ELF, BLS12381_DOUBLE_ELF, BLS12381_MUL_ELF, BN254_ADD_ELF, BN254_MUL_ELF, - SECP256K1_ADD_ELF, SECP256K1_MUL_ELF, + SECP256K1_ADD_ELF, SECP256K1_MUL_ELF, SECP256R1_ADD_ELF, }, }; @@ -471,6 +482,13 @@ mod tests { run_test::>(program).unwrap(); } + #[test] + fn test_secp256r1_add_simple() { + setup_logger(); + let program = Program::from(SECP256R1_ADD_ELF).unwrap(); + run_test::>(program).unwrap(); + } + #[test] fn test_bn254_add_simple() { setup_logger(); diff --git a/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs index ddf0728d2c..1edc1440f9 100644 --- a/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs +++ b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_decompress.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use crate::{air::MemoryAirBuilder, utils::zeroed_f_vec}; use generic_array::GenericArray; -use num::{BigUint, Zero}; +use num::{BigUint, One, Zero}; use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{AbstractField, PrimeField32}; use p3_matrix::{dense::RowMajorMatrix, Matrix}; @@ -17,17 +17,23 @@ use sp1_core_executor::{ }; use sp1_curves::{ params::{limbs_from_vec, FieldParameters, Limbs, NumLimbs, NumWords}, - weierstrass::{bls12_381::bls12381_sqrt, secp256k1::secp256k1_sqrt, WeierstrassParameters}, + weierstrass::{ + bls12_381::bls12381_sqrt, secp256k1::secp256k1_sqrt, secp256r1::secp256r1_sqrt, + WeierstrassParameters, + }, CurveType, EllipticCurve, }; use sp1_derive::AlignedBorrow; -use sp1_stark::air::{BaseAirBuilder, InteractionScope, MachineAir, SP1AirBuilder}; +use sp1_stark::air::{BaseAirBuilder, InteractionScope, MachineAir, Polynomial, SP1AirBuilder}; use std::marker::PhantomData; use typenum::Unsigned; use crate::{ memory::{MemoryReadCols, MemoryReadWriteCols}, - operations::field::{field_op::FieldOpCols, field_sqrt::FieldSqrtCols, range::FieldLtCols}, + operations::field::{ + field_inner_product::FieldInnerProductCols, field_op::FieldOpCols, + field_sqrt::FieldSqrtCols, range::FieldLtCols, + }, utils::{bytes_to_words_le_vec, limbs_from_access, limbs_from_prev_access, pad_rows_fixed}, }; @@ -51,7 +57,8 @@ pub struct WeierstrassDecompressCols { pub(crate) range_x: FieldLtCols, pub(crate) x_2: FieldOpCols, pub(crate) x_3: FieldOpCols, - pub(crate) x_3_plus_b: FieldOpCols, + pub(crate) ax_plus_b: FieldInnerProductCols, + pub(crate) x_3_plus_b_plus_ax: FieldOpCols, pub(crate) y: FieldSqrtCols, pub(crate) neg_y: FieldOpCols, } @@ -107,20 +114,26 @@ impl WeierstrassDecompressChip { cols: &mut WeierstrassDecompressCols, x: BigUint, ) { - // Y = sqrt(x^3 + b) + // Y = sqrt(x^3 + ax + b) cols.range_x.populate(record, shard, &x, &E::BaseField::modulus()); let x_2 = cols.x_2.populate(record, shard, &x.clone(), &x.clone(), FieldOperation::Mul); let x_3 = cols.x_3.populate(record, shard, &x_2, &x, FieldOperation::Mul); let b = E::b_int(); - let x_3_plus_b = cols.x_3_plus_b.populate(record, shard, &x_3, &b, FieldOperation::Add); + let a = E::a_int(); + let param_vec = vec![a, b]; + let x_vec = vec![x, BigUint::one()]; + let ax_plus_b = cols.ax_plus_b.populate(record, shard, ¶m_vec, &x_vec); + let x_3_plus_b_plus_ax = + cols.x_3_plus_b_plus_ax.populate(record, shard, &x_3, &ax_plus_b, FieldOperation::Add); let sqrt_fn = match E::CURVE_TYPE { CurveType::Secp256k1 => secp256k1_sqrt, + CurveType::Secp256r1 => secp256r1_sqrt, CurveType::Bls12381 => bls12381_sqrt, _ => panic!("Unsupported curve"), }; - let y = cols.y.populate(record, shard, &x_3_plus_b, sqrt_fn); + let y = cols.y.populate(record, shard, &x_3_plus_b_plus_ax, sqrt_fn); let zero = BigUint::zero(); cols.neg_y.populate(record, shard, &zero, &y, FieldOperation::Sub); } @@ -135,6 +148,7 @@ impl MachineAir fn name(&self) -> String { match E::CURVE_TYPE { CurveType::Secp256k1 => "Secp256k1Decompress".to_string(), + CurveType::Secp256r1 => "Secp256r1Decompress".to_string(), CurveType::Bls12381 => "Bls12381Decompress".to_string(), _ => panic!("Unsupported curve"), } @@ -147,6 +161,7 @@ impl MachineAir ) -> RowMajorMatrix { let events = match E::CURVE_TYPE { CurveType::Secp256k1 => input.get_precompile_events(SyscallCode::SECP256K1_DECOMPRESS), + CurveType::Secp256r1 => input.get_precompile_events(SyscallCode::SECP256R1_DECOMPRESS), CurveType::Bls12381 => input.get_precompile_events(SyscallCode::BLS12381_DECOMPRESS), _ => panic!("Unsupported curve"), }; @@ -162,6 +177,7 @@ impl MachineAir for (_, event) in events { let event = match (E::CURVE_TYPE, event) { (CurveType::Secp256k1, PrecompileEvent::Secp256k1Decompress(event)) => event, + (CurveType::Secp256r1, PrecompileEvent::Secp256r1Decompress(event)) => event, (CurveType::Bls12381, PrecompileEvent::Bls12381Decompress(event)) => event, _ => panic!("Unsupported curve"), }; @@ -282,6 +298,9 @@ impl MachineAir CurveType::Secp256k1 => { !shard.get_precompile_events(SyscallCode::SECP256K1_DECOMPRESS).is_empty() } + CurveType::Secp256r1 => { + !shard.get_precompile_events(SyscallCode::SECP256R1_DECOMPRESS).is_empty() + } CurveType::Bls12381 => { !shard.get_precompile_events(SyscallCode::BLS12381_DECOMPRESS).is_empty() } @@ -339,12 +358,17 @@ where ); local.x_2.eval(builder, &x, &x, FieldOperation::Mul, local.is_real); local.x_3.eval(builder, &local.x_2.result, &x, FieldOperation::Mul, local.is_real); - let b = E::b_int(); - let b_const = E::BaseField::to_limbs_field::(&b); - local.x_3_plus_b.eval( + let b_const = E::BaseField::to_limbs_field::(&E::b_int()); + let a_const = E::BaseField::to_limbs_field::(&E::a_int()); + let params = [a_const, b_const]; + let p_x: Polynomial = x.into(); + let p_one: Polynomial = + E::BaseField::to_limbs_field::(&BigUint::one()).into(); + local.ax_plus_b.eval::(builder, ¶ms, &[p_x, p_one], local.is_real); + local.x_3_plus_b_plus_ax.eval( builder, &local.x_3.result, - &b_const, + &local.ax_plus_b.result, FieldOperation::Add, local.is_real, ); @@ -357,7 +381,7 @@ where local.is_real, ); - local.y.eval(builder, &local.x_3_plus_b.result, local.y.lsb, local.is_real); + local.y.eval(builder, &local.x_3_plus_b_plus_ax.result, local.y.lsb, local.is_real); let y_limbs: Limbs::Limbs> = limbs_from_access(&local.y_access); @@ -492,6 +516,9 @@ where CurveType::Secp256k1 => { AB::F::from_canonical_u32(SyscallCode::SECP256K1_DECOMPRESS.syscall_id()) } + CurveType::Secp256r1 => { + AB::F::from_canonical_u32(SyscallCode::SECP256R1_DECOMPRESS.syscall_id()) + } CurveType::Bls12381 => { AB::F::from_canonical_u32(SyscallCode::BLS12381_DECOMPRESS.syscall_id()) } @@ -526,7 +553,9 @@ mod tests { use sp1_core_executor::Program; use sp1_stark::CpuProver; - use crate::utils::{run_test_io, tests::SECP256K1_DECOMPRESS_ELF}; + use crate::utils::{ + run_test_io, tests::SECP256K1_DECOMPRESS_ELF, tests::SECP256R1_DECOMPRESS_ELF, + }; #[test] fn test_weierstrass_bls_decompress() { @@ -587,4 +616,33 @@ mod tests { assert_eq!(result, decompressed); } } + + #[test] + fn test_weierstrass_p256_decompress() { + utils::setup_logger(); + + let mut rng = thread_rng(); + + let num_tests = 1; + + for _ in 0..num_tests { + let secret_key = p256::SecretKey::random(&mut rng); + let public_key = secret_key.public_key(); + let encoded = public_key.to_encoded_point(false); + let decompressed = encoded.as_bytes(); + let encoded_compressed = public_key.to_encoded_point(true); + let compressed = encoded_compressed.as_bytes(); + + let inputs = SP1Stdin::from(compressed); + + let mut public_values = run_test_io::>( + Program::from(SECP256R1_DECOMPRESS_ELF).unwrap(), + inputs, + ) + .unwrap(); + let mut result = [0; 65]; + public_values.read_slice(&mut result); + assert_eq!(result, decompressed); + } + } } diff --git a/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_double.rs index fc39b858c0..9e18fc60f1 100644 --- a/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/crates/core/machine/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -6,15 +6,15 @@ use std::{fmt::Debug, marker::PhantomData}; use crate::{air::MemoryAirBuilder, utils::zeroed_f_vec}; use generic_array::GenericArray; -use num::{BigUint, Zero}; +use num::{BigUint, One, Zero}; use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{AbstractField, PrimeField32}; use p3_matrix::{dense::RowMajorMatrix, Matrix}; use p3_maybe_rayon::prelude::{ParallelBridge, ParallelIterator, ParallelSlice}; use sp1_core_executor::{ events::{ - ByteLookupEvent, ByteRecord, EllipticCurveDoubleEvent, FieldOperation, PrecompileEvent, - SyscallEvent, + ByteLookupEvent, ByteRecord, EllipticCurveDoubleEvent, FieldOperation, MemoryWriteRecord, + PrecompileEvent, SyscallEvent, }, syscalls::SyscallCode, ExecutionRecord, Program, @@ -83,8 +83,6 @@ impl WeierstrassDoubleAssignChip { // This populates necessary field operations to double a point on a Weierstrass curve. let a = E::a_int(); - - // slope = slope_numerator / slope_denominator. let slope = { // slope_numerator = a + (p.x * p.x) * 3. let slope_numerator = { @@ -170,6 +168,7 @@ impl MachineAir fn name(&self) -> String { match E::CURVE_TYPE { CurveType::Secp256k1 => "Secp256k1DoubleAssign".to_string(), + CurveType::Secp256r1 => "Secp256r1DoubleAssign".to_string(), CurveType::Bn254 => "Bn254DoubleAssign".to_string(), CurveType::Bls12381 => "Bls12381DoubleAssign".to_string(), _ => panic!("Unsupported curve"), @@ -179,6 +178,7 @@ impl MachineAir fn generate_dependencies(&self, input: &Self::Record, output: &mut Self::Record) { let events = match E::CURVE_TYPE { CurveType::Secp256k1 => &input.get_precompile_events(SyscallCode::SECP256K1_DOUBLE), + CurveType::Secp256r1 => &input.get_precompile_events(SyscallCode::SECP256R1_DOUBLE), CurveType::Bn254 => &input.get_precompile_events(SyscallCode::BN254_DOUBLE), CurveType::Bls12381 => &input.get_precompile_events(SyscallCode::BLS12381_DOUBLE), _ => panic!("Unsupported curve"), @@ -194,6 +194,7 @@ impl MachineAir let mut blu = Vec::new(); ops.iter().for_each(|(_, op)| match op { PrecompileEvent::Secp256k1Double(event) + | PrecompileEvent::Secp256r1Double(event) | PrecompileEvent::Bn254Double(event) | PrecompileEvent::Bls12381Double(event) => { let mut row = zeroed_f_vec(num_cols); @@ -220,6 +221,7 @@ impl MachineAir // collects the events based on the curve type. let events = match E::CURVE_TYPE { CurveType::Secp256k1 => input.get_precompile_events(SyscallCode::SECP256K1_DOUBLE), + CurveType::Secp256r1 => input.get_precompile_events(SyscallCode::SECP256R1_DOUBLE), CurveType::Bn254 => input.get_precompile_events(SyscallCode::BN254_DOUBLE), CurveType::Bls12381 => input.get_precompile_events(SyscallCode::BLS12381_DOUBLE), _ => panic!("Unsupported curve"), @@ -233,11 +235,22 @@ impl MachineAir let mut values = zeroed_f_vec(num_rows * num_cols); let chunk_size = 64; + let num_words_field_element = E::BaseField::NB_LIMBS / 4; let mut dummy_row = zeroed_f_vec(num_cols); let cols: &mut WeierstrassDoubleAssignCols = dummy_row.as_mut_slice().borrow_mut(); + let dummy_memory_record = MemoryWriteRecord { + value: 1, + shard: 0, + timestamp: 1, + prev_value: 1, + prev_shard: 0, + prev_timestamp: 0, + }; let zero = BigUint::zero(); - Self::populate_field_ops(&mut vec![], 0, cols, zero.clone(), zero); + let one = BigUint::one(); + cols.p_access[num_words_field_element].populate(dummy_memory_record, &mut vec![]); + Self::populate_field_ops(&mut vec![], 0, cols, zero, one); values.chunks_mut(chunk_size * num_cols).enumerate().par_bridge().for_each(|(i, rows)| { rows.chunks_mut(num_cols).enumerate().for_each(|(j, row)| { @@ -247,6 +260,7 @@ impl MachineAir let cols: &mut WeierstrassDoubleAssignCols = row.borrow_mut(); match &events[idx].1 { PrecompileEvent::Secp256k1Double(event) + | PrecompileEvent::Secp256r1Double(event) | PrecompileEvent::Bn254Double(event) | PrecompileEvent::Bls12381Double(event) => { Self::populate_row(event, cols, &mut new_byte_lookup_events); @@ -282,6 +296,9 @@ impl MachineAir CurveType::Secp256k1 => { !shard.get_precompile_events(SyscallCode::SECP256K1_DOUBLE).is_empty() } + CurveType::Secp256r1 => { + !shard.get_precompile_events(SyscallCode::SECP256R1_DOUBLE).is_empty() + } CurveType::Bn254 => { !shard.get_precompile_events(SyscallCode::BN254_DOUBLE).is_empty() } @@ -450,6 +467,9 @@ where CurveType::Secp256k1 => { AB::F::from_canonical_u32(SyscallCode::SECP256K1_DOUBLE.syscall_id()) } + CurveType::Secp256r1 => { + AB::F::from_canonical_u32(SyscallCode::SECP256R1_DOUBLE.syscall_id()) + } CurveType::Bn254 => AB::F::from_canonical_u32(SyscallCode::BN254_DOUBLE.syscall_id()), CurveType::Bls12381 => { AB::F::from_canonical_u32(SyscallCode::BLS12381_DOUBLE.syscall_id()) @@ -472,13 +492,14 @@ where #[cfg(test)] pub mod tests { - use sp1_core_executor::Program; use sp1_stark::CpuProver; use crate::utils::{ run_test, setup_logger, - tests::{BLS12381_DOUBLE_ELF, BN254_DOUBLE_ELF, SECP256K1_DOUBLE_ELF}, + tests::{ + BLS12381_DOUBLE_ELF, BN254_DOUBLE_ELF, SECP256K1_DOUBLE_ELF, SECP256R1_DOUBLE_ELF, + }, }; #[test] @@ -488,6 +509,13 @@ pub mod tests { run_test::>(program).unwrap(); } + #[test] + fn test_secp256r1_double_simple() { + setup_logger(); + let program = Program::from(SECP256R1_DOUBLE_ELF).unwrap(); + run_test::>(program).unwrap(); + } + #[test] fn test_bn254_double_simple() { setup_logger(); diff --git a/crates/core/machine/src/utils/programs.rs b/crates/core/machine/src/utils/programs.rs index 5d51137dd3..4ee29bb7ad 100644 --- a/crates/core/machine/src/utils/programs.rs +++ b/crates/core/machine/src/utils/programs.rs @@ -59,6 +59,15 @@ pub mod tests { pub const SECP256K1_DOUBLE_ELF: &[u8] = include_bytes!("../../../../../tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf"); + pub const SECP256R1_ADD_ELF: &[u8] = + include_bytes!("../../../../../tests/secp256r1-add/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256R1_DECOMPRESS_ELF: &[u8] = + include_bytes!("../../../../../tests/secp256r1-decompress/elf/riscv32im-succinct-zkvm-elf"); + + pub const SECP256R1_DOUBLE_ELF: &[u8] = + include_bytes!("../../../../../tests/secp256r1-double/elf/riscv32im-succinct-zkvm-elf"); + pub const SHA_COMPRESS_ELF: &[u8] = include_bytes!("../../../../../tests/sha-compress/elf/riscv32im-succinct-zkvm-elf"); diff --git a/crates/core/machine/src/utils/span.rs b/crates/core/machine/src/utils/span.rs index 032598cc26..8e8ce69933 100644 --- a/crates/core/machine/src/utils/span.rs +++ b/crates/core/machine/src/utils/span.rs @@ -109,7 +109,8 @@ where /// Calculate the total number of items counted by this span and its children. pub fn total(&self) -> usize { - self.cts.values().cloned().chain(self.children.iter().map(|x| x.total())).sum() + // Counts are already added from children. + self.cts.values().cloned().sum() } /// Format and yield lines describing this span. Appropriate for logging. diff --git a/crates/curves/Cargo.toml b/crates/curves/Cargo.toml index 8d7f16afcc..5e6d2b8420 100644 --- a/crates/curves/Cargo.toml +++ b/crates/curves/Cargo.toml @@ -15,6 +15,7 @@ serde = { version = "1.0.207", features = ["derive"] } typenum = "1.17.0" curve25519-dalek = { version = "4.1.2" } k256 = { version = "0.13.3", features = ["expose-field"] } +p256 = { version = "0.13.2", features = ["expose-field"] } generic-array = { version = "1.1.0", features = ["alloc", "serde"] } amcl = { package = "snowbridge-amcl", version = "1.0.2", default-features = false, features = [ "bls381", diff --git a/crates/curves/src/lib.rs b/crates/curves/src/lib.rs index 7b91ab429f..c3f66d9eac 100644 --- a/crates/curves/src/lib.rs +++ b/crates/curves/src/lib.rs @@ -17,6 +17,13 @@ pub mod k256 { }; } +pub mod p256 { + pub use p256::{ + ecdsa::{Signature, VerifyingKey}, + elliptic_curve::ops::Invert, + }; +} + use params::{FieldParameters, NumWords}; use sp1_primitives::consts::WORD_SIZE; use std::{ @@ -39,6 +46,7 @@ pub const NUM_WORDS_EC_POINT: usize = 2 * NUM_WORDS_FIELD_ELEMENT; #[derive(Debug, PartialEq, Eq)] pub enum CurveType { Secp256k1, + Secp256r1, Bn254, Ed25519, Bls12381, @@ -48,6 +56,7 @@ impl Display for CurveType { fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self { CurveType::Secp256k1 => write!(f, "Secp256k1"), + CurveType::Secp256r1 => write!(f, "Secp256r1"), CurveType::Bn254 => write!(f, "Bn254"), CurveType::Ed25519 => write!(f, "Ed25519"), CurveType::Bls12381 => write!(f, "Bls12381"), diff --git a/crates/curves/src/params.rs b/crates/curves/src/params.rs index 7bf2af5459..e3524fa875 100644 --- a/crates/curves/src/params.rs +++ b/crates/curves/src/params.rs @@ -164,3 +164,13 @@ impl<'a, T: Debug + Default + Clone, N: ArrayLength> From> for Limbs Self(inner) } } + +impl FromIterator for Limbs { + #[inline] + fn from_iter(iter: I) -> Limbs + where + I: IntoIterator, + { + Limbs(GenericArray::from_iter(iter)) + } +} diff --git a/crates/curves/src/weierstrass/mod.rs b/crates/curves/src/weierstrass/mod.rs index 871fdc9b67..ef4e702b11 100644 --- a/crates/curves/src/weierstrass/mod.rs +++ b/crates/curves/src/weierstrass/mod.rs @@ -15,6 +15,7 @@ use crate::utils::{biguint_to_rug, rug_to_biguint}; pub mod bls12_381; pub mod bn254; pub mod secp256k1; +pub mod secp256r1; /// Parameters that specify a short Weierstrass curve : y^2 = x^3 + ax + b. pub trait WeierstrassParameters: EllipticCurveParameters { diff --git a/crates/curves/src/weierstrass/secp256r1.rs b/crates/curves/src/weierstrass/secp256r1.rs new file mode 100644 index 0000000000..fa78b5fd5c --- /dev/null +++ b/crates/curves/src/weierstrass/secp256r1.rs @@ -0,0 +1,147 @@ +//! Modulo defining the Secp256r1 curve and its base field. The constants are all taken from +//! https://neuromancer.sk/std/secg/secp256r1 + +use std::str::FromStr; + +use elliptic_curve::{sec1::ToEncodedPoint, subtle::Choice}; +use generic_array::GenericArray; +use num::{ + traits::{FromBytes, ToBytes}, + BigUint, +}; +use p256::{elliptic_curve::point::DecompressPoint, FieldElement}; +use serde::{Deserialize, Serialize}; +use typenum::{U32, U62}; + +use super::{SwCurve, WeierstrassParameters}; +use crate::{ + params::{FieldParameters, NumLimbs}, + AffinePoint, CurveType, EllipticCurve, EllipticCurveParameters, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +/// Secp256r1 curve parameter +pub struct Secp256r1Parameters; + +pub type Secp256r1 = SwCurve; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)] +/// Secp256r1 base field parameter +pub struct Secp256r1BaseField; + +impl FieldParameters for Secp256r1BaseField { + const MODULUS: &'static [u8] = &[ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, + ]; + /// A rough witness-offset estimate given the size of the limbs and the size of the field. + const WITNESS_OFFSET: usize = 1usize << 14; + + fn modulus() -> BigUint { + BigUint::from_bytes_le(Self::MODULUS) + } +} + +impl NumLimbs for Secp256r1BaseField { + type Limbs = U32; + type Witness = U62; +} + +impl EllipticCurveParameters for Secp256r1Parameters { + type BaseField = Secp256r1BaseField; + const CURVE_TYPE: CurveType = CurveType::Secp256r1; +} + +impl WeierstrassParameters for Secp256r1Parameters { + const A: GenericArray = GenericArray::from_array([ + 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 255, 255, 255, 255, + ]); + + const B: GenericArray = GenericArray::from_array([ + 75, 96, 210, 39, 62, 60, 206, 59, 246, 176, 83, 204, 176, 6, 29, 101, 188, 134, 152, 118, + 85, 189, 235, 179, 231, 147, 58, 170, 216, 53, 198, 90, + ]); + + fn generator() -> (BigUint, BigUint) { + let x = BigUint::from_str( + "48439561293906451759052585252797914202762949526041747995844080717082404635286", + ) + .unwrap(); + let y = BigUint::from_str( + "36134250956749795798585127919587881956611106672985015071877198253568414405109", + ) + .unwrap(); + (x, y) + } + + fn prime_group_order() -> num::BigUint { + BigUint::from_slice(&[ + 0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0xFFFFFFFF, + ]) + } + + fn a_int() -> BigUint { + BigUint::from_slice(&[ + 0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0xFFFFFFFF, + ]) + } + + fn b_int() -> BigUint { + BigUint::from_slice(&[ + 0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, + 0x5AC635D8, + ]) + } +} + +pub fn secp256r1_decompress(bytes_be: &[u8], sign: u32) -> AffinePoint { + let computed_point = + p256::AffinePoint::decompress(bytes_be.into(), Choice::from(sign as u8)).unwrap(); + let point = computed_point.to_encoded_point(false); + + let x = BigUint::from_bytes_be(point.x().unwrap()); + let y = BigUint::from_bytes_be(point.y().unwrap()); + AffinePoint::::new(x, y) +} + +pub fn secp256r1_sqrt(n: &BigUint) -> BigUint { + let be_bytes = n.to_be_bytes(); + let mut bytes = [0_u8; 32]; + bytes[32 - be_bytes.len()..].copy_from_slice(&be_bytes); + let fe = FieldElement::from_bytes(&bytes.into()).unwrap(); + let result_bytes = fe.sqrt().unwrap().to_bytes(); + BigUint::from_be_bytes(&result_bytes as &[u8]) +} + +#[cfg(test)] +mod tests { + + use super::*; + use crate::utils::biguint_from_limbs; + use num::bigint::RandBigInt; + use rand::thread_rng; + + #[test] + fn test_weierstrass_biguint_scalar_mul() { + assert_eq!(biguint_from_limbs(Secp256r1BaseField::MODULUS), Secp256r1BaseField::modulus()); + } + + #[test] + fn test_secp256r_sqrt() { + let mut rng = thread_rng(); + for _ in 0..10 { + // Check that sqrt(x^2)^2 == x^2 + // We use x^2 since not all field elements have a square root + let x = rng.gen_biguint(256) % Secp256r1BaseField::modulus(); + let x_2 = (&x * &x) % Secp256r1BaseField::modulus(); // x^2 + let sqrt = secp256r1_sqrt(&x_2); //sqrt(x^2) = x + let sqrt_2 = (&sqrt * &sqrt) % Secp256r1BaseField::modulus(); + + assert_eq!(sqrt_2, x_2); + } + } +} diff --git a/crates/sdk/src/proof.rs b/crates/sdk/src/proof.rs index 86bd723e50..222e69f135 100644 --- a/crates/sdk/src/proof.rs +++ b/crates/sdk/src/proof.rs @@ -53,27 +53,9 @@ impl SP1ProofWithPublicValues { } } - /// Returns the *raw* proof as bytes, prepended with the first 4 bytes of the vkey hash. - /// - /// This is the format expected by the `sp1-verifier` crate. The extra 4 bytes are used to - /// ensure that the proof will eventually be verified by the correct vkey. - pub fn raw_with_checksum(&self) -> Vec { - match &self.proof { - SP1Proof::Plonk(plonk) => { - let proof_bytes = hex::decode(&plonk.raw_proof).expect("Invalid Plonk proof"); - [plonk.plonk_vkey_hash[..4].to_vec(), proof_bytes].concat() - } - SP1Proof::Groth16(groth16) => { - let proof_bytes = hex::decode(&groth16.raw_proof).expect("Invalid Groth16 proof"); - [groth16.groth16_vkey_hash[..4].to_vec(), proof_bytes].concat() - } - _ => unimplemented!(), - } - } - /// For Plonk or Groth16 proofs, returns the proof in a byte encoding the onchain verifier /// accepts. The bytes consist of the first four bytes of Plonk vkey hash followed by the - /// *encoded* proof. + /// encoded proof, in a form optimized for onchain verification. pub fn bytes(&self) -> Vec { match &self.proof { SP1Proof::Plonk(plonk_proof) => { diff --git a/crates/verifier/Cargo.toml b/crates/verifier/Cargo.toml index 321fa3c905..63690ec55a 100644 --- a/crates/verifier/Cargo.toml +++ b/crates/verifier/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sp1-verifier" description = "Verifier for SP1 Groth16 and Plonk proofs." -readme = "../../README.md" +readme = "README.md" version = { workspace = true } edition = { workspace = true } license = { workspace = true } @@ -10,7 +10,7 @@ keywords = { workspace = true } categories = { workspace = true } [dependencies] -bn = { git = "https://github.com/sp1-patches/bn", tag = "substrate_bn-v0.6.0-patch-v2", package = "substrate-bn" } +bn = { version = "0.6.0", package = "substrate-bn-succinct" } sha2 = { version = "0.10.8", default-features = false } thiserror-no-std = "2.0.2" hex = { version = "0.4.3", default-features = false, features = ["alloc"] } @@ -23,4 +23,4 @@ num-traits = "0.2.19" [features] default = ["std"] -std = [] +std = ["thiserror-no-std/std"] diff --git a/crates/verifier/src/error.rs b/crates/verifier/src/error.rs index 0facb98902..2d37bceac9 100644 --- a/crates/verifier/src/error.rs +++ b/crates/verifier/src/error.rs @@ -3,51 +3,19 @@ use thiserror_no_std::Error; #[derive(Error, Debug)] pub enum Error { - // Cryptographic Errors - #[error("BSB22 Commitment number mismatch")] - Bsb22CommitmentMismatch, - #[error("Challenge already computed")] - ChallengeAlreadyComputed, - #[error("Challenge not found")] - ChallengeNotFound, - #[error("Previous challenge not computed")] - PreviousChallengeNotComputed, - #[error("Pairing check failed")] - PairingCheckFailed, - #[error("Invalid point in subgroup check")] - InvalidPoint, - - // Arithmetic Errors - #[error("Beyond the modulus")] - BeyondTheModulus, - #[error("Ell too large")] - EllTooLarge, - #[error("Inverse not found")] - InverseNotFound, - #[error("Opening linear polynomial mismatch")] - OpeningPolyMismatch, - // Input Errors - #[error("DST too large")] - DSTTooLarge, - #[error("Invalid number of digests")] - InvalidNumberOfDigests, #[error("Invalid witness")] InvalidWitness, #[error("Invalid x length")] InvalidXLength, - #[error("Unexpected flag")] - UnexpectedFlag, #[error("Invalid data")] InvalidData, + #[error("Invalid point in subgroup check")] + InvalidPoint, // Conversion Errors #[error("Failed to get Fr from random bytes")] FailedToGetFrFromRandomBytes, - #[error("Failed to get x")] - FailedToGetX, - #[error("Failed to get y")] - FailedToGetY, // External Library Errors #[error("BN254 Field Error")] diff --git a/crates/verifier/src/groth16/error.rs b/crates/verifier/src/groth16/error.rs index bc88da868c..36952cb749 100644 --- a/crates/verifier/src/groth16/error.rs +++ b/crates/verifier/src/groth16/error.rs @@ -8,8 +8,6 @@ pub enum Groth16Error { ProcessVerifyingKeyFailed, #[error("Prepare inputs failed")] PrepareInputsFailed, - #[error("Unexpected identity")] - UnexpectedIdentity, #[error("General error")] GeneralError(#[from] crate::error::Error), #[error("Groth16 vkey hash mismatch")] diff --git a/crates/verifier/src/groth16/mod.rs b/crates/verifier/src/groth16/mod.rs index 123d71e4f6..c6cf98a23a 100644 --- a/crates/verifier/src/groth16/mod.rs +++ b/crates/verifier/src/groth16/mod.rs @@ -1,5 +1,5 @@ mod converter; -pub(crate) mod error; +pub mod error; mod verify; pub(crate) use converter::{load_groth16_proof_from_bytes, load_groth16_verifying_key_from_bytes}; @@ -8,7 +8,7 @@ pub(crate) use verify::*; use error::Groth16Error; -use crate::{bn254_public_values, decode_sp1_vkey_hash}; +use crate::{bn254_public_values, decode_sp1_vkey_hash, error::Error}; /// A verifier for Groth16 zero-knowledge proofs. #[derive(Debug)] @@ -30,21 +30,22 @@ impl Groth16Verifier { /// let sp1_vkey_hash = vk.bytes32(); /// ``` /// * `groth16_vk` - The Groth16 verifying key bytes. - /// Usually this will be the [`crate::GROTH16_VK_BYTES`] constant, which is the Groth16 + /// Usually this will be the [`static@crate::GROTH16_VK_BYTES`] constant, which is the Groth16 /// verifying key for the current SP1 version. /// /// # Returns /// - /// A [`Result`] containing a boolean indicating whether the proof is valid, - /// or a [`Groth16Error`] if verification fails. + /// A success [`Result`] if verification succeeds, or a [`Groth16Error`] if verification fails. pub fn verify( proof: &[u8], sp1_public_inputs: &[u8], sp1_vkey_hash: &str, groth16_vk: &[u8], - ) -> Result { + ) -> Result<(), Groth16Error> { // Hash the vk and get the first 4 bytes. - let groth16_vk_hash: [u8; 4] = Sha256::digest(groth16_vk)[..4].try_into().unwrap(); + let groth16_vk_hash: [u8; 4] = Sha256::digest(groth16_vk)[..4] + .try_into() + .map_err(|_| Groth16Error::GeneralError(Error::InvalidData))?; // Check to make sure that this proof was generated by the groth16 proving key corresponding to // the given groth16_vk. @@ -58,8 +59,8 @@ impl Groth16Verifier { let sp1_vkey_hash = decode_sp1_vkey_hash(sp1_vkey_hash)?; let public_inputs = bn254_public_values(&sp1_vkey_hash, sp1_public_inputs); - let proof = load_groth16_proof_from_bytes(&proof[4..]).unwrap(); - let groth16_vk = load_groth16_verifying_key_from_bytes(groth16_vk).unwrap(); + let proof = load_groth16_proof_from_bytes(&proof[4..])?; + let groth16_vk = load_groth16_verifying_key_from_bytes(groth16_vk)?; verify_groth16_raw(&groth16_vk, &proof, &public_inputs) } diff --git a/crates/verifier/src/groth16/verify.rs b/crates/verifier/src/groth16/verify.rs index 510815b971..686e62ff61 100644 --- a/crates/verifier/src/groth16/verify.rs +++ b/crates/verifier/src/groth16/verify.rs @@ -54,13 +54,18 @@ pub(crate) fn verify_groth16_raw( vk: &Groth16VerifyingKey, proof: &Groth16Proof, public_inputs: &[Fr], -) -> Result { +) -> Result<(), Groth16Error> { let prepared_inputs = prepare_inputs(vk.clone(), public_inputs)?; - Ok(pairing_batch(&[ + if pairing_batch(&[ (-Into::::into(proof.ar), proof.bs.into()), (prepared_inputs, vk.g2.gamma.into()), (proof.krs.into(), vk.g2.delta.into()), (vk.g1.alpha.into(), -Into::::into(vk.g2.beta)), - ]) == Gt::one()) + ]) == Gt::one() + { + Ok(()) + } else { + Err(Groth16Error::ProofVerificationFailed) + } } diff --git a/crates/verifier/src/lib.rs b/crates/verifier/src/lib.rs index 6abbd051e2..228d60624f 100644 --- a/crates/verifier/src/lib.rs +++ b/crates/verifier/src/lib.rs @@ -19,14 +19,17 @@ lazy_static! { mod constants; mod converter; mod error; -mod groth16; + mod utils; +pub use utils::*; +pub use groth16::error::Groth16Error; pub use groth16::Groth16Verifier; -pub use utils::*; +mod groth16; -mod plonk; +pub use plonk::error::PlonkError; pub use plonk::PlonkVerifier; +mod plonk; #[cfg(test)] mod tests; diff --git a/crates/verifier/src/plonk/converter.rs b/crates/verifier/src/plonk/converter.rs index 16bd387218..df94303d77 100644 --- a/crates/verifier/src/plonk/converter.rs +++ b/crates/verifier/src/plonk/converter.rs @@ -112,41 +112,46 @@ pub(crate) fn load_plonk_verifying_key_from_bytes( Ok(result) } -pub(crate) fn load_plonk_proof_from_bytes(buffer: &[u8]) -> Result { +/// See https://github.com/jtguibas/gnark/blob/26e3df73fc223292be8b7fc0b7451caa4059a649/backend/plonk/bn254/solidity.go +/// for how the proof is serialized. +pub(crate) fn load_plonk_proof_from_bytes( + buffer: &[u8], + num_bsb22_commitments: usize, +) -> Result { let lro0 = uncompressed_bytes_to_g1_point(&buffer[..64])?; let lro1 = uncompressed_bytes_to_g1_point(&buffer[64..128])?; let lro2 = uncompressed_bytes_to_g1_point(&buffer[128..192])?; - let z = uncompressed_bytes_to_g1_point(&buffer[192..256])?; - let h0 = uncompressed_bytes_to_g1_point(&buffer[256..320])?; - let h1 = uncompressed_bytes_to_g1_point(&buffer[320..384])?; - let h2 = uncompressed_bytes_to_g1_point(&buffer[384..448])?; - let batched_proof_h = uncompressed_bytes_to_g1_point(&buffer[448..512])?; - - let num_claimed_values = - u32::from_be_bytes([buffer[512], buffer[513], buffer[514], buffer[515]]) as usize; - - let mut claimed_values = Vec::new(); - let mut offset = 516; - for _ in 0..num_claimed_values { + let h0 = uncompressed_bytes_to_g1_point(&buffer[192..256])?; + let h1 = uncompressed_bytes_to_g1_point(&buffer[256..320])?; + let h2 = uncompressed_bytes_to_g1_point(&buffer[320..384])?; + + // Stores l_at_zeta, r_at_zeta, o_at_zeta, s 1_at_zeta, s2_at_zeta, bsb22_commitments + let mut claimed_values = Vec::with_capacity(5 + num_bsb22_commitments); + let mut offset = 384; + for _ in 1..6 { let value = Fr::from_slice(&buffer[offset..offset + 32]) .map_err(|e| PlonkError::GeneralError(Error::Field(e)))?; claimed_values.push(value); offset += 32; } - let z_shifted_opening_h = uncompressed_bytes_to_g1_point(&buffer[offset..offset + 64])?; + let z = uncompressed_bytes_to_g1_point(&buffer[offset..offset + 64])?; let z_shifted_opening_value = Fr::from_slice(&buffer[offset + 64..offset + 96]) .map_err(|e| PlonkError::GeneralError(Error::Field(e)))?; + offset += 96; - let num_bsb22_commitments = u32::from_be_bytes([ - buffer[offset + 96], - buffer[offset + 97], - buffer[offset + 98], - buffer[offset + 99], - ]) as usize; + let batched_proof_h = uncompressed_bytes_to_g1_point(&buffer[offset..offset + 64])?; + let z_shifted_opening_h = uncompressed_bytes_to_g1_point(&buffer[offset + 64..offset + 128])?; + offset += 128; + + for _ in 0..num_bsb22_commitments { + let commitment = Fr::from_slice(&buffer[offset..offset + 32]) + .map_err(|e| PlonkError::GeneralError(Error::Field(e)))?; + claimed_values.push(commitment); + offset += 32; + } - let mut bsb22_commitments = Vec::new(); - offset += 100; + let mut bsb22_commitments = Vec::with_capacity(num_bsb22_commitments); for _ in 0..num_bsb22_commitments { let commitment = uncompressed_bytes_to_g1_point(&buffer[offset..offset + 64])?; bsb22_commitments.push(commitment); diff --git a/crates/verifier/src/plonk/error.rs b/crates/verifier/src/plonk/error.rs index cc166638dd..1d33e503d6 100644 --- a/crates/verifier/src/plonk/error.rs +++ b/crates/verifier/src/plonk/error.rs @@ -14,34 +14,18 @@ pub enum PlonkError { DSTTooLarge, #[error("Ell too large")] EllTooLarge, - #[error("Failed to get Fr from random bytes")] - FailedToGetFrFromRandomBytes, - #[error("Failed to get x")] - FailedToGetX, - #[error("Failed to get y")] - FailedToGetY, #[error("Inverse not found")] InverseNotFound, #[error("Invalid number of digests")] InvalidNumberOfDigests, - #[error("Invalid point in subgroup check")] - InvalidPoint, #[error("Invalid witness")] InvalidWitness, - #[error("Invalid x length")] - InvalidXLength, - #[error("Opening linear polynomial mismatch")] - OpeningPolyMismatch, #[error("Pairing check failed")] PairingCheckFailed, #[error("Previous challenge not computed")] PreviousChallengeNotComputed, - #[error("Unexpected flag")] - UnexpectedFlag, #[error("Transcript error")] TranscriptError, - #[error("Hash to field initialization failed")] - HashToFieldInitializationFailed, #[error("Plonk vkey hash mismatch")] PlonkVkeyHashMismatch, #[error("General error")] diff --git a/crates/verifier/src/plonk/hash_to_field.rs b/crates/verifier/src/plonk/hash_to_field.rs index d473abc4fe..fb077019b1 100644 --- a/crates/verifier/src/plonk/hash_to_field.rs +++ b/crates/verifier/src/plonk/hash_to_field.rs @@ -3,7 +3,7 @@ use alloc::vec::Vec; use core::hash::Hasher; use sha2::Digest; -use crate::error::Error; +use crate::PlonkError; pub(crate) struct WrappedHashToField { domain: Vec, @@ -12,18 +12,22 @@ pub(crate) struct WrappedHashToField { impl WrappedHashToField { // Creates a new instance with a domain separator - pub(crate) fn new(domain_separator: &[u8]) -> Result { + pub(crate) fn new(domain_separator: &[u8]) -> Result { Ok(Self { domain: domain_separator.to_vec(), to_hash: Vec::new() }) } // Hashes the bytes to a field element and returns the byte representation - pub(crate) fn sum(&self) -> Result, Error> { + pub(crate) fn sum(&self) -> Result, PlonkError> { let res = Self::hash(self.to_hash.clone(), self.domain.clone(), 1)?; Ok(res[0].clone()) } - pub(crate) fn hash(msg: Vec, dst: Vec, count: usize) -> Result>, Error> { + pub(crate) fn hash( + msg: Vec, + dst: Vec, + count: usize, + ) -> Result>, PlonkError> { let bytes = 32; let l = 16 + bytes; @@ -38,16 +42,16 @@ impl WrappedHashToField { Ok(res) } - fn expand_msg_xmd(msg: Vec, dst: Vec, len: usize) -> Result, Error> { + fn expand_msg_xmd(msg: Vec, dst: Vec, len: usize) -> Result, PlonkError> { let mut h = sha2::Sha256::new(); let ell = (len + 32 - 1) / 32; if ell > 255 { - Err(Error::EllTooLarge)?; + Err(PlonkError::EllTooLarge)?; } if dst.len() > 255 { - Err(Error::DSTTooLarge)?; + Err(PlonkError::DSTTooLarge)?; } let size_domain = dst.len(); diff --git a/crates/verifier/src/plonk/kzg.rs b/crates/verifier/src/plonk/kzg.rs index 549e048f9c..03098162ac 100644 --- a/crates/verifier/src/plonk/kzg.rs +++ b/crates/verifier/src/plonk/kzg.rs @@ -97,7 +97,7 @@ pub(crate) fn fold_proof( let nb_digests = digests.len(); if nb_digests != batch_opening_proof.claimed_values.len() { - return Err(Error::InvalidNumberOfDigests.into()); + return Err(PlonkError::InvalidNumberOfDigests); } let gamma = derive_gamma( @@ -141,15 +141,15 @@ pub(crate) fn batch_verify_multi_points( let nb_points = points.len(); if nb_digests != nb_proofs { - return Err(Error::InvalidNumberOfDigests.into()); + return Err(PlonkError::InvalidNumberOfDigests); } if nb_digests != nb_points { - return Err(Error::InvalidNumberOfDigests.into()); + return Err(PlonkError::InvalidNumberOfDigests); } if nb_digests == 1 { - todo!(); + unimplemented!(); } let mut random_numbers = Vec::with_capacity(nb_digests); @@ -186,7 +186,7 @@ pub(crate) fn batch_verify_multi_points( pairing_batch(&[(folded_digests.into(), vk.g2[0]), (folded_quotients.into(), vk.g2[1])]); if !pairing_result.is_one() { - return Err(Error::PairingCheckFailed.into()); + return Err(PlonkError::PairingCheckFailed); } Ok(()) diff --git a/crates/verifier/src/plonk/mod.rs b/crates/verifier/src/plonk/mod.rs index 4ee223b71e..0456704f3e 100644 --- a/crates/verifier/src/plonk/mod.rs +++ b/crates/verifier/src/plonk/mod.rs @@ -20,7 +20,7 @@ pub(crate) use verify::verify_plonk_raw; use error::PlonkError; use sha2::{Digest, Sha256}; -use crate::{bn254_public_values, decode_sp1_vkey_hash}; +use crate::{bn254_public_values, decode_sp1_vkey_hash, error::Error}; /// A verifier for Plonk zero-knowledge proofs. #[derive(Debug)] pub struct PlonkVerifier; @@ -40,20 +40,21 @@ impl PlonkVerifier { /// let sp1_vkey_hash = vk.bytes32(); /// ``` /// * `plonk_vk` - The Plonk verifying key bytes. - /// Usually this will be the [`crate::PLONK_VK_BYTES`] constant. + /// Usually this will be the [`static@crate::PLONK_VK_BYTES`] constant. /// /// # Returns /// - /// A `Result` containing a boolean indicating whether the proof is valid, - /// or a [`PlonkError`] if verification fails. + /// A success [`Result`] if verification succeeds, or a [`PlonkError`] if verification fails. pub fn verify( proof: &[u8], sp1_public_inputs: &[u8], sp1_vkey_hash: &str, plonk_vk: &[u8], - ) -> Result { + ) -> Result<(), PlonkError> { // Hash the vk and get the first 4 bytes. - let plonk_vk_hash: [u8; 4] = Sha256::digest(plonk_vk)[..4].try_into().unwrap(); + let plonk_vk_hash: [u8; 4] = Sha256::digest(plonk_vk)[..4] + .try_into() + .map_err(|_| PlonkError::GeneralError(Error::InvalidData))?; // Check to make sure that this proof was generated by the plonk proving key corresponding to // the given plonk vk. @@ -67,8 +68,8 @@ impl PlonkVerifier { let sp1_vkey_hash = decode_sp1_vkey_hash(sp1_vkey_hash)?; let public_inputs = bn254_public_values(&sp1_vkey_hash, sp1_public_inputs); - let proof = load_plonk_proof_from_bytes(&proof[4..]).unwrap(); - let plonk_vk = load_plonk_verifying_key_from_bytes(plonk_vk).unwrap(); + let plonk_vk = load_plonk_verifying_key_from_bytes(plonk_vk)?; + let proof = load_plonk_proof_from_bytes(&proof[4..], plonk_vk.qcp.len())?; verify_plonk_raw(&plonk_vk, &proof, &public_inputs) } diff --git a/crates/verifier/src/plonk/transcript.rs b/crates/verifier/src/plonk/transcript.rs index 5d1c2db8db..55dbd99dcb 100644 --- a/crates/verifier/src/plonk/transcript.rs +++ b/crates/verifier/src/plonk/transcript.rs @@ -1,7 +1,7 @@ use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec}; use sha2::{Digest, Sha256}; -use crate::error::Error; +use crate::PlonkError; /// A challenge in the transcript, derived with randomness from `bindings` and the previous /// challenge. @@ -24,7 +24,7 @@ pub(crate) struct Transcript { impl Transcript { /// Creates a new transcript. - pub(crate) fn new(challenges_id: Option>) -> Result { + pub(crate) fn new(challenges_id: Option>) -> Result { let h = Sha256::new(); if let Some(challenges_id) = challenges_id { @@ -48,10 +48,10 @@ impl Transcript { } /// Binds some data to a challenge. - pub(crate) fn bind(&mut self, id: &str, binding: &[u8]) -> Result<(), Error> { - let current_challenge = self.challenges.get_mut(id).ok_or(Error::ChallengeNotFound)?; + pub(crate) fn bind(&mut self, id: &str, binding: &[u8]) -> Result<(), PlonkError> { + let current_challenge = self.challenges.get_mut(id).ok_or(PlonkError::ChallengeNotFound)?; if current_challenge.is_computed { - return Err(Error::ChallengeAlreadyComputed); + return Err(PlonkError::ChallengeAlreadyComputed); } current_challenge.bindings.push(binding.to_vec()); @@ -63,8 +63,9 @@ impl Transcript { /// /// Challenges must be computed in order. The previous challenge is automatically fed into the /// challenge currently being computed. - pub(crate) fn compute_challenge(&mut self, challenge_id: &str) -> Result, Error> { - let challenge = self.challenges.get_mut(challenge_id).ok_or(Error::ChallengeNotFound)?; + pub(crate) fn compute_challenge(&mut self, challenge_id: &str) -> Result, PlonkError> { + let challenge = + self.challenges.get_mut(challenge_id).ok_or(PlonkError::ChallengeNotFound)?; if challenge.is_computed { return Ok(challenge.value.clone()); @@ -78,11 +79,11 @@ impl Transcript { if challenge.position != 0 { if let Some(previous_challenge) = &self.previous_challenge { if previous_challenge.position != challenge.position - 1 { - return Err(Error::PreviousChallengeNotComputed); + return Err(PlonkError::PreviousChallengeNotComputed); } self.h.update(&previous_challenge.value) } else { - return Err(Error::PreviousChallengeNotComputed); + return Err(PlonkError::PreviousChallengeNotComputed); } } diff --git a/crates/verifier/src/plonk/verify.rs b/crates/verifier/src/plonk/verify.rs index d00f35094b..4cfbcc884f 100644 --- a/crates/verifier/src/plonk/verify.rs +++ b/crates/verifier/src/plonk/verify.rs @@ -2,7 +2,10 @@ use alloc::{string::ToString, vec, vec::Vec}; use bn::{arith::U256, AffineG1, Fr}; use core::hash::Hasher; -use crate::{error::Error, plonk::transcript::Transcript}; +use crate::{ + error::Error, + plonk::{kzg::BatchOpeningProof, transcript::Transcript}, +}; use super::{ converter::g1_to_bytes, error::PlonkError, kzg, PlonkProof, ALPHA, BETA, GAMMA, U, ZETA, @@ -45,15 +48,15 @@ pub(crate) fn verify_plonk_raw( vk: &PlonkVerifyingKey, proof: &PlonkProof, public_inputs: &[Fr], -) -> Result { +) -> Result<(), PlonkError> { // Check if the number of BSB22 commitments matches the number of Qcp in the verifying key if proof.bsb22_commitments.len() != vk.qcp.len() { - return Err(PlonkError::GeneralError(Error::Bsb22CommitmentMismatch)); + return Err(PlonkError::Bsb22CommitmentMismatch); } // Check if the number of public inputs matches the number of public variables in the verifying key if public_inputs.len() != vk.nb_public_variables { - return Err(PlonkError::GeneralError(Error::InvalidWitness)); + return Err(PlonkError::InvalidWitness); } // Initialize the Fiat-Shamir transcript @@ -93,7 +96,7 @@ pub(crate) fn verify_plonk_raw( let zh_zeta = zeta_power_n - one; // Compute Lagrange polynomial at ζ: L₁(ζ) = (ζⁿ - 1) / (n * (ζ - 1)) - let mut lagrange_one = (zeta - one).inverse().ok_or(Error::InverseNotFound)?; + let mut lagrange_one = (zeta - one).inverse().ok_or(PlonkError::InverseNotFound)?; lagrange_one *= zh_zeta; lagrange_one *= vk.size_inv; @@ -138,7 +141,7 @@ pub(crate) fn verify_plonk_raw( let exponent = U256::from((vk.nb_public_variables + vk.commitment_constraint_indexes[i]) as u64); - let exponent = Fr::new(exponent).ok_or(Error::BeyondTheModulus)?; + let exponent = Fr::new(exponent).ok_or(PlonkError::BeyondTheModulus)?; let w_pow_i = vk.generator.pow(exponent); let mut den = zeta; den -= w_pow_i; @@ -153,11 +156,11 @@ pub(crate) fn verify_plonk_raw( } // Extract claimed values from the proof - let l = proof.batched_proof.claimed_values[1]; - let r = proof.batched_proof.claimed_values[2]; - let o = proof.batched_proof.claimed_values[3]; - let s1 = proof.batched_proof.claimed_values[4]; - let s2 = proof.batched_proof.claimed_values[5]; + let l = proof.batched_proof.claimed_values[0]; + let r = proof.batched_proof.claimed_values[1]; + let o = proof.batched_proof.claimed_values[2]; + let s1 = proof.batched_proof.claimed_values[3]; + let s2 = proof.batched_proof.claimed_values[4]; let zu = proof.z_shifted_opening.claimed_value; @@ -171,6 +174,7 @@ pub(crate) fn verify_plonk_raw( // Compute the constant term of the linearization polynomial: // -[PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ)] + let mut tmp = beta; tmp *= s1; tmp += gamma; @@ -196,13 +200,6 @@ pub(crate) fn verify_plonk_raw( const_lin = -const_lin; - // Check if the opening of the linearized polynomial is equal to -const_lin - let opening_lin_pol = proof.batched_proof.claimed_values[0]; - - if const_lin != opening_lin_pol { - return Err(Error::OpeningPolyMismatch.into()); - } - // Compute coefficients for the linearized polynomial // _s1 = α*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*β*Z(ωζ) let mut _s1 = beta * s1 + l + gamma; @@ -253,7 +250,7 @@ pub(crate) fn verify_plonk_raw( points.push(proof.h[1]); points.push(proof.h[2]); - let qc = proof.batched_proof.claimed_values[6..].to_vec(); + let qc = proof.batched_proof.claimed_values[5..].to_vec(); let mut scalars = Vec::new(); scalars.extend_from_slice(&qc); @@ -283,11 +280,15 @@ pub(crate) fn verify_plonk_raw( digests_to_fold[4] = vk.s[0]; digests_to_fold[5] = vk.s[1]; + // Prepend the constant term of the linearization polynomial to the claimed values. + let claimed_values = [vec![const_lin], proof.batched_proof.claimed_values.clone()].concat(); + let batch_opening_proof = BatchOpeningProof { h: proof.batched_proof.h, claimed_values }; + // Fold the proof // Internally derives V, and binds it to the transcript to challenge U. let (folded_proof, folded_digest) = kzg::fold_proof( digests_to_fold, - &proof.batched_proof, + &batch_opening_proof, &zeta, Some(zu.into_u256().to_bytes_be().to_vec()), &mut fs, @@ -313,7 +314,7 @@ pub(crate) fn verify_plonk_raw( &vk.kzg, )?; - Ok(true) + Ok(()) } /// Binds all plonk public data to the transcript. diff --git a/crates/verifier/src/tests.rs b/crates/verifier/src/tests.rs index 7048c3c8e8..e99d71ebd9 100644 --- a/crates/verifier/src/tests.rs +++ b/crates/verifier/src/tests.rs @@ -16,13 +16,8 @@ fn test_verify_groth16() { // This vkey hash was derived by calling `vk.bytes32()` on the verifying key. let vkey_hash = "0x00e60860c07bfc6e4c480286c0ddbb879674eb47f84b4ef041cf858b17aa0ed1"; - let is_valid = - crate::Groth16Verifier::verify(&proof, &public_inputs, vkey_hash, &crate::GROTH16_VK_BYTES) - .expect("Groth16 proof is invalid"); - - if !is_valid { - panic!("Groth16 proof is invalid"); - } + crate::Groth16Verifier::verify(&proof, &public_inputs, vkey_hash, &crate::GROTH16_VK_BYTES) + .expect("Groth16 proof is invalid"); } #[test] @@ -33,19 +28,14 @@ fn test_verify_plonk() { // Load the saved proof and extract the proof and public inputs. let sp1_proof_with_public_values = SP1ProofWithPublicValues::load(proof_file).unwrap(); - let proof = sp1_proof_with_public_values.raw_with_checksum(); + let proof = sp1_proof_with_public_values.bytes(); let public_inputs = sp1_proof_with_public_values.public_values.to_vec(); // This vkey hash was derived by calling `vk.bytes32()` on the verifying key. let vkey_hash = "0x00e60860c07bfc6e4c480286c0ddbb879674eb47f84b4ef041cf858b17aa0ed1"; - let is_valid = - crate::PlonkVerifier::verify(&proof, &public_inputs, vkey_hash, &crate::PLONK_VK_BYTES) - .expect("Plonk proof is invalid"); - - if !is_valid { - panic!("Plonk proof is invalid"); - } + crate::PlonkVerifier::verify(&proof, &public_inputs, vkey_hash, &crate::PLONK_VK_BYTES) + .expect("Plonk proof is invalid"); } #[test] diff --git a/crates/zkvm/entrypoint/src/syscalls/mod.rs b/crates/zkvm/entrypoint/src/syscalls/mod.rs index e40728d7ed..a25434370e 100644 --- a/crates/zkvm/entrypoint/src/syscalls/mod.rs +++ b/crates/zkvm/entrypoint/src/syscalls/mod.rs @@ -8,6 +8,7 @@ mod io; mod keccak_permute; mod memory; mod secp256k1; +mod secp256r1; mod sha_compress; mod sha_extend; mod sys; @@ -26,6 +27,7 @@ pub use io::*; pub use keccak_permute::*; pub use memory::*; pub use secp256k1::*; +pub use secp256r1::*; pub use sha_compress::*; pub use sha_extend::*; pub use sys::*; @@ -73,6 +75,15 @@ pub const SECP256K1_DOUBLE: u32 = 0x00_00_01_0B; /// Executes `K256_DECOMPRESS`. pub const SECP256K1_DECOMPRESS: u32 = 0x00_00_01_0C; +/// Executes `SECP256R1_ADD`. +pub const SECP256R1_ADD: u32 = 0x00_01_01_2C; + +/// Executes `SECP256R1_DOUBLE`. +pub const SECP256R1_DOUBLE: u32 = 0x00_00_01_2D; + +/// Executes `SECP256R1_DECOMPRESS`. +pub const SECP256R1_DECOMPRESS: u32 = 0x00_00_01_2E; + /// Executes `BN254_ADD`. pub const BN254_ADD: u32 = 0x00_01_01_0E; diff --git a/crates/zkvm/entrypoint/src/syscalls/secp256r1.rs b/crates/zkvm/entrypoint/src/syscalls/secp256r1.rs new file mode 100644 index 0000000000..6e09b1a7fb --- /dev/null +++ b/crates/zkvm/entrypoint/src/syscalls/secp256r1.rs @@ -0,0 +1,86 @@ +#[cfg(target_os = "zkvm")] +use core::arch::asm; + +/// Adds two Secp256k1 points. +/// +/// The result is stored in the first point. +/// +/// ### Safety +/// +/// The caller must ensure that `p` and `q` are valid pointers to data that is aligned along a four +/// byte boundary. Additionally, the caller must ensure that `p` and `q` are valid points on the +/// secp256k1 curve, and that `p` and `q` are not equal to each other. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_secp256r1_add(p: *mut [u32; 16], q: *mut [u32; 16]) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::SECP256R1_ADD, + in("a0") p, + in("a1") q + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Double a Secp256k1 point. +/// +/// The result is stored in-place in the supplied buffer. +/// +/// ### Safety +/// +/// The caller must ensure that `p` is valid pointer to data that is aligned along a four byte +/// boundary. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_secp256r1_double(p: *mut [u32; 16]) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::SECP256R1_DOUBLE, + in("a0") p, + in("a1") 0 + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +/// Decompresses a compressed Secp256k1 point. +/// +/// The input array should be 64 bytes long, with the first 32 bytes containing the X coordinate in +/// big-endian format. The second half of the input will be overwritten with the Y coordinate of the +/// decompressed point in big-endian format using the point's parity (is_odd). +/// +/// ### Safety +/// +/// The caller must ensure that `point` is valid pointer to data that is aligned along a four byte +/// boundary. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_secp256r1_decompress(point: &mut [u8; 64], is_odd: bool) { + #[cfg(target_os = "zkvm")] + { + // Memory system/FpOps are little endian so we'll just flip the whole array before/after + point.reverse(); + let p = point.as_mut_ptr(); + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::SECP256R1_DECOMPRESS, + in("a0") p, + in("a1") is_odd as u8 + ); + } + point.reverse(); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} diff --git a/crates/zkvm/lib/src/io.rs b/crates/zkvm/lib/src/io.rs index 48faad5f14..94a92a602c 100644 --- a/crates/zkvm/lib/src/io.rs +++ b/crates/zkvm/lib/src/io.rs @@ -12,8 +12,9 @@ pub const FD_PUBLIC_VALUES: u32 = 3; /// The file descriptor for hints. pub const FD_HINT: u32 = 4; -/// The file descriptor for the `ecreover` hook. -pub const FD_ECRECOVER_HOOK: u32 = 5; +/// The file descriptor for the `ecrecover` hook. +pub const K1_ECRECOVER_HOOK: u32 = 5; +pub const R1_ECRECOVER_HOOK: u32 = 6; /// A writer that writes to a file descriptor inside the zkVM. struct SyscallWriter { diff --git a/crates/zkvm/lib/src/lib.rs b/crates/zkvm/lib/src/lib.rs index f849859a8b..ffa6bb64c6 100644 --- a/crates/zkvm/lib/src/lib.rs +++ b/crates/zkvm/lib/src/lib.rs @@ -8,6 +8,7 @@ pub mod bn254; pub mod ed25519; pub mod io; pub mod secp256k1; +pub mod secp256r1; pub mod unconstrained; pub mod utils; #[cfg(feature = "verify")] @@ -44,6 +45,15 @@ extern "C" { /// Executes an Secp256k1 curve decompression on the given point. pub fn syscall_secp256k1_decompress(point: &mut [u8; 64], is_odd: bool); + /// Executes an Secp256r1 curve addition on the given points. + pub fn syscall_secp256r1_add(p: *mut [u32; 16], q: *const [u32; 16]); + + /// Executes an Secp256r1 curve doubling on the given point. + pub fn syscall_secp256r1_double(p: *mut [u32; 16]); + + /// Executes an Secp256r1 curve decompression on the given point. + pub fn syscall_secp256r1_decompress(point: &mut [u8; 64], is_odd: bool); + /// Executes a Bn254 curve addition on the given points. pub fn syscall_bn254_add(p: *mut [u32; 16], q: *const [u32; 16]); diff --git a/crates/zkvm/lib/src/secp256r1.rs b/crates/zkvm/lib/src/secp256r1.rs new file mode 100644 index 0000000000..69565faf49 --- /dev/null +++ b/crates/zkvm/lib/src/secp256r1.rs @@ -0,0 +1,70 @@ +use crate::{ + syscall_secp256r1_add, syscall_secp256r1_double, + utils::{AffinePoint, WeierstrassAffinePoint, WeierstrassPoint}, +}; + +/// The number of limbs in [Secp256r1Point]. +pub const N: usize = 16; + +/// An affine point on the Secp256k1 curve. +#[derive(Copy, Clone)] +#[repr(align(4))] +pub struct Secp256r1Point(pub WeierstrassPoint); + +impl WeierstrassAffinePoint for Secp256r1Point { + fn infinity() -> Self { + Self(WeierstrassPoint::Infinity) + } + + fn is_infinity(&self) -> bool { + matches!(self.0, WeierstrassPoint::Infinity) + } +} + +impl AffinePoint for Secp256r1Point { + /// The values are taken from + const GENERATOR: [u32; N] = [ + 3633889942, 4104206661, 770388896, 1996717441, 1671708914, 4173129445, 3777774151, + 1796723186, 935285237, 3417718888, 1798397646, 734933847, 2081398294, 2397563722, + 4263149467, 1340293858, + ]; + + fn new(limbs: [u32; N]) -> Self { + Self(WeierstrassPoint::Affine(limbs)) + } + + fn limbs_ref(&self) -> &[u32; N] { + match &self.0 { + WeierstrassPoint::Infinity => panic!("Infinity point has no limbs"), + WeierstrassPoint::Affine(limbs) => limbs, + } + } + + fn limbs_mut(&mut self) -> &mut [u32; N] { + match &mut self.0 { + WeierstrassPoint::Infinity => panic!("Infinity point has no limbs"), + WeierstrassPoint::Affine(limbs) => limbs, + } + } + + fn complete_add_assign(&mut self, other: &Self) { + self.weierstrass_add_assign(other); + } + + fn add_assign(&mut self, other: &Self) { + let a = self.limbs_mut(); + let b = other.limbs_ref(); + unsafe { + syscall_secp256r1_add(a, b); + } + } + + fn double(&mut self) { + match &mut self.0 { + WeierstrassPoint::Infinity => (), + WeierstrassPoint::Affine(limbs) => unsafe { + syscall_secp256r1_double(limbs); + }, + } + } +} diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 663d53235f..9acc219708 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -74,11 +74,11 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836cf02383d9ebb35502d379bcd1ae803155094077eaab9c29131d888cd5fa3e" +checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "num_enum 0.7.3", "serde", @@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "629b62e38d471cc15fea534eb7283d2f8a4e8bdb1811bcc5d66dda6cfce6fae1" dependencies = [ "alloy-eips 0.3.6", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-serde 0.3.6", "c-kzg", @@ -106,7 +106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41ed961a48297c732a5d97ee321aa8bb5009ecadbcb077d8bec90cb54e651629" dependencies = [ "alloy-eips 0.5.4", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-serde 0.5.4", "auto_impl", @@ -121,7 +121,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "serde", ] @@ -132,7 +132,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "k256", "serde", @@ -144,7 +144,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ffc577390ce50234e02d841214b3dc0bea6aaaae8e04bbf3cb82e9a45da9eb" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "derive_more 1.0.0", "serde", @@ -158,7 +158,7 @@ checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" dependencies = [ "alloy-eip2930", "alloy-eip7702 0.1.1", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-serde 0.3.6", "c-kzg", @@ -176,7 +176,7 @@ checksum = "b69e06cf9c37be824b9d26d6d101114fdde6af0c87de2828b414c05c4b3daa71" dependencies = [ "alloy-eip2930", "alloy-eip7702 0.3.2", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-serde 0.5.4", "c-kzg", @@ -192,18 +192,18 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a7a18afb0b318616b6b2b0e2e7ac5529d32a966c673b48091c9919e284e6aca" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-serde 0.3.6", "serde", ] [[package]] name = "alloy-json-abi" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31a0f0d51db8a1a30a4d98a9f90e090a94c8f44cb4d9eafc7e03aa6d00aae984" +checksum = "ded610181f3dad5810f6ff12d1a99994cf9b42d2fcb7709029352398a5da5ae6" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-sol-type-parser", "serde", "serde_json", @@ -215,7 +215,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af5979e0d5a7bf9c7eb79749121e8256e59021af611322aee56e77e20776b4b3" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-sol-types", "serde", "serde_json", @@ -233,7 +233,7 @@ dependencies = [ "alloy-eips 0.5.4", "alloy-json-rpc", "alloy-network-primitives 0.5.4", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rpc-types-eth 0.5.4", "alloy-serde 0.5.4", "alloy-signer", @@ -251,7 +251,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94ad40869867ed2d9cd3842b1e800889e5b49e6b92da346e93862b4a741bedf3" dependencies = [ "alloy-eips 0.3.6", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-serde 0.3.6", "serde", ] @@ -264,7 +264,7 @@ checksum = "514f70ee2a953db21631cd817b13a1571474ec77ddc03d47616d5e8203489fde" dependencies = [ "alloy-consensus 0.5.4", "alloy-eips 0.5.4", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-serde 0.5.4", "serde", ] @@ -293,9 +293,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8edae627382349b56cd6a7a2106f4fd69b243a9233e560c55c2e03cabb7e1d3c" +checksum = "fd58d377699e6cfeab52c4a9d28bdc4ef37e2bd235ff2db525071fe37a2e9af5" dependencies = [ "alloy-rlp", "bytes", @@ -362,7 +362,7 @@ dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-network-primitives 0.3.6", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-serde 0.3.6", "alloy-sol-types", @@ -383,7 +383,7 @@ dependencies = [ "alloy-consensus 0.5.4", "alloy-eips 0.5.4", "alloy-network-primitives 0.5.4", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-serde 0.5.4", "alloy-sol-types", @@ -399,7 +399,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731f75ec5d383107fd745d781619bd9cedf145836c51ecb991623d41278e71fa" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "serde", "serde_json", ] @@ -410,7 +410,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "028e72eaa9703e4882344983cfe7636ce06d8cce104a78ea62fd19b46659efc4" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "serde", "serde_json", ] @@ -421,7 +421,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "592c185d7100258c041afac51877660c7bf6213447999787197db4842f0e938e" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "async-trait", "auto_impl", "elliptic-curve", @@ -437,7 +437,7 @@ checksum = "6614f02fc1d5b079b2a4a5320018317b506fd0a6d67c1fd5542a71201724986c" dependencies = [ "alloy-consensus 0.5.4", "alloy-network", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-signer", "async-trait", "k256", @@ -447,9 +447,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841eabaa4710f719fddbc24c95d386eae313f07e6da4babc25830ee37945be0c" +checksum = "8a1b42ac8f45e2f49f4bcdd72cbfde0bb148f5481d403774ffa546e48b83efc1" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -461,9 +461,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6672337f19d837b9f7073c45853aeb528ed9f7dd6a4154ce683e9e5cb7794014" +checksum = "06318f1778e57f36333e850aa71bd1bb5e560c10279e236622faae0470c50412" dependencies = [ "alloy-sol-macro-input", "const-hex", @@ -479,9 +479,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dff37dd20bfb118b777c96eda83b2067f4226d2644c5cfa00187b3bc01770ba" +checksum = "eaebb9b0ad61a41345a22c9279975c0cdd231b97947b10d7aad1cf0a7181e4a5" dependencies = [ "const-hex", "dunce", @@ -494,9 +494,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b853d42292dbb159671a3edae3b2750277ff130f32b726fe07dc2b17aa6f2b5" +checksum = "12c71028bfbfec210e24106a542aad3def7caf1a70e2c05710e92a98481980d3" dependencies = [ "serde", "winnow 0.6.20", @@ -504,12 +504,12 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa828bb1b9a6dc52208fbb18084fb9ce2c30facc2bfda6a5d922349b4990354f" +checksum = "374d7fb042d68ddfe79ccb23359de3007f6d4d53c13f703b64fb0db422132111" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-sol-macro", "const-hex", "serde", @@ -521,7 +521,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a46c9c4fdccda7982e7928904bd85fe235a0404ee3d7e197fff13d61eac8b4f" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "derive_more 1.0.0", "hashbrown 0.14.5", @@ -606,9 +606,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "ark-ff" @@ -1160,9 +1160,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.34" +version = "1.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" +checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" dependencies = [ "jobserver", "libc", @@ -1495,7 +1495,7 @@ dependencies = [ [[package]] name = "curve25519-dalek-ng" version = "4.1.1" -source = "git+https://github.com/sp1-patches/curve25519-dalek-ng?branch=patch-v4.1.1#3fb3e7f6047ddeef0f0c9212f4604bd30d64bd28" +source = "git+https://github.com/sp1-patches/curve25519-dalek-ng.git?branch=patch-v4.1.1#3fb3e7f6047ddeef0f0c9212f4604bd30d64bd28" dependencies = [ "anyhow", "byteorder", @@ -1829,7 +1829,7 @@ name = "ed25519-consensus" version = "2.1.0" source = "git+https://github.com/sp1-patches/ed25519-consensus?tag=ed25519_consensus-v2.1.0-patch-v1#2b2c4b43344bc4daf5b1326f367f2d9d661eeabb" dependencies = [ - "curve25519-dalek-ng 4.1.1 (git+https://github.com/sp1-patches/curve25519-dalek-ng?branch=patch-v4.1.1)", + "curve25519-dalek-ng 4.1.1 (git+https://github.com/sp1-patches/curve25519-dalek-ng.git?branch=patch-v4.1.1)", "hex", "rand_core 0.6.4", "serde", @@ -1876,6 +1876,7 @@ dependencies = [ "ff 0.13.0", "generic-array 0.14.7", "group 0.13.0", + "pem-rfc7468 0.7.0", "pkcs8 0.10.2", "rand_core 0.6.4", "sec1", @@ -3397,7 +3398,7 @@ checksum = "21aad1fbf80d2bcd7406880efc7ba109365f44bbb72896758ddcbfa46bf1592c" dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-serde 0.3.6", "derive_more 1.0.0", @@ -3413,7 +3414,7 @@ checksum = "e281fbfc2198b7c0c16457d6524f83d192662bc9f3df70f24c3038d4521616df" dependencies = [ "alloy-eips 0.3.6", "alloy-network-primitives 0.3.6", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rpc-types-eth 0.3.6", "alloy-serde 0.3.6", "cfg-if", @@ -3790,11 +3791,13 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" name = "patch-testing-program" version = "1.1.0" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "curve25519-dalek", "curve25519-dalek-ng 4.1.1 (git+https://github.com/sp1-patches/curve25519-dalek-ng?tag=curve25519_dalek_ng-v4.1.1-patch-v1)", "ed25519-consensus", "ed25519-dalek", + "k256", + "p256", "revm-precompile", "secp256k1", "sha2 0.10.8", @@ -4127,9 +4130,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" dependencies = [ "cfg_aliases", "libc", @@ -4428,7 +4431,7 @@ dependencies = [ "alloy-chains", "alloy-eips 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-trie", "auto_impl", "derive_more 1.0.0", @@ -4450,7 +4453,7 @@ dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-trie", "bytes", "modular-bitfield", @@ -4532,7 +4535,7 @@ version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ "alloy-chains", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "auto_impl", "crc", @@ -4605,7 +4608,7 @@ version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ "alloy-eips 0.3.6", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "derive_more 1.0.0", "nybbles", @@ -4642,7 +4645,7 @@ name = "reth-network-peers" version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "enr", "serde_with", @@ -4656,7 +4659,7 @@ version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ "alloy-chains", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "derive_more 1.0.0", "once_cell", "reth-chainspec", @@ -4685,7 +4688,7 @@ dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-rpc-types", "alloy-serde 0.3.6", @@ -4714,7 +4717,7 @@ dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-rpc-types-eth 0.3.6", "byteorder", @@ -4732,7 +4735,7 @@ name = "reth-prune-types" version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "bytes", "derive_more 1.0.0", "modular-bitfield", @@ -4761,7 +4764,7 @@ name = "reth-stages-types" version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "bytes", "modular-bitfield", "reth-codecs", @@ -4774,7 +4777,7 @@ name = "reth-static-file-types" version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "derive_more 1.0.0", "serde", "strum", @@ -4833,7 +4836,7 @@ source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374 dependencies = [ "alloy-consensus 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-trie", "bytes", @@ -4898,7 +4901,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7a6bff9dbde3370a5ac9555104117f7e6039b3cc76e8d5d9d01899088beca2a" dependencies = [ "alloy-eips 0.3.6", - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "auto_impl", "bitflags", "bitvec", @@ -5040,7 +5043,7 @@ name = "rsp-client-executor" version = "0.1.0" source = "git+https://github.com/succinctlabs/rsp/?rev=3647076#3647076da6580e30384dd911a3fc50d4bcdb5bc1" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "eyre", "futures", @@ -5073,7 +5076,7 @@ name = "rsp-mpt" version = "0.1.0" source = "git+https://github.com/succinctlabs/rsp/?rev=3647076#3647076da6580e30384dd911a3fc50d4bcdb5bc1" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "alloy-rlp", "alloy-rpc-types", "anyhow", @@ -5123,7 +5126,7 @@ dependencies = [ name = "rsp-script" version = "0.1.0" dependencies = [ - "alloy-primitives 0.8.10", + "alloy-primitives 0.8.11", "bincode", "clap", "rsp-client-executor", @@ -5732,6 +5735,7 @@ dependencies = [ "log", "num", "num_cpus", + "p256", "p3-air", "p3-baby-bear", "p3-challenger", @@ -5789,6 +5793,7 @@ dependencies = [ "itertools 0.13.0", "k256", "num", + "p256", "p3-field", "serde", "snowbridge-amcl", @@ -6313,9 +6318,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16320d4a2021ba1a32470b3759676114a918885e9800e68ad60f2c67969fba62" +checksum = "edf42e81491fb8871b74df3d222c64ae8cbc1269ea509fa768a3ed3e1b0ac8cb" dependencies = [ "paste", "proc-macro2", @@ -7471,7 +7476,7 @@ dependencies = [ [[patch.unused]] name = "ecdsa" version = "0.16.8" -source = "git+https://github.com/sp1-patches/signatures?tag=ecdsa-v0.16.8-patch-v1#aad9626d51e830729969220eee44de082ff97d53" +source = "git+https://github.com/sp1-patches/signatures?branch=umadayal/secp256r1#49b6288468aff7f88f0be8cfd3719c7c20b2ba47" [[patch.unused]] name = "sha2" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 4022f079b2..f5d06c2216 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -63,7 +63,7 @@ sp1-zkvm = { path = "../crates/zkvm/entrypoint", default-features = false } [patch.crates-io] curve25519-dalek = { git = "https://github.com/sp1-patches/curve25519-dalek", tag = "curve25519_dalek-v4.1.3-patch-v1" } curve25519-dalek-ng = { git = "https://github.com/sp1-patches/curve25519-dalek-ng", tag = "curve25519_dalek_ng-v4.1.1-patch-v1" } -ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", tag = "ecdsa-v0.16.8-patch-v1" } +ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", branch = "umadayal/secp256r1" } ed25519-consensus = { git = "https://github.com/sp1-patches/ed25519-consensus", tag = "ed25519_consensus-v2.1.0-patch-v1" } secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", tag = "secp256k1-v0.29.0-patch-v1" } sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", tag = "sha2-v0.10.8-patch-v1" } diff --git a/examples/aggregation/program/elf/riscv32im-succinct-zkvm-elf b/examples/aggregation/program/elf/riscv32im-succinct-zkvm-elf index 6ca187d36d..a2da621a86 100755 Binary files a/examples/aggregation/program/elf/riscv32im-succinct-zkvm-elf and b/examples/aggregation/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/chess/program/elf/riscv32im-succinct-zkvm-elf b/examples/chess/program/elf/riscv32im-succinct-zkvm-elf index 6dd5d47402..2894eb1b33 100755 Binary files a/examples/chess/program/elf/riscv32im-succinct-zkvm-elf and b/examples/chess/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/cycle-tracking/program/elf/normal b/examples/cycle-tracking/program/elf/normal index 1f6e0e65b9..db1fa3549c 100755 Binary files a/examples/cycle-tracking/program/elf/normal and b/examples/cycle-tracking/program/elf/normal differ diff --git a/examples/cycle-tracking/program/elf/report b/examples/cycle-tracking/program/elf/report index 23173c4284..400f358765 100755 Binary files a/examples/cycle-tracking/program/elf/report and b/examples/cycle-tracking/program/elf/report differ diff --git a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf index 61e8973390..c82f73b866 100755 Binary files a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf and b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/groth16/program/src/main.rs b/examples/groth16/program/src/main.rs index f7dd8178f4..bc38ecdbc9 100644 --- a/examples/groth16/program/src/main.rs +++ b/examples/groth16/program/src/main.rs @@ -18,12 +18,9 @@ pub fn main() { println!("cycle-tracker-end: verify"); match result { - Ok(true) => { + Ok(()) => { println!("Proof is valid"); } - Ok(false) => { - println!("Proof is invalid"); - } Err(e) => { println!("Error verifying proof: {:?}", e); } diff --git a/examples/groth16/script/src/main.rs b/examples/groth16/script/src/main.rs index 1a55484de1..b35a15f58c 100644 --- a/examples/groth16/script/src/main.rs +++ b/examples/groth16/script/src/main.rs @@ -1,7 +1,7 @@ //! A script that generates a Groth16 proof for the Fibonacci program, and verifies the //! Groth16 proof in SP1. -use sp1_sdk::{include_elf, utils, HashableKey, ProverClient, SP1ProofWithPublicValues, SP1Stdin}; +use sp1_sdk::{include_elf, utils, HashableKey, ProverClient, SP1Stdin}; /// The ELF for the Groth16 verifier program. const GROTH16_ELF: &[u8] = include_elf!("groth16-verifier-program"); @@ -9,7 +9,11 @@ const GROTH16_ELF: &[u8] = include_elf!("groth16-verifier-program"); /// The ELF for the Fibonacci program. const FIBONACCI_ELF: &[u8] = include_elf!("fibonacci-program"); -fn generate_fibonacci_proof() -> (SP1ProofWithPublicValues, String) { +/// Generates the proof, public values, and vkey hash for the Fibonacci program in a format that +/// can be read by `sp1-verifier`. +/// +/// Returns the proof bytes, public values, and vkey hash. +fn generate_fibonacci_proof() -> (Vec, Vec, String) { // Create an input stream and write '20' to it. let n = 20u32; @@ -21,23 +25,24 @@ fn generate_fibonacci_proof() -> (SP1ProofWithPublicValues, String) { // Create a `ProverClient`. let client = ProverClient::new(); - // Generate the proof for the fibonacci program.. + // Generate the groth16 proof for the Fibonacci program. let (pk, vk) = client.setup(FIBONACCI_ELF); println!("vk: {:?}", vk.bytes32()); - (client.prove(&pk, stdin).groth16().run().unwrap(), vk.bytes32()) + let proof = client.prove(&pk, stdin).groth16().run().unwrap(); + (proof.bytes(), proof.public_values.to_vec(), vk.bytes32()) } fn main() { // Setup logging. utils::setup_logger(); - // Generate the Fibonacci proof. - let (fibonacci_proof, vk) = generate_fibonacci_proof(); + // Generate the Fibonacci proof, public values, and vkey hash. + let (fibonacci_proof, fibonacci_public_values, vk) = generate_fibonacci_proof(); // Write the proof, public values, and vkey hash to the input stream. let mut stdin = SP1Stdin::new(); - stdin.write_vec(fibonacci_proof.bytes()); - stdin.write_vec(fibonacci_proof.public_values.to_vec()); + stdin.write_vec(fibonacci_proof); + stdin.write_vec(fibonacci_public_values); stdin.write(&vk); // Create a `ProverClient`. diff --git a/examples/io/program/elf/riscv32im-succinct-zkvm-elf b/examples/io/program/elf/riscv32im-succinct-zkvm-elf index 30a53c5a44..597cbb8d5e 100755 Binary files a/examples/io/program/elf/riscv32im-succinct-zkvm-elf and b/examples/io/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/json/program/elf/riscv32im-succinct-zkvm-elf b/examples/json/program/elf/riscv32im-succinct-zkvm-elf index 799030dbca..74f4004c86 100755 Binary files a/examples/json/program/elf/riscv32im-succinct-zkvm-elf and b/examples/json/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/patch-testing/program/Cargo.toml b/examples/patch-testing/program/Cargo.toml index 93b9967e0e..a9d4feff9e 100644 --- a/examples/patch-testing/program/Cargo.toml +++ b/examples/patch-testing/program/Cargo.toml @@ -17,7 +17,9 @@ ed25519-dalek = "2.1.0" tiny-keccak = { version = "2.0.2", features = ["keccak"] } curve25519-dalek = { version = "4.1.3", default-features = false, features = ["alloc"] } curve25519-dalek-ng = { version = "4.1", default-features = false, features = ["u32_backend", "alloc"] } +k256 = { version = "0.13.3", default-features = false, features = ["ecdsa"] } +p256 = { version = "0.13.2", default-features = false, features = ["ecdsa"] } alloy-primitives = { version = "0.8", features = ["k256"] } secp256k1 = { version = "0.29", features = ["recovery", "global-context"] } -revm-precompile = { version = "11.0.1", default-features = false, features = ["kzg-rs"] } +revm-precompile = { version = "11.0.1", default-features = false, features = ["kzg-rs", "secp256r1"] } diff --git a/examples/patch-testing/program/elf/riscv32im-succinct-zkvm-elf b/examples/patch-testing/program/elf/riscv32im-succinct-zkvm-elf index a96b1c119c..7dea910adf 100755 Binary files a/examples/patch-testing/program/elf/riscv32im-succinct-zkvm-elf and b/examples/patch-testing/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/patch-testing/program/src/main.rs b/examples/patch-testing/program/src/main.rs index cfa7829209..fe6e0d36a0 100644 --- a/examples/patch-testing/program/src/main.rs +++ b/examples/patch-testing/program/src/main.rs @@ -15,15 +15,15 @@ use ed25519_dalek::{ use sha2_v0_10_6::{Digest as Digest_10_6, Sha256 as Sha256_10_6}; // use sha2_v0_10_8::{Digest as Digest_10_8, Sha256 as Sha256_10_8}; -use sha2_v0_9_8::{Digest as Digest_9_8, Sha256 as Sha256_9_8}; -use tiny_keccak::{Hasher, Keccak}; - use secp256k1::{ ecdsa::{ RecoverableSignature as Secp256k1RecoverableSignature, RecoveryId as Secp256k1RecoveryId, + Signature as Secp256k1Signature, }, Message as Secp256k1Message, }; +use sha2_v0_9_8::{Digest as Digest_9_8, Sha256 as Sha256_9_8}; +use tiny_keccak::{Hasher, Keccak}; /// Simple interface to the [`keccak256`] hash function. /// @@ -122,6 +122,32 @@ fn test_sha256() { // let output_10_8 = sha256_10_8.finalize(); } +fn test_p256_patch() { + // A valid signature. + let precompile_input = bytes!("b5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdcef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1"); + println!("cycle-tracker-start: p256 verify"); + let result = revm_precompile::secp256r1::verify_impl(&precompile_input); + println!("cycle-tracker-end: p256 verify"); + + assert!(result.is_some()); + + let invalid_test_cases = vec![ + bytes!("3cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e"), + bytes!("afec5769b5cf4e310a7d150508e82fb8e3eda1c2c94c61492d3bd8aea99e06c9e22466e928fdccef0de49e3503d2657d00494a00e764fd437bdafa05f5922b1fbbb77c6817ccf50748419477e843d5bac67e6a70e97dde5a57e0c983b777e1ad31a80482dadf89de6302b1988c82c29544c9c07bb910596158f6062517eb089a2f54c9a0f348752950094d3228d3b940258c75fe2a413cb70baa21dc2e352fc5"), + bytes!("f775723953ead4a90411a02908fd1a629db584bc600664c609061f221ef6bf7c440066c8626b49daaa7bf2bcc0b74be4f7a1e3dcf0e869f1542fe821498cbf2de73ad398194129f635de4424a07ca715838aefe8fe69d1a391cfa70470795a80dd056866e6e1125aff94413921880c437c9e2570a28ced7267c8beef7e9b2d8d1547d76dfcf4bee592f5fefe10ddfb6aeb0991c5b9dbbee6ec80d11b17c0eb1a"), + bytes!("4cee90eb86eaa050036147a12d49004b6a"), + bytes!("4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e00"), + bytes!("b5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1") + ]; + + for input in invalid_test_cases { + println!("cycle-tracker-start: p256 verify false"); + let result = revm_precompile::secp256r1::verify_impl(&input); + println!("cycle-tracker-end: p256 verify false"); + assert!(result.is_none()); + } +} + /// Emits SECP256K1_ADD, SECP256K1_DOUBLE, and SECP256K1_DECOMPRESS syscalls. /// Source: https://github.com/alloy-rs/core/blob/adcf7adfa1f35c56e6331bab85b8c56d32a465f1/crates/primitives/src/signature/sig.rs#L620-L631 fn test_k256_patch() { @@ -130,6 +156,7 @@ fn test_k256_patch() { let msg = <&B256>::try_from(&precompile_input[0..32]).unwrap(); let recid = precompile_input[63] - 27; + println!("recid: {}", recid); let sig = <&B512>::try_from(&precompile_input[64..128]).unwrap(); println!("cycle-tracker-start: k256 verify"); @@ -180,6 +207,13 @@ fn test_secp256k1_patch() { let serialized_key = public_key.serialize_uncompressed(); + let sig = Secp256k1Signature::from_compact(&hex!("80AEBD912F05D302BA8000A3C5D6E604333AAF34E22CC1BA14BE1737213EAED5040D67D6E9FA5FBDFE6E3457893839631B87A41D90508B7C92991ED7824E962D")).unwrap(); + println!("cycle-tracker-start: secp256k1 verify_ecdsa"); + let result = secp.verify_ecdsa(&message, &sig, &public_key); + println!("cycle-tracker-end: secp256k1 verify_ecdsa"); + + assert!(result.is_ok()); + // Use the message in the recover_ecdsa call assert_eq!(hex::encode(serialized_key), expected); } @@ -199,4 +233,5 @@ pub fn main() { test_k256_patch(); test_secp256k1_patch(); + test_p256_patch(); } diff --git a/examples/patch-testing/script/src/main.rs b/examples/patch-testing/script/src/main.rs index 9b0df8f01c..c80446a5b3 100644 --- a/examples/patch-testing/script/src/main.rs +++ b/examples/patch-testing/script/src/main.rs @@ -33,6 +33,13 @@ pub fn main() { 0 ); + // Confirm there was at least 1 SECP256R1_ADD and SECP256R1_DOUBLE syscall. + assert_ne!(report.syscall_counts[sp1_core_executor::syscalls::SyscallCode::SECP256R1_ADD], 0); + assert_ne!( + report.syscall_counts[sp1_core_executor::syscalls::SyscallCode::SECP256R1_DOUBLE], + 0 + ); + println!("Total instructions: {:?}", report.total_instruction_count()); println!("Successfully executed the program & confirmed syscalls."); } diff --git a/examples/regex/program/elf/riscv32im-succinct-zkvm-elf b/examples/regex/program/elf/riscv32im-succinct-zkvm-elf index a6dae1343f..d514b22b0e 100755 Binary files a/examples/regex/program/elf/riscv32im-succinct-zkvm-elf and b/examples/regex/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf b/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf index 514e936859..d50cf9dff3 100755 Binary files a/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf and b/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf b/examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf index 10b1987383..ebd2cdcdc1 100755 Binary files a/examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf and b/examples/ssz-withdrawals/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf b/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf index be2d7b0e48..371681cd5c 100755 Binary files a/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf and b/examples/tendermint/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/Cargo.lock b/tests/Cargo.lock index 065277d8c4..d286799538 100644 --- a/tests/Cargo.lock +++ b/tests/Cargo.lock @@ -107,7 +107,7 @@ version = "1.1.0" dependencies = [ "common-test-utils", "sp1-curves", - "sp1-lib 2.0.0", + "sp1-lib 3.0.0-rc4", "sp1-zkvm", ] @@ -151,7 +151,7 @@ name = "bls12381-mul-test" version = "1.1.0" dependencies = [ "sp1-derive", - "sp1-lib 2.0.0", + "sp1-lib 3.0.0-rc4", "sp1-zkvm", ] @@ -161,7 +161,7 @@ version = "1.1.0" dependencies = [ "common-test-utils", "sp1-curves", - "sp1-lib 2.0.0", + "sp1-lib 3.0.0-rc4", "sp1-zkvm", ] @@ -204,7 +204,7 @@ name = "bn254-mul-test" version = "1.1.0" dependencies = [ "sp1-derive", - "sp1-lib 2.0.0", + "sp1-lib 3.0.0-rc4", "sp1-zkvm", ] @@ -246,7 +246,7 @@ name = "common-test-utils" version = "1.1.0" dependencies = [ "num-bigint", - "sp1-lib 2.0.0", + "sp1-lib 3.0.0-rc4", ] [[package]] @@ -495,6 +495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -632,6 +633,7 @@ dependencies = [ "ff", "generic-array 0.14.7", "group", + "pem-rfc7468", "pkcs8", "rand_core", "sec1", @@ -1065,10 +1067,23 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.8", +] + [[package]] name = "p3-air" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "066f571b2e645505ed5972dd0e1e252ba03352150830c9566769ca711c0f1e9b" dependencies = [ "p3-field", "p3-matrix", @@ -1076,8 +1091,9 @@ dependencies = [ [[package]] name = "p3-baby-bear" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff00f571044d299310d9659c6e51c98422de3bf94b8577f7f30cf59cf2043e40" dependencies = [ "num-bigint", "p3-field", @@ -1090,8 +1106,9 @@ dependencies = [ [[package]] name = "p3-challenger" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be7e4fbce4566a93091107eadfafa0b5374bd1ffd3e0f6b850da3ff72eb183f" dependencies = [ "p3-field", "p3-maybe-rayon", @@ -1103,11 +1120,13 @@ dependencies = [ [[package]] name = "p3-commit" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a03eb0f99d68a712c41e658e9a7782a0705d4ffcfb6232a43bd3f1ef9591002" dependencies = [ "itertools 0.12.1", "p3-challenger", + "p3-dft", "p3-field", "p3-matrix", "p3-util", @@ -1116,8 +1135,9 @@ dependencies = [ [[package]] name = "p3-dft" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1556de968523fbe5d804ab50600ea306fcceea3500cfd7601e40882480524664" dependencies = [ "p3-field", "p3-matrix", @@ -1128,8 +1148,9 @@ dependencies = [ [[package]] name = "p3-field" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec2af6e1ac47a2035af5165e668d64612c4b9ccabd06df37fc1fd381fdf8a71" dependencies = [ "itertools 0.12.1", "num-bigint", @@ -1141,8 +1162,9 @@ dependencies = [ [[package]] name = "p3-fri" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f351ee9f9d4256455164565cd91e3e6d2487cc2a5355515fa2b6d479269188dd" dependencies = [ "itertools 0.12.1", "p3-challenger", @@ -1159,8 +1181,9 @@ dependencies = [ [[package]] name = "p3-interpolation" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24d0f2907a374ebe4545fcff3120d6376d9630cf0bef30feedcfc5908ea2c37" dependencies = [ "p3-field", "p3-matrix", @@ -1169,8 +1192,9 @@ dependencies = [ [[package]] name = "p3-matrix" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa272f3ae77ed8d73478aa7c89e712efb15bda3ff4aff10fadfe11a012cd5389" dependencies = [ "itertools 0.12.1", "p3-field", @@ -1183,16 +1207,18 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eecad6292021858f282d643d9d1284ab112a200494d589863a9c4080e578ef0" dependencies = [ "rayon", ] [[package]] name = "p3-mds" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "716c4dbe68a02f1541eb09149d07b8663a3a5951b1864a31cd67ff3bb0826e57" dependencies = [ "itertools 0.12.1", "p3-dft", @@ -1205,8 +1231,9 @@ dependencies = [ [[package]] name = "p3-merkle-tree" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad7ebab52a03c26025988663a135aed62f5084a2e2ea262176dc8748efb593e5" dependencies = [ "itertools 0.12.1", "p3-commit", @@ -1221,8 +1248,9 @@ dependencies = [ [[package]] name = "p3-poseidon2" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c042efa15beab7a8c4d0ca9b9e4cbda7582be0c08e121e830fec45f082935b" dependencies = [ "gcd", "p3-field", @@ -1234,8 +1262,9 @@ dependencies = [ [[package]] name = "p3-symmetric" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9896a831f5b688adc13f6fbe1dcf66ecfaa4622a500f81aa745610e777acb72" dependencies = [ "itertools 0.12.1", "p3-field", @@ -1244,8 +1273,9 @@ dependencies = [ [[package]] name = "p3-uni-stark" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437ebcd060c8a5479898030b114a93da8a86eb4c2e5f313d9eeaaf40c6e6f61" dependencies = [ "itertools 0.12.1", "p3-air", @@ -1262,8 +1292,9 @@ dependencies = [ [[package]] name = "p3-util" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v3#0f8d103e67dbec3e84bac1de6d00bf0f2fb80de0" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dedb9d27ba47ac314c6fac4ca54e55c3e486c864d51ec5ba55dbe47b75121157" dependencies = [ "serde", ] @@ -1305,6 +1336,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1348,6 +1388,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -1550,7 +1599,7 @@ version = "1.1.0" dependencies = [ "common-test-utils", "sp1-curves", - "sp1-lib 2.0.0", + "sp1-lib 3.0.0-rc4", "sp1-zkvm", ] @@ -1713,7 +1762,7 @@ dependencies = [ [[package]] name = "sp1-curves" -version = "2.0.0" +version = "3.0.0-rc4" dependencies = [ "cfg-if", "curve25519-dalek 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1723,6 +1772,7 @@ dependencies = [ "itertools 0.13.0", "k256", "num", + "p256", "p3-field", "serde", "snowbridge-amcl", @@ -1733,7 +1783,7 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "2.0.0" +version = "3.0.0-rc4" dependencies = [ "quote", "syn 1.0.109", @@ -1755,7 +1805,7 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "2.0.0" +version = "3.0.0-rc4" dependencies = [ "bincode", "serde", @@ -1763,7 +1813,7 @@ dependencies = [ [[package]] name = "sp1-primitives" -version = "2.0.0" +version = "3.0.0-rc4" dependencies = [ "bincode", "hex", @@ -1779,7 +1829,7 @@ dependencies = [ [[package]] name = "sp1-stark" -version = "2.0.0" +version = "3.0.0-rc4" dependencies = [ "arrayref", "getrandom", @@ -1813,7 +1863,7 @@ dependencies = [ [[package]] name = "sp1-zkvm" -version = "2.0.0" +version = "3.0.0-rc4" dependencies = [ "cfg-if", "getrandom", @@ -1823,7 +1873,7 @@ dependencies = [ "p3-field", "rand", "sha2 0.10.8", - "sp1-lib 2.0.0", + "sp1-lib 3.0.0-rc4", "sp1-primitives", ] diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 277a393152..aed2a6f4ef 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -28,6 +28,9 @@ members = [ "secp256k1-decompress", "secp256k1-double", "secp256k1-mul", + "secp256r1-add", + "secp256r1-decompress", + "secp256r1-double", "sha-compress", "sha-extend", "sha2", diff --git a/tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf index 8338541b89..bba115ef9d 100755 Binary files a/tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf and b/tests/bls12381-add/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-decompress/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-decompress/elf/riscv32im-succinct-zkvm-elf index 338b1294f5..03acdb46c2 100755 Binary files a/tests/bls12381-decompress/elf/riscv32im-succinct-zkvm-elf and b/tests/bls12381-decompress/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-double/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-double/elf/riscv32im-succinct-zkvm-elf index e6069d00d7..b8da0c0c5e 100755 Binary files a/tests/bls12381-double/elf/riscv32im-succinct-zkvm-elf and b/tests/bls12381-double/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf index 0dc6cb73de..ae3399e676 100755 Binary files a/tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf and b/tests/bls12381-fp/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf index 0528a0304d..31c4ed4d21 100755 Binary files a/tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf and b/tests/bls12381-fp2-addsub/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf index aefd01db8f..ada874cdb8 100755 Binary files a/tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf and b/tests/bls12381-fp2-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bls12381-mul/elf/riscv32im-succinct-zkvm-elf b/tests/bls12381-mul/elf/riscv32im-succinct-zkvm-elf index 5102c5ce76..10056efc39 100755 Binary files a/tests/bls12381-mul/elf/riscv32im-succinct-zkvm-elf and b/tests/bls12381-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-add/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-add/elf/riscv32im-succinct-zkvm-elf index bf87b4456c..4197f5e570 100755 Binary files a/tests/bn254-add/elf/riscv32im-succinct-zkvm-elf and b/tests/bn254-add/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-double/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-double/elf/riscv32im-succinct-zkvm-elf index 77f9a29d7c..d8ce2e4945 100755 Binary files a/tests/bn254-double/elf/riscv32im-succinct-zkvm-elf and b/tests/bn254-double/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf index 487f198d10..157b571756 100755 Binary files a/tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf and b/tests/bn254-fp/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf index 5af2f91a1a..254f1e5338 100755 Binary files a/tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf and b/tests/bn254-fp2-addsub/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf index 8ed09da22f..7f9ce49898 100755 Binary files a/tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf and b/tests/bn254-fp2-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/bn254-mul/elf/riscv32im-succinct-zkvm-elf b/tests/bn254-mul/elf/riscv32im-succinct-zkvm-elf index 48720a7225..0826d5be1e 100755 Binary files a/tests/bn254-mul/elf/riscv32im-succinct-zkvm-elf and b/tests/bn254-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/cycle-tracker/elf/riscv32im-succinct-zkvm-elf b/tests/cycle-tracker/elf/riscv32im-succinct-zkvm-elf index cfcd052579..d24493ae78 100755 Binary files a/tests/cycle-tracker/elf/riscv32im-succinct-zkvm-elf and b/tests/cycle-tracker/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/ed-add/elf/riscv32im-succinct-zkvm-elf b/tests/ed-add/elf/riscv32im-succinct-zkvm-elf index 2522026284..ba53a59d77 100755 Binary files a/tests/ed-add/elf/riscv32im-succinct-zkvm-elf and b/tests/ed-add/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf b/tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf index 52cd651f37..817545c74d 100755 Binary files a/tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf and b/tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/ed25519/elf/riscv32im-succinct-zkvm-elf b/tests/ed25519/elf/riscv32im-succinct-zkvm-elf index 9b4414d93c..8d569ec367 100755 Binary files a/tests/ed25519/elf/riscv32im-succinct-zkvm-elf and b/tests/ed25519/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/fibonacci/elf/riscv32im-succinct-zkvm-elf b/tests/fibonacci/elf/riscv32im-succinct-zkvm-elf index 2a1154f08c..148ae8d903 100755 Binary files a/tests/fibonacci/elf/riscv32im-succinct-zkvm-elf and b/tests/fibonacci/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/hint-io/elf/riscv32im-succinct-zkvm-elf b/tests/hint-io/elf/riscv32im-succinct-zkvm-elf index 3ce153925a..08e72217e3 100755 Binary files a/tests/hint-io/elf/riscv32im-succinct-zkvm-elf and b/tests/hint-io/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/keccak-permute/elf/riscv32im-succinct-zkvm-elf b/tests/keccak-permute/elf/riscv32im-succinct-zkvm-elf index f4d95ffeee..3d5bc8f27b 100755 Binary files a/tests/keccak-permute/elf/riscv32im-succinct-zkvm-elf and b/tests/keccak-permute/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/keccak256/elf/riscv32im-succinct-zkvm-elf b/tests/keccak256/elf/riscv32im-succinct-zkvm-elf index 94db343707..e2ce61eedf 100755 Binary files a/tests/keccak256/elf/riscv32im-succinct-zkvm-elf and b/tests/keccak256/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/panic/elf/riscv32im-succinct-zkvm-elf b/tests/panic/elf/riscv32im-succinct-zkvm-elf index 11c6c7cba4..9b4339532b 100755 Binary files a/tests/panic/elf/riscv32im-succinct-zkvm-elf and b/tests/panic/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/rand/elf/riscv32im-succinct-zkvm-elf b/tests/rand/elf/riscv32im-succinct-zkvm-elf index 1ce9664bcb..486f5f4649 100755 Binary files a/tests/rand/elf/riscv32im-succinct-zkvm-elf and b/tests/rand/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf b/tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf index eba9ea3bab..f05f5721be 100755 Binary files a/tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf and b/tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf b/tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf index 89751b5437..679964c0a6 100755 Binary files a/tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf and b/tests/secp256k1-decompress/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf b/tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf index 2fb2a017c3..039a7c443a 100755 Binary files a/tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf and b/tests/secp256k1-double/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/secp256k1-double/src/main.rs b/tests/secp256k1-double/src/main.rs index bddcc1ac4d..72d62e4218 100644 --- a/tests/secp256k1-double/src/main.rs +++ b/tests/secp256k1-double/src/main.rs @@ -5,7 +5,7 @@ use sp1_zkvm::syscalls::syscall_secp256k1_double; sp1_zkvm::entrypoint!(main); pub fn main() { - for _ in 0..10i64.pow(3) { + for _ in 0..10 { // generator. // 55066263022277343669578718895168534326250603453777594175500187360389116729240 // 32670510020758816978083085130507043184471273380659243275938904335757337482424 diff --git a/tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf b/tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf index cb8333c2ae..d407481757 100755 Binary files a/tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf and b/tests/secp256k1-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/secp256r1-add/Cargo.toml b/tests/secp256r1-add/Cargo.toml new file mode 100644 index 0000000000..aa89d51815 --- /dev/null +++ b/tests/secp256r1-add/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "secp256r1-add-test" +version = "1.1.0" +edition = "2021" +publish = false + +[dependencies] +sp1-zkvm = { path = "../../crates/zkvm/entrypoint" } +sp1-lib = { path = "../../crates/zkvm/lib" } +sp1-curves = { path = "../../crates/curves" } +common-test-utils = { path = "../common" } +hex-literal = "0.4.1" +num = { version = "0.4.1", default-features = false } +p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] } +elliptic-curve = { version = "0.14.0-rc.0", default-features = false, features = ["sec1"] } \ No newline at end of file diff --git a/tests/secp256r1-add/elf/riscv32im-succinct-zkvm-elf b/tests/secp256r1-add/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..7819093a3a Binary files /dev/null and b/tests/secp256r1-add/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/secp256r1-add/src/main.rs b/tests/secp256r1-add/src/main.rs new file mode 100644 index 0000000000..7926e90993 --- /dev/null +++ b/tests/secp256r1-add/src/main.rs @@ -0,0 +1,44 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +use sp1_curves::params::FieldParameters; +use sp1_zkvm::lib::secp256r1::Secp256r1Point; + +pub fn main() { + // generator. + // 48439561293906451759052585252797914202762949526041747995844080717082404635286 + // 36134250956749795798585127919587881956611106672985015071877198253568414405109 + + const A: [u8; 64] = [ + 150, 194, 152, 216, 69, 57, 161, 244, 160, 51, 235, 45, 129, 125, 3, 119, 242, 64, 164, 99, + 229, 230, 188, 248, 71, 66, 44, 225, 242, 209, 23, 107, 245, 81, 191, 55, 104, 64, 182, + 203, 206, 94, 49, 107, 87, 51, 206, 43, 22, 158, 15, 124, 74, 235, 231, 142, 155, 127, 26, + 254, 226, 66, 227, 79, + ]; + + // 2 * generator. + // 56515219790691171413109057904011688695424810155802929973526481321309856242040 + // 3377031843712258259223711451491452598088675519751548567112458094635497583569 + const B: [u8; 64] = [ + 120, 153, 102, 71, 252, 72, 11, 166, 53, 27, 242, 119, 226, 105, 137, 192, 195, 26, 181, 4, + 3, 56, 82, 138, 126, 79, 3, 141, 24, 123, 242, 124, 209, 115, 120, 34, 157, 183, 4, 158, + 41, 130, 233, 60, 230, 173, 125, 186, 219, 48, 116, 159, 198, 154, 61, 41, 64, 208, 142, + 219, 16, 85, 119, 7, + ]; + + // 3 * generator. + // 42877656971275811310262564894490210024759287182177196162425349131675946712428 + // 61154801112014214504178281461992570017247172004704277041681093927569603776562 + const C: [u8; 64] = [ + 108, 253, 231, 198, 27, 102, 65, 251, 133, 169, 173, 239, 33, 183, 198, 230, 101, 241, 75, + 29, 149, 239, 247, 200, 68, 10, 51, 166, 209, 228, 203, 94, 50, 80, 125, 162, 39, 177, 121, + 154, 61, 184, 79, 56, 54, 176, 42, 216, 236, 162, 100, 26, 206, 6, 75, 55, 126, 255, 152, + 73, 12, 100, 52, 135, + ]; + + // Tests A + B == C, sum of points of infinity, A + A == 2 * A, and A + (-A) == infinity. + common_test_utils::weierstrass_add::test_weierstrass_add::< + Secp256r1Point, + { sp1_lib::secp256r1::N }, + >(&A, &B, &C, sp1_curves::weierstrass::secp256r1::Secp256r1BaseField::MODULUS); +} diff --git a/tests/secp256r1-decompress/Cargo.toml b/tests/secp256r1-decompress/Cargo.toml new file mode 100644 index 0000000000..dd6984ced9 --- /dev/null +++ b/tests/secp256r1-decompress/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "secp256r1-decompress-test" +version = "1.1.0" +edition = "2021" +publish = false + +[dependencies] +sp1-zkvm = { path = "../../crates/zkvm/entrypoint" } diff --git a/tests/secp256r1-decompress/elf/riscv32im-succinct-zkvm-elf b/tests/secp256r1-decompress/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..d30ed5c96c Binary files /dev/null and b/tests/secp256r1-decompress/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/secp256r1-decompress/src/main.rs b/tests/secp256r1-decompress/src/main.rs new file mode 100644 index 0000000000..a7f5344b03 --- /dev/null +++ b/tests/secp256r1-decompress/src/main.rs @@ -0,0 +1,26 @@ +#![no_main] + +use sp1_zkvm::syscalls::syscall_secp256r1_decompress; + +sp1_zkvm::entrypoint!(main); + +pub fn main() { + let compressed_key: [u8; 33] = sp1_zkvm::io::read_vec().try_into().unwrap(); + + for _ in 0..4 { + let mut decompressed_key: [u8; 64] = [0; 64]; + decompressed_key[..32].copy_from_slice(&compressed_key[1..]); + let is_odd = match compressed_key[0] { + 2 => false, + 3 => true, + _ => panic!("Invalid compressed key"), + }; + syscall_secp256r1_decompress(&mut decompressed_key, is_odd); + + let mut result: [u8; 65] = [0; 65]; + result[0] = 4; + result[1..].copy_from_slice(&decompressed_key); + + sp1_zkvm::io::commit_slice(&result); + } +} diff --git a/tests/secp256r1-double/Cargo.toml b/tests/secp256r1-double/Cargo.toml new file mode 100644 index 0000000000..88c4299cad --- /dev/null +++ b/tests/secp256r1-double/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "secp256r1-double-test" +version = "1.1.0" +edition = "2021" +publish = false + +[dependencies] +sp1-zkvm = { path = "../../crates/zkvm/entrypoint" } +sp1-lib = { path = "../../crates/zkvm/lib" } +sp1-curves = { path = "../../crates/curves" } +common-test-utils = { path = "../common" } +hex-literal = "0.4.1" +num = { version = "0.4.1", default-features = false } +p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] } +elliptic-curve = { version = "0.14.0-rc.0", default-features = false, features = ["sec1"] } \ No newline at end of file diff --git a/tests/secp256r1-double/elf/riscv32im-succinct-zkvm-elf b/tests/secp256r1-double/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000..0b3b6c6aa9 Binary files /dev/null and b/tests/secp256r1-double/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/secp256r1-double/src/main.rs b/tests/secp256r1-double/src/main.rs new file mode 100644 index 0000000000..55660ac6ba --- /dev/null +++ b/tests/secp256r1-double/src/main.rs @@ -0,0 +1,30 @@ +#![no_main] +sp1_zkvm::entrypoint!(main); + +use sp1_zkvm::syscalls::syscall_secp256r1_double; + +pub fn main() { + // generator. + // 48439561293906451759052585252797914202762949526041747995844080717082404635286 + // 36134250956749795798585127919587881956611106672985015071877198253568414405109 + let mut a: [u8; 64] = [ + 150, 194, 152, 216, 69, 57, 161, 244, 160, 51, 235, 45, 129, 125, 3, 119, 242, 64, 164, 99, + 229, 230, 188, 248, 71, 66, 44, 225, 242, 209, 23, 107, 245, 81, 191, 55, 104, 64, 182, + 203, 206, 94, 49, 107, 87, 51, 206, 43, 22, 158, 15, 124, 74, 235, 231, 142, 155, 127, 26, + 254, 226, 66, 227, 79, + ]; + + // 2 * generator. + // 56515219790691171413109057904011688695424810155802929973526481321309856242040 + // 3377031843712258259223711451491452598088675519751548567112458094635497583569 + let b: [u8; 64] = [ + 120, 153, 102, 71, 252, 72, 11, 166, 53, 27, 242, 119, 226, 105, 137, 192, 195, 26, 181, 4, + 3, 56, 82, 138, 126, 79, 3, 141, 24, 123, 242, 124, 209, 115, 120, 34, 157, 183, 4, 158, + 41, 130, 233, 60, 230, 173, 125, 186, 219, 48, 116, 159, 198, 154, 61, 41, 64, 208, 142, + 219, 16, 85, 119, 7, + ]; + + syscall_secp256r1_double(a.as_mut_ptr() as *mut [u32; 16]); + + assert_eq!(a, b); +} diff --git a/tests/sha-compress/elf/riscv32im-succinct-zkvm-elf b/tests/sha-compress/elf/riscv32im-succinct-zkvm-elf index e7043fbe59..caa4b8d7fc 100755 Binary files a/tests/sha-compress/elf/riscv32im-succinct-zkvm-elf and b/tests/sha-compress/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/sha-extend/elf/riscv32im-succinct-zkvm-elf b/tests/sha-extend/elf/riscv32im-succinct-zkvm-elf index e90da84120..1f4b0f2854 100755 Binary files a/tests/sha-extend/elf/riscv32im-succinct-zkvm-elf and b/tests/sha-extend/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/sha2/elf/riscv32im-succinct-zkvm-elf b/tests/sha2/elf/riscv32im-succinct-zkvm-elf index 104609fa19..b8bcf3e71e 100755 Binary files a/tests/sha2/elf/riscv32im-succinct-zkvm-elf and b/tests/sha2/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/tendermint-benchmark/elf/riscv32im-succinct-zkvm-elf b/tests/tendermint-benchmark/elf/riscv32im-succinct-zkvm-elf index f16503cb07..9e70028015 100755 Binary files a/tests/tendermint-benchmark/elf/riscv32im-succinct-zkvm-elf and b/tests/tendermint-benchmark/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/uint256-arith/elf/riscv32im-succinct-zkvm-elf b/tests/uint256-arith/elf/riscv32im-succinct-zkvm-elf index b8e6cb0d8b..5f6f1e3e22 100755 Binary files a/tests/uint256-arith/elf/riscv32im-succinct-zkvm-elf and b/tests/uint256-arith/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf b/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf index f9862d8d20..886b86c07d 100755 Binary files a/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf and b/tests/uint256-mul/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/verify-proof/elf/riscv32im-succinct-zkvm-elf b/tests/verify-proof/elf/riscv32im-succinct-zkvm-elf index 140253849b..e982b30951 100755 Binary files a/tests/verify-proof/elf/riscv32im-succinct-zkvm-elf and b/tests/verify-proof/elf/riscv32im-succinct-zkvm-elf differ