From bcb99f8a9cfac0485a8947d4d7b7f2297742c50f Mon Sep 17 00:00:00 2001 From: mattstam Date: Wed, 9 Oct 2024 16:08:19 -0700 Subject: [PATCH 1/3] feat: v3.0.0-rc3 --- Cargo.lock | 610 ++------ Cargo.toml | 2 +- UPDATE_CONTRACTS.md | 6 +- .../v3.0.0-rc3/SP1VerifierGroth16.s.sol | 38 + .../deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol | 38 + contracts/src/v3.0.0-rc3/Groth16Verifier.sol | 578 +++++++ contracts/src/v3.0.0-rc3/PlonkVerifier.sol | 1379 +++++++++++++++++ .../src/v3.0.0-rc3/SP1VerifierGroth16.sol | 57 + contracts/src/v3.0.0-rc3/SP1VerifierPlonk.sol | 59 + src/bin/artifacts.rs | 52 +- 10 files changed, 2339 insertions(+), 480 deletions(-) create mode 100644 contracts/script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol create mode 100644 contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol create mode 100644 contracts/src/v3.0.0-rc3/Groth16Verifier.sol create mode 100644 contracts/src/v3.0.0-rc3/PlonkVerifier.sol create mode 100644 contracts/src/v3.0.0-rc3/SP1VerifierGroth16.sol create mode 100644 contracts/src/v3.0.0-rc3/SP1VerifierPlonk.sol diff --git a/Cargo.lock b/Cargo.lock index 50ea80b..769df1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,7 +131,7 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.5.0", + "indexmap", "proc-macro-error", "proc-macro2", "quote", @@ -167,21 +167,6 @@ dependencies = [ "serde", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "ansi_term" version = "0.12.1" @@ -455,7 +440,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -636,7 +621,6 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "rayon-core", ] [[package]] @@ -768,11 +752,7 @@ version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "android-tzdata", - "iana-time-zone", "num-traits", - "serde", - "windows-targets 0.52.6", ] [[package]] @@ -836,12 +816,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" -[[package]] -name = "cobs" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" - [[package]] name = "coins-bip32" version = "0.8.7" @@ -1057,41 +1031,6 @@ dependencies = [ "syn 2.0.77", ] -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.77", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.77", -] - [[package]] name = "dashu" version = "0.4.2" @@ -1187,7 +1126,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", - "serde", ] [[package]] @@ -1319,18 +1257,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - [[package]] name = "encode_unicode" version = "0.3.6" @@ -1938,10 +1864,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -2016,7 +1940,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.5.0", + "indexmap", "slab", "tokio", "tokio-util", @@ -2035,7 +1959,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.5.0", + "indexmap", "slab", "tokio", "tokio-util", @@ -2065,12 +1989,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.5" @@ -2264,6 +2182,19 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.30", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -2295,40 +2226,11 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", + "tower 0.4.13", "tower-service", "tracing", ] -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "0.5.0" @@ -2383,17 +2285,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - [[package]] name = "indexmap" version = "2.5.0" @@ -2401,8 +2292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown 0.14.5", - "serde", + "hashbrown", ] [[package]] @@ -2659,7 +2549,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" dependencies = [ - "hashbrown 0.14.5", + "hashbrown", ] [[package]] @@ -2962,12 +2852,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "oneshot" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29" - [[package]] name = "open-fastrlp" version = "0.1.4" @@ -3051,9 +2935,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "p3-air" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e909ef66fa5d77ff0fd3cb5af4b33b27fa6fb68d02b9b1e70edbc29383e565" +checksum = "066f571b2e645505ed5972dd0e1e252ba03352150830c9566769ca711c0f1e9b" dependencies = [ "p3-field", "p3-matrix", @@ -3061,9 +2945,9 @@ dependencies = [ [[package]] name = "p3-baby-bear" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46965470aac1cddfe52f535424b59d52f2fffef0fdeb9dbed19da39b1d8f048a" +checksum = "ff00f571044d299310d9659c6e51c98422de3bf94b8577f7f30cf59cf2043e40" dependencies = [ "num-bigint 0.4.6", "p3-field", @@ -3076,9 +2960,9 @@ dependencies = [ [[package]] name = "p3-blake3" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ef32d6ea21dd5cf9fec8a31bf0c64e6ceee8901dbf50966b83a443093c2aba" +checksum = "cc4cb69ae54a279bbbd477566d1bdb71aa879b528fd658d0fcfc36f54b00217c" dependencies = [ "blake3", "p3-symmetric", @@ -3086,9 +2970,9 @@ dependencies = [ [[package]] name = "p3-bn254-fr" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3edfca6be3b3109adf8e3330baec30c3fc5f9f4d63d27aaec1b471ca51ed67" +checksum = "bf19917f986d45e9abb6d177e875824ced6eed096480d574fce16f2c45c721ea" dependencies = [ "ff 0.13.0", "num-bigint 0.4.6", @@ -3101,25 +2985,27 @@ dependencies = [ [[package]] name = "p3-challenger" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6662ea899a5d848b60c699944491d72757873b5e1fd46798e4712f90a03a4e9" +checksum = "3be7e4fbce4566a93091107eadfafa0b5374bd1ffd3e0f6b850da3ff72eb183f" dependencies = [ "p3-field", "p3-maybe-rayon", "p3-symmetric", "p3-util", + "serde", "tracing", ] [[package]] name = "p3-commit" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3563918b5cc44ef5280bf9b51753e70dc78802de25e3fb81ed6c94617ccb6e" +checksum = "7a03eb0f99d68a712c41e658e9a7782a0705d4ffcfb6232a43bd3f1ef9591002" dependencies = [ "itertools 0.12.1", "p3-challenger", + "p3-dft", "p3-field", "p3-matrix", "p3-util", @@ -3128,9 +3014,9 @@ dependencies = [ [[package]] name = "p3-dft" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510095701819d83c9509fe825bbf1ebfe50426ae75149df5fe1dcfd18261323a" +checksum = "1556de968523fbe5d804ab50600ea306fcceea3500cfd7601e40882480524664" dependencies = [ "p3-field", "p3-matrix", @@ -3141,9 +3027,9 @@ dependencies = [ [[package]] name = "p3-field" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f1977a0a65789f719aa824119c332c4676b000bdbfe94d312fb6244a70d601" +checksum = "cec2af6e1ac47a2035af5165e668d64612c4b9ccabd06df37fc1fd381fdf8a71" dependencies = [ "itertools 0.12.1", "num-bigint 0.4.6", @@ -3155,9 +3041,9 @@ dependencies = [ [[package]] name = "p3-fri" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22ddb958f200d9289cc73ff68847b0167ca0c14557b791dd9e318f98c2d1b28" +checksum = "f351ee9f9d4256455164565cd91e3e6d2487cc2a5355515fa2b6d479269188dd" dependencies = [ "itertools 0.12.1", "p3-challenger", @@ -3174,30 +3060,20 @@ dependencies = [ [[package]] name = "p3-interpolation" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d032cda212f6b408d7d5b0b9a8270a9455acb93742fe55a0880d82be8e90e500" +checksum = "d24d0f2907a374ebe4545fcff3120d6376d9630cf0bef30feedcfc5908ea2c37" dependencies = [ "p3-field", "p3-matrix", "p3-util", ] -[[package]] -name = "p3-keccak" -version = "0.1.3-succinct" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c56abdd5a8a780049d2f8e92cea1df57b55a2ef50a40d1103f2732f7a00e4b1" -dependencies = [ - "p3-symmetric", - "tiny-keccak", -] - [[package]] name = "p3-keccak-air" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8398f1694ccc38513df0b8cab5f9ef7325423f27cd9e4fa20bdc77d5079cf1b" +checksum = "e66badd47cedf6570e91a0cabc389b80dfd53ba1a6e9a45a3923fd54b86122ff" dependencies = [ "p3-air", "p3-field", @@ -3205,15 +3081,13 @@ dependencies = [ "p3-maybe-rayon", "p3-util", "tracing", - "tracing-forest", - "tracing-subscriber", ] [[package]] name = "p3-matrix" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d548ee0b834f8e2ebc5037073acd101a3b0ca41a2d1d28a15ba0ccd9059495b0" +checksum = "fa272f3ae77ed8d73478aa7c89e712efb15bda3ff4aff10fadfe11a012cd5389" dependencies = [ "itertools 0.12.1", "p3-field", @@ -3226,18 +3100,18 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f5575d3d61bedb3e05681abb0f36b8bb339d65aa395d50756bfa64e9cd3f46" +checksum = "3eecad6292021858f282d643d9d1284ab112a200494d589863a9c4080e578ef0" dependencies = [ "rayon", ] [[package]] name = "p3-mds" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6e57ed310d59245f93e24ee805ea7aa16fc9c505551b76a15f5e50f29d177e" +checksum = "716c4dbe68a02f1541eb09149d07b8663a3a5951b1864a31cd67ff3bb0826e57" dependencies = [ "itertools 0.12.1", "p3-dft", @@ -3250,9 +3124,9 @@ dependencies = [ [[package]] name = "p3-merkle-tree" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af46b41cba75d483ec8a553cbab1d2d794935ae3403d75394acfa4fb2c977cce" +checksum = "ad7ebab52a03c26025988663a135aed62f5084a2e2ea262176dc8748efb593e5" dependencies = [ "itertools 0.12.1", "p3-commit", @@ -3267,22 +3141,23 @@ dependencies = [ [[package]] name = "p3-poseidon2" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adaba6f14c197203530e233badce0ca1126ba3bf3c9ff766505b497bdad0bee1" +checksum = "39c042efa15beab7a8c4d0ca9b9e4cbda7582be0c08e121e830fec45f082935b" dependencies = [ "gcd", "p3-field", "p3-mds", "p3-symmetric", "rand", + "serde", ] [[package]] name = "p3-symmetric" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ecc4282566eb14f48be7707f6745c4dff6be664984d59ec0fb1849cd82b5c2" +checksum = "b9896a831f5b688adc13f6fbe1dcf66ecfaa4622a500f81aa745610e777acb72" dependencies = [ "itertools 0.12.1", "p3-field", @@ -3291,9 +3166,9 @@ dependencies = [ [[package]] name = "p3-uni-stark" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1af5c038b22b058bf1d49fb1ea3dd6c240a3e46c3278fde5c444e0034f7ffe37" +checksum = "8437ebcd060c8a5479898030b114a93da8a86eb4c2e5f313d9eeaaf40c6e6f61" dependencies = [ "itertools 0.12.1", "p3-air", @@ -3304,18 +3179,15 @@ dependencies = [ "p3-matrix", "p3-maybe-rayon", "p3-util", - "postcard", "serde", "tracing", - "tracing-forest", - "tracing-subscriber", ] [[package]] name = "p3-util" -version = "0.1.3-succinct" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79f3fef0e00d9d7246385e758c4cd39b4efcbbcea31752471491ab502631385e" +checksum = "dedb9d27ba47ac314c6fac4ca54e55c3e486c864d51ec5ba55dbe47b75121157" dependencies = [ "serde", ] @@ -3523,18 +3395,6 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" -[[package]] -name = "postcard" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -3648,9 +3508,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.6" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", "prost-derive", @@ -3658,26 +3518,17 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.6" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.77", ] -[[package]] -name = "psm" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" -dependencies = [ - "cc", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -3894,19 +3745,23 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", "system-configuration 0.5.1", "tokio", + "tokio-native-tls", "tower-service", "url", "wasm-bindgen", @@ -3932,7 +3787,7 @@ dependencies = [ "http-body-util", "hyper 1.4.1", "hyper-rustls", - "hyper-tls", + "hyper-tls 0.6.0", "hyper-util", "ipnet", "js-sys", @@ -3944,7 +3799,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-pemfile", + "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", "serde_json", @@ -4161,6 +4016,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pemfile" version = "2.1.3" @@ -4435,36 +4299,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.5.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "serial_test" version = "3.1.1" @@ -4620,31 +4454,27 @@ dependencies = [ [[package]] name = "sp1-core-executor" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930d18a62671763334d40f610c22947e3ebbb65b2407dad3c4797d69ddc63504" +checksum = "4bcf4d12fdcdb59632dbb8491e9f1ed5090de774b46cb5ef26ce5fcd4d024e3e" dependencies = [ "bincode", "bytemuck", "elf", "enum-map", "eyre", - "generic-array 1.1.0", - "hashbrown 0.14.5", + "hashbrown", "hex", "itertools 0.13.0", "log", "nohash-hasher", "num", "p3-field", - "p3-keccak-air", "p3-maybe-rayon", "rand", "rrs-succinct", "serde", - "serde_with", "sp1-curves", - "sp1-derive", "sp1-primitives", "sp1-stark", "strum", @@ -4658,51 +4488,33 @@ dependencies = [ [[package]] name = "sp1-core-machine" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b204c89ac15554342f93cfa1b15f162e86abfb25eaa64f54213471edb9d1446c" +checksum = "0a6f7b232d011a2db7a314d53ee37ef79e60c2e282e4c249c9b91041e4ff88ec" dependencies = [ - "anyhow", - "arrayref", "bincode", - "blake3", - "bytemuck", "cfg-if", - "curve25519-dalek", - "elf", "elliptic-curve", "generic-array 1.1.0", - "hashbrown 0.14.5", + "hashbrown", "hex", "itertools 0.13.0", "k256", "log", - "nohash-hasher", "num", - "num-bigint 0.4.6", "num_cpus", "p3-air", "p3-baby-bear", "p3-blake3", "p3-challenger", - "p3-commit", - "p3-dft", "p3-field", - "p3-fri", - "p3-keccak", "p3-keccak-air", "p3-matrix", "p3-maybe-rayon", - "p3-merkle-tree", - "p3-poseidon2", - "p3-symmetric", "p3-uni-stark", "p3-util", "rand", - "rayon-scan", - "rrs-succinct", "serde", - "serde_with", "size", "snowbridge-amcl", "sp1-core-executor", @@ -4724,10 +4536,11 @@ dependencies = [ [[package]] name = "sp1-curves" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93de9945823c2607929212519d88d28ca03256ce9c9720f35aa43127a388489" +checksum = "c1c2c7fb1a24a9dcd06ffc26c4377056163cba55d47b973b19eec81442217f57" dependencies = [ + "cfg-if", "curve25519-dalek", "dashu", "elliptic-curve", @@ -4745,60 +4558,65 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4804a7b60abc3e55a3c4ff919bac3b81a4ce3162552f8ca76dc9d2b9211f0348" +checksum = "1d6c88b3e7ead9192679bf2ef5b0c28b6e7b9a56f929bd76851820e5e5b947bb" dependencies = [ - "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "sp1-primitives" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4ed9076a2951a76944f33888f2cd62b9b16005f692e4cc983a14c1eb4d81f5" +checksum = "2567220b2d8170a0c42eba514dec66b76c5c87927c9a3232ee53a56310acee72" dependencies = [ - "itertools 0.13.0", + "bincode", + "hex", "lazy_static", + "num-bigint 0.4.6", "p3-baby-bear", "p3-field", "p3-poseidon2", "p3-symmetric", + "serde", + "sha2", ] [[package]] name = "sp1-prover" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f139f34954057edb219ee0853e367b67939936ba311b87b6af5112972463d04" +checksum = "cb59f305b4768a441049f46bc52e0d1edfd2d3179d65a3440f7396baa74e1bda" dependencies = [ "anyhow", "bincode", "clap", "dirs", - "hex", + "eyre", "itertools 0.13.0", + "lazy_static", "lru", "num-bigint 0.4.6", - "oneshot", "p3-baby-bear", "p3-bn254-fr", "p3-challenger", "p3-commit", "p3-field", "p3-matrix", + "p3-symmetric", "rayon", + "reqwest 0.11.27", "serde", "serde_json", "serial_test", "sp1-core-executor", "sp1-core-machine", "sp1-primitives", - "sp1-recursion-circuit-v2", + "sp1-recursion-circuit", "sp1-recursion-compiler", - "sp1-recursion-core-v2", + "sp1-recursion-core", "sp1-recursion-gnark-ffi", "sp1-stark", "subtle-encoding", @@ -4810,38 +4628,13 @@ dependencies = [ [[package]] name = "sp1-recursion-circuit" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a3f58ee42f62cf6b25f7f1d55bdff58c0932a35c42c4483db92e5cef99edd51" +checksum = "e08f45e8fa3caf412251a730cdad04b36285e745a6c1b409d865bae3338a5196" dependencies = [ - "bincode", - "itertools 0.13.0", - "p3-air", - "p3-baby-bear", - "p3-bn254-fr", - "p3-commit", - "p3-field", - "p3-fri", - "p3-matrix", - "p3-util", - "serde", - "sp1-core-machine", - "sp1-recursion-compiler", - "sp1-recursion-core", - "sp1-recursion-derive", - "sp1-recursion-program", - "sp1-stark", -] - -[[package]] -name = "sp1-recursion-circuit-v2" -version = "3.0.0-rc1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff652584d89e6c5df6205a78d535fad80b470df7f14e557b0199689692759ec" -dependencies = [ - "bincode", - "hashbrown 0.14.5", + "hashbrown", "itertools 0.13.0", + "num-traits", "p3-air", "p3-baby-bear", "p3-bn254-fr", @@ -4851,51 +4644,38 @@ dependencies = [ "p3-field", "p3-fri", "p3-matrix", - "p3-maybe-rayon", - "p3-merkle-tree", - "p3-poseidon2", "p3-symmetric", "p3-util", "rand", + "rayon", "serde", "sp1-core-executor", "sp1-core-machine", + "sp1-derive", "sp1-primitives", - "sp1-recursion-circuit", "sp1-recursion-compiler", - "sp1-recursion-core-v2", - "sp1-recursion-derive", + "sp1-recursion-core", "sp1-recursion-gnark-ffi", - "sp1-recursion-program", "sp1-stark", - "stacker", "tracing", ] [[package]] name = "sp1-recursion-compiler" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b5dc96969935264cf7cc666feb0b387ff80547492ac0bf309ee3bcf43aad97" +checksum = "648941453ab9e8c69386df5cd660dedabe4d06c041450d8a2548ba6cefa6ed45" dependencies = [ "backtrace", "itertools 0.13.0", - "p3-air", "p3-baby-bear", "p3-bn254-fr", - "p3-commit", "p3-field", - "p3-fri", - "p3-matrix", - "p3-poseidon2", "p3-symmetric", - "p3-util", - "rayon", "serde", "sp1-core-machine", "sp1-primitives", "sp1-recursion-core", - "sp1-recursion-core-v2", "sp1-recursion-derive", "sp1-stark", "tracing", @@ -4904,54 +4684,14 @@ dependencies = [ [[package]] name = "sp1-recursion-core" -version = "3.0.0-rc1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53a40c98a1ec05530eed56077f2adb18aaeeb4af757a247843340d3455e5006" -dependencies = [ - "arrayref", - "backtrace", - "ff 0.13.0", - "hashbrown 0.14.5", - "itertools 0.13.0", - "num_cpus", - "p3-air", - "p3-baby-bear", - "p3-bn254-fr", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-fri", - "p3-matrix", - "p3-maybe-rayon", - "p3-merkle-tree", - "p3-poseidon2", - "p3-symmetric", - "p3-util", - "serde", - "serde_with", - "sp1-core-executor", - "sp1-core-machine", - "sp1-derive", - "sp1-primitives", - "sp1-stark", - "static_assertions", - "tracing", - "zkhash", -] - -[[package]] -name = "sp1-recursion-core-v2" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41e8f51f729f95d45fee6e6e9cf6521ec50e2e2d8e453df4ef56f97bd570348" +checksum = "faf8c5dc0a2c33ef1dc7da7a137574e4f1783e45489681ca01aa3309abc6adee" dependencies = [ - "arrayref", "backtrace", "ff 0.13.0", - "hashbrown 0.14.5", + "hashbrown", "itertools 0.13.0", - "num_cpus", "p3-air", "p3-baby-bear", "p3-bn254-fr", @@ -4967,12 +4707,9 @@ dependencies = [ "p3-symmetric", "p3-util", "serde", - "serde_with", - "sp1-core-executor", "sp1-core-machine", "sp1-derive", "sp1-primitives", - "sp1-recursion-core", "sp1-stark", "static_assertions", "thiserror", @@ -4983,20 +4720,19 @@ dependencies = [ [[package]] name = "sp1-recursion-derive" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "922b5ee37c72693c8e309a812f555fc2afbf090d38715989f4c255ab5e36fa47" +checksum = "a7807dc1a72bb7b86f2e82c414cb58b9789d880ca459b2113f7406df814945ae" dependencies = [ - "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "sp1-recursion-gnark-ffi" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c830f46fbefa380baf9377cc693f952af5b28d9359bba562298227b0c7df462f" +checksum = "bff667dda92cbe2f9382e36fe222641f60a4e794e0a3b6c7597cd6a74d79262d" dependencies = [ "anyhow", "bincode", @@ -5009,7 +4745,6 @@ dependencies = [ "p3-baby-bear", "p3-field", "p3-symmetric", - "rand", "serde", "serde_json", "sha2", @@ -5019,43 +4754,11 @@ dependencies = [ "tempfile", ] -[[package]] -name = "sp1-recursion-program" -version = "3.0.0-rc1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9810e506813c71fbcf665e1347adffcb35aa52b99248067601a8a18c9565744" -dependencies = [ - "itertools 0.13.0", - "p3-air", - "p3-baby-bear", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-fri", - "p3-matrix", - "p3-maybe-rayon", - "p3-merkle-tree", - "p3-poseidon2", - "p3-symmetric", - "p3-util", - "rand", - "serde", - "sp1-core-executor", - "sp1-core-machine", - "sp1-primitives", - "sp1-recursion-compiler", - "sp1-recursion-core", - "sp1-stark", - "stacker", - "tracing", -] - [[package]] name = "sp1-sdk" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee3d7cd459f6503ae0929b16bb9c1514dd63fade2ec7e9fb47dd5a2d9decda6" +checksum = "df9a960e85019f30d96a2269bb2faa4982fbc0af784bc7c5998ae5d8ee2ea033" dependencies = [ "alloy-sol-types", "anyhow", @@ -5065,30 +4768,25 @@ dependencies = [ "dirs", "ethers", "futures", - "getrandom", - "hashbrown 0.14.5", + "hashbrown", "hex", "indicatif", + "itertools 0.13.0", "log", - "num-bigint 0.4.6", "p3-baby-bear", - "p3-commit", "p3-field", "p3-fri", - "p3-matrix", "prost", "reqwest 0.12.7", "reqwest-middleware", "serde", - "serde_json", - "sha2", "sp1-core-executor", "sp1-core-machine", + "sp1-primitives", "sp1-prover", "sp1-stark", "strum", "strum_macros", - "sysinfo", "tempfile", "thiserror", "tokio", @@ -5099,14 +4797,15 @@ dependencies = [ [[package]] name = "sp1-stark" -version = "3.0.0-rc1" +version = "3.0.0-rc3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "371c3681bebcdf23ec7c76bb20af184b0051a2f5b43d2f4056ff79d9674734cb" +checksum = "ba8706930d1d65aa645d194b175f6c4c0f47ac7833640b4f46cf4da5964d2d1d" dependencies = [ "arrayref", "getrandom", - "hashbrown 0.14.5", + "hashbrown", "itertools 0.13.0", + "num-traits", "p3-air", "p3-baby-bear", "p3-challenger", @@ -5125,7 +4824,10 @@ dependencies = [ "serde", "sp1-derive", "sp1-primitives", + "strum", + "strum_macros", "sysinfo", + "thiserror", "tracing", ] @@ -5151,19 +4853,6 @@ dependencies = [ "der", ] -[[package]] -name = "stacker" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" -dependencies = [ - "cc", - "cfg-if", - "libc", - "psm", - "windows-sys 0.59.0", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -5340,18 +5029,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", @@ -5515,7 +5204,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.5.0", + "indexmap", "toml_datetime", "winnow 0.5.40", ] @@ -5526,7 +5215,7 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.5.0", + "indexmap", "serde", "serde_spanned", "toml_datetime", @@ -5549,6 +5238,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -5654,13 +5353,12 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "twirp-rs" -version = "0.3.0" +version = "0.13.0-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa3161d8eee0abcad4e762f4215381a430cc1281870d575b0f1e4fbfc74b8ce" +checksum = "27dfcc06b8d9262bc2d4b8d1847c56af9971a52dd8a0076876de9db763227d0d" dependencies = [ "async-trait", "axum", - "bytes", "futures", "http 1.1.0", "http-body-util", @@ -5671,7 +5369,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tower", + "tower 0.5.1", "url", ] diff --git a/Cargo.toml b/Cargo.toml index d2eda87..f8a700d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,4 @@ path = "src/bin/artifacts.rs" anyhow = "1.0.86" dotenv = "0.15.0" log = "0.4.21" -sp1-sdk = "3.0.0-rc1" \ No newline at end of file +sp1-sdk = "3.0.0-rc3" \ No newline at end of file diff --git a/UPDATE_CONTRACTS.md b/UPDATE_CONTRACTS.md index c2c727e..dad7da1 100644 --- a/UPDATE_CONTRACTS.md +++ b/UPDATE_CONTRACTS.md @@ -1,14 +1,12 @@ - # Update SP1 Contracts with New SP1 Version This section outlines the steps required to update the SP1 contracts repository with a new SP1 version. Follow these instructions to ensure the SP1 contracts are correctly updated and aligned with the latest version. - 1. Change the version tag in `Cargo.toml` to the target `sp1` version. ```toml [dependencies] -sp1-sdk = { git = "https://github.com/succinctlabs/sp1", tag = "" } +sp1-sdk = "" ``` 2. Update `contracts/src` with the new verifier contracts. @@ -23,5 +21,5 @@ cargo run --bin artifacts --release 4. After merging to `main`, create a release tag with the same version as the `sp1` tag used. ## Miscellaneous -The SP1 Solidity contract artifacts are included in each release of `sp1`. You can see how these are included in the `sp1` repository [here](https://github.com/succinctlabs/sp1/blob/21455d318ae383b317c92e10709bbfc313d8f1df/recursion/gnark-ffi/src/plonk_bn254.rs#L57-L96). +The SP1 Solidity contract artifacts are included in each release of `sp1`. You can see how these are included in the `sp1` repository [here](https://github.com/succinctlabs/sp1/blob/21455d318ae383b317c92e10709bbfc313d8f1df/recursion/gnark-ffi/src/plonk_bn254.rs#L57-L96). diff --git a/contracts/script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol b/contracts/script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol new file mode 100644 index 0000000..e307f3d --- /dev/null +++ b/contracts/script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {BaseScript} from "../../utils/Base.s.sol"; +import {SP1Verifier} from "../../../src/v3.0.0-rc1/SP1VerifierGroth16.sol"; +import {SP1VerifierGateway} from "../../../src/SP1VerifierGateway.sol"; +import {ISP1VerifierWithHash} from "../../../src/ISP1Verifier.sol"; + +contract SP1VerifierScript is BaseScript { + string internal constant KEY = "V3_0_0_RC3_SP1_VERIFIER_GROTH16"; + + function run() external multichain(KEY) broadcaster { + // Read config + bytes32 CREATE2_SALT = readBytes32("CREATE2_SALT"); + address SP1_VERIFIER_GATEWAY = readAddress("SP1_VERIFIER_GATEWAY"); + + // Deploy contract + address verifier = address(new SP1Verifier{salt: CREATE2_SALT}()); + + // Add the verifier to the gateway + SP1VerifierGateway gateway = SP1VerifierGateway(SP1_VERIFIER_GATEWAY); + gateway.addRoute(verifier); + + // Write address + writeAddress(KEY, verifier); + } + + function freeze() external multichain(KEY) broadcaster { + // Read config + address SP1_VERIFIER_GATEWAY = readAddress("SP1_VERIFIER_GATEWAY"); + address SP1_VERIFIER = readAddress(KEY); + + // Freeze the verifier on the gateway + SP1VerifierGateway gateway = SP1VerifierGateway(SP1_VERIFIER_GATEWAY); + bytes4 selector = bytes4(ISP1VerifierWithHash(SP1_VERIFIER).VERIFIER_HASH()); + gateway.freezeRoute(selector); + } +} diff --git a/contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol b/contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol new file mode 100644 index 0000000..5d4c8f0 --- /dev/null +++ b/contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {BaseScript} from "../../utils/Base.s.sol"; +import {SP1Verifier} from "../../../src/v3.0.0-rc1/SP1VerifierPlonk.sol"; +import {SP1VerifierGateway} from "../../../src/SP1VerifierGateway.sol"; +import {ISP1VerifierWithHash} from "../../../src/ISP1Verifier.sol"; + +contract SP1VerifierScript is BaseScript { + string internal constant KEY = "V3_0_0_RC3_SP1_VERIFIER_PLONK"; + + function run() external multichain(KEY) broadcaster { + // Read config + bytes32 CREATE2_SALT = readBytes32("CREATE2_SALT"); + address SP1_VERIFIER_GATEWAY = readAddress("SP1_VERIFIER_GATEWAY"); + + // Deploy contract + address verifier = address(new SP1Verifier{salt: CREATE2_SALT}()); + + // Add the verifier to the gateway + SP1VerifierGateway gateway = SP1VerifierGateway(SP1_VERIFIER_GATEWAY); + gateway.addRoute(verifier); + + // Write address + writeAddress(KEY, verifier); + } + + function freeze() external multichain(KEY) broadcaster { + // Read config + address SP1_VERIFIER_GATEWAY = readAddress("SP1_VERIFIER_GATEWAY"); + address SP1_VERIFIER = readAddress(KEY); + + // Freeze the verifier on the gateway + SP1VerifierGateway gateway = SP1VerifierGateway(SP1_VERIFIER_GATEWAY); + bytes4 selector = bytes4(ISP1VerifierWithHash(SP1_VERIFIER).VERIFIER_HASH()); + gateway.freezeRoute(selector); + } +} diff --git a/contracts/src/v3.0.0-rc3/Groth16Verifier.sol b/contracts/src/v3.0.0-rc3/Groth16Verifier.sol new file mode 100644 index 0000000..50e3e8d --- /dev/null +++ b/contracts/src/v3.0.0-rc3/Groth16Verifier.sol @@ -0,0 +1,578 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +/// @title Groth16 verifier template. +/// @author Remco Bloemen +/// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed +/// (256 bytes) and compressed (128 bytes) format. A view function is provided +/// to compress proofs. +/// @notice See for further explanation. +contract Groth16Verifier { + /// Some of the provided public input values are larger than the field modulus. + /// @dev Public input elements are not automatically reduced, as this is can be + /// a dangerous source of bugs. + error PublicInputNotInField(); + + /// The proof is invalid. + /// @dev This can mean that provided Groth16 proof points are not on their + /// curves, that pairing equation fails, or that the proof is not for the + /// provided public input. + error ProofInvalid(); + + // Addresses of precompiles + uint256 constant PRECOMPILE_MODEXP = 0x05; + uint256 constant PRECOMPILE_ADD = 0x06; + uint256 constant PRECOMPILE_MUL = 0x07; + uint256 constant PRECOMPILE_VERIFY = 0x08; + + // Base field Fp order P and scalar field Fr order R. + // For BN254 these are computed as follows: + // t = 4965661367192848881 + // P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1 + // R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1 + uint256 constant P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47; + uint256 constant R = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001; + + // Extension field Fp2 = Fp[i] / (i² + 1) + // Note: This is the complex extension field of Fp with i² = -1. + // Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i. + // Note: The order of Fp2 elements is *opposite* that of the pairing contract, which + // expects Fp2 elements in order (a₁, a₀). This is also the order in which + // Fp2 elements are encoded in the public interface as this became convention. + + // Constants in Fp + uint256 constant FRACTION_1_2_FP = + 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea4; + uint256 constant FRACTION_27_82_FP = + 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5; + uint256 constant FRACTION_3_82_FP = + 0x2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775; + + // Exponents for inversions and square roots mod P + uint256 constant EXP_INVERSE_FP = + 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2 + uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4; + + // Groth16 alpha point in G1 + uint256 constant ALPHA_X = + 21733119224899173617056606073001209533825019254172681255018802217793864566820; + uint256 constant ALPHA_Y = + 11899216843110560933934607660236564396890568243613476007907387823822495310001; + + // Groth16 beta point in G2 in powers of i + uint256 constant BETA_NEG_X_0 = + 12559408596491730037860352119269676613335171522660987383680214016857693557230; + uint256 constant BETA_NEG_X_1 = + 6408967506583980541938799224962156676369977952609826464679972952840827472518; + uint256 constant BETA_NEG_Y_0 = + 875623757141576192530842037471879386918015575772628778759041964858399489198; + uint256 constant BETA_NEG_Y_1 = + 6957573551963196984096568743157308265301844219831209362110450250618379560886; + + // Groth16 gamma point in G2 in powers of i + uint256 constant GAMMA_NEG_X_0 = + 13126155139452209858331167586209047810573130177413568760191043234305594450448; + uint256 constant GAMMA_NEG_X_1 = + 4718167903367214038708599594507147575530522693102002967814831717551827126207; + uint256 constant GAMMA_NEG_Y_0 = + 12474210604018540363464302091763530505080030087260936402162186715427160029630; + uint256 constant GAMMA_NEG_Y_1 = + 19057457579881782703930765785468081435968711077480176316324668190746909123963; + + // Groth16 delta point in G2 in powers of i + uint256 constant DELTA_NEG_X_0 = + 13633347496941505736725947091948267218127997268498788288021123721126616826803; + uint256 constant DELTA_NEG_X_1 = + 10853896149897886508956650897535398694071781224445187823115781128531286242948; + uint256 constant DELTA_NEG_Y_0 = + 9523090161075614249622308966999035777867723859322410794384092560791306712333; + uint256 constant DELTA_NEG_Y_1 = + 13600611586617908782777925479575903312299140050884429522713225837342923237385; + + // Constant and public input points + uint256 constant CONSTANT_X = + 12544738455277509946552917963707361491250317272501480192154250267812639867251; + uint256 constant CONSTANT_Y = + 8287458568190583619117906628856384619270412775992007276185083920330954471725; + uint256 constant PUB_0_X = + 19902416787417869340835891371907154191243403784306143118883112000866175272843; + uint256 constant PUB_0_Y = + 2594481869814415113139164273878772131847992355353116047829559056292428666642; + uint256 constant PUB_1_X = + 20504890532783663083771736073066025639815155114107742156672532874830566497633; + uint256 constant PUB_1_Y = + 2474505186643754364619028319255098785554484865733391543603607059214126652680; + + /// Negation in Fp. + /// @notice Returns a number x such that a + x = 0 in Fp. + /// @notice The input does not need to be reduced. + /// @param a the base + /// @return x the result + function negate(uint256 a) internal pure returns (uint256 x) { + unchecked { + x = (P - (a % P)) % P; // Modulo is cheaper than branching + } + } + + /// Exponentiation in Fp. + /// @notice Returns a number x such that a ^ e = x in Fp. + /// @notice The input does not need to be reduced. + /// @param a the base + /// @param e the exponent + /// @return x the result + function exp(uint256 a, uint256 e) internal view returns (uint256 x) { + bool success; + assembly ("memory-safe") { + let f := mload(0x40) + mstore(f, 0x20) + mstore(add(f, 0x20), 0x20) + mstore(add(f, 0x40), 0x20) + mstore(add(f, 0x60), a) + mstore(add(f, 0x80), e) + mstore(add(f, 0xa0), P) + success := staticcall(gas(), PRECOMPILE_MODEXP, f, 0xc0, f, 0x20) + x := mload(f) + } + if (!success) { + // Exponentiation failed. + // Should not happen. + revert ProofInvalid(); + } + } + + /// Invertsion in Fp. + /// @notice Returns a number x such that a * x = 1 in Fp. + /// @notice The input does not need to be reduced. + /// @notice Reverts with ProofInvalid() if the inverse does not exist + /// @param a the input + /// @return x the solution + function invert_Fp(uint256 a) internal view returns (uint256 x) { + x = exp(a, EXP_INVERSE_FP); + if (mulmod(a, x, P) != 1) { + // Inverse does not exist. + // Can only happen during G2 point decompression. + revert ProofInvalid(); + } + } + + /// Square root in Fp. + /// @notice Returns a number x such that x * x = a in Fp. + /// @notice Will revert with InvalidProof() if the input is not a square + /// or not reduced. + /// @param a the square + /// @return x the solution + function sqrt_Fp(uint256 a) internal view returns (uint256 x) { + x = exp(a, EXP_SQRT_FP); + if (mulmod(x, x, P) != a) { + // Square root does not exist or a is not reduced. + // Happens when G1 point is not on curve. + revert ProofInvalid(); + } + } + + /// Square test in Fp. + /// @notice Returns whether a number x exists such that x * x = a in Fp. + /// @notice Will revert with InvalidProof() if the input is not a square + /// or not reduced. + /// @param a the square + /// @return x the solution + function isSquare_Fp(uint256 a) internal view returns (bool) { + uint256 x = exp(a, EXP_SQRT_FP); + return mulmod(x, x, P) == a; + } + + /// Square root in Fp2. + /// @notice Fp2 is the complex extension Fp[i]/(i^2 + 1). The input is + /// a0 + a1 ⋅ i and the result is x0 + x1 ⋅ i. + /// @notice Will revert with InvalidProof() if + /// * the input is not a square, + /// * the hint is incorrect, or + /// * the input coefficents are not reduced. + /// @param a0 The real part of the input. + /// @param a1 The imaginary part of the input. + /// @param hint A hint which of two possible signs to pick in the equation. + /// @return x0 The real part of the square root. + /// @return x1 The imaginary part of the square root. + function sqrt_Fp2(uint256 a0, uint256 a1, bool hint) + internal + view + returns (uint256 x0, uint256 x1) + { + // If this square root reverts there is no solution in Fp2. + uint256 d = sqrt_Fp(addmod(mulmod(a0, a0, P), mulmod(a1, a1, P), P)); + if (hint) { + d = negate(d); + } + // If this square root reverts there is no solution in Fp2. + x0 = sqrt_Fp(mulmod(addmod(a0, d, P), FRACTION_1_2_FP, P)); + x1 = mulmod(a1, invert_Fp(mulmod(x0, 2, P)), P); + + // Check result to make sure we found a root. + // Note: this also fails if a0 or a1 is not reduced. + if ( + a0 != addmod(mulmod(x0, x0, P), negate(mulmod(x1, x1, P)), P) + || a1 != mulmod(2, mulmod(x0, x1, P), P) + ) { + revert ProofInvalid(); + } + } + + /// Compress a G1 point. + /// @notice Reverts with InvalidProof if the coordinates are not reduced + /// or if the point is not on the curve. + /// @notice The point at infinity is encoded as (0,0) and compressed to 0. + /// @param x The X coordinate in Fp. + /// @param y The Y coordinate in Fp. + /// @return c The compresed point (x with one signal bit). + function compress_g1(uint256 x, uint256 y) internal view returns (uint256 c) { + if (x >= P || y >= P) { + // G1 point not in field. + revert ProofInvalid(); + } + if (x == 0 && y == 0) { + // Point at infinity + return 0; + } + + // Note: sqrt_Fp reverts if there is no solution, i.e. the x coordinate is invalid. + uint256 y_pos = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P)); + if (y == y_pos) { + return (x << 1) | 0; + } else if (y == negate(y_pos)) { + return (x << 1) | 1; + } else { + // G1 point not on curve. + revert ProofInvalid(); + } + } + + /// Decompress a G1 point. + /// @notice Reverts with InvalidProof if the input does not represent a valid point. + /// @notice The point at infinity is encoded as (0,0) and compressed to 0. + /// @param c The compresed point (x with one signal bit). + /// @return x The X coordinate in Fp. + /// @return y The Y coordinate in Fp. + function decompress_g1(uint256 c) internal view returns (uint256 x, uint256 y) { + // Note that X = 0 is not on the curve since 0³ + 3 = 3 is not a square. + // so we can use it to represent the point at infinity. + if (c == 0) { + // Point at infinity as encoded in EIP196 and EIP197. + return (0, 0); + } + bool negate_point = c & 1 == 1; + x = c >> 1; + if (x >= P) { + // G1 x coordinate not in field. + revert ProofInvalid(); + } + + // Note: (x³ + 3) is irreducible in Fp, so it can not be zero and therefore + // y can not be zero. + // Note: sqrt_Fp reverts if there is no solution, i.e. the point is not on the curve. + y = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P)); + if (negate_point) { + y = negate(y); + } + } + + /// Compress a G2 point. + /// @notice Reverts with InvalidProof if the coefficients are not reduced + /// or if the point is not on the curve. + /// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1) + /// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i). + /// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0). + /// @param x0 The real part of the X coordinate. + /// @param x1 The imaginary poart of the X coordinate. + /// @param y0 The real part of the Y coordinate. + /// @param y1 The imaginary part of the Y coordinate. + /// @return c0 The first half of the compresed point (x0 with two signal bits). + /// @return c1 The second half of the compressed point (x1 unmodified). + function compress_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1) + internal + view + returns (uint256 c0, uint256 c1) + { + if (x0 >= P || x1 >= P || y0 >= P || y1 >= P) { + // G2 point not in field. + revert ProofInvalid(); + } + if ((x0 | x1 | y0 | y1) == 0) { + // Point at infinity + return (0, 0); + } + + // Compute y^2 + // Note: shadowing variables and scoping to avoid stack-to-deep. + uint256 y0_pos; + uint256 y1_pos; + { + uint256 n3ab = mulmod(mulmod(x0, x1, P), P - 3, P); + uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P); + uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P); + y0_pos = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P); + y1_pos = negate(addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P)); + } + + // Determine hint bit + // If this sqrt fails the x coordinate is not on the curve. + bool hint; + { + uint256 d = sqrt_Fp(addmod(mulmod(y0_pos, y0_pos, P), mulmod(y1_pos, y1_pos, P), P)); + hint = !isSquare_Fp(mulmod(addmod(y0_pos, d, P), FRACTION_1_2_FP, P)); + } + + // Recover y + (y0_pos, y1_pos) = sqrt_Fp2(y0_pos, y1_pos, hint); + if (y0 == y0_pos && y1 == y1_pos) { + c0 = (x0 << 2) | (hint ? 2 : 0) | 0; + c1 = x1; + } else if (y0 == negate(y0_pos) && y1 == negate(y1_pos)) { + c0 = (x0 << 2) | (hint ? 2 : 0) | 1; + c1 = x1; + } else { + // G1 point not on curve. + revert ProofInvalid(); + } + } + + /// Decompress a G2 point. + /// @notice Reverts with InvalidProof if the input does not represent a valid point. + /// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1) + /// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i). + /// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0). + /// @param c0 The first half of the compresed point (x0 with two signal bits). + /// @param c1 The second half of the compressed point (x1 unmodified). + /// @return x0 The real part of the X coordinate. + /// @return x1 The imaginary poart of the X coordinate. + /// @return y0 The real part of the Y coordinate. + /// @return y1 The imaginary part of the Y coordinate. + function decompress_g2(uint256 c0, uint256 c1) + internal + view + returns (uint256 x0, uint256 x1, uint256 y0, uint256 y1) + { + // Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square. + // so we can use it to represent the point at infinity. + if (c0 == 0 && c1 == 0) { + // Point at infinity as encoded in EIP197. + return (0, 0, 0, 0); + } + bool negate_point = c0 & 1 == 1; + bool hint = c0 & 2 == 2; + x0 = c0 >> 2; + x1 = c1; + if (x0 >= P || x1 >= P) { + // G2 x0 or x1 coefficient not in field. + revert ProofInvalid(); + } + + uint256 n3ab = mulmod(mulmod(x0, x1, P), P - 3, P); + uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P); + uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P); + + y0 = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P); + y1 = negate(addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P)); + + // Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve. + // Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero. + // But y0 or y1 may still independently be zero. + (y0, y1) = sqrt_Fp2(y0, y1, hint); + if (negate_point) { + y0 = negate(y0); + y1 = negate(y1); + } + } + + /// Compute the public input linear combination. + /// @notice Reverts with PublicInputNotInField if the input is not in the field. + /// @notice Computes the multi-scalar-multiplication of the public input + /// elements and the verification key including the constant term. + /// @param input The public inputs. These are elements of the scalar field Fr. + /// @return x The X coordinate of the resulting G1 point. + /// @return y The Y coordinate of the resulting G1 point. + function publicInputMSM(uint256[2] calldata input) + internal + view + returns (uint256 x, uint256 y) + { + // Note: The ECMUL precompile does not reject unreduced values, so we check this. + // Note: Unrolling this loop does not cost much extra in code-size, the bulk of the + // code-size is in the PUB_ constants. + // ECMUL has input (x, y, scalar) and output (x', y'). + // ECADD has input (x1, y1, x2, y2) and output (x', y'). + // We reduce commitments(if any) with constants as the first point argument to ECADD. + // We call them such that ecmul output is already in the second point + // argument to ECADD so we can have a tight loop. + bool success = true; + assembly ("memory-safe") { + let f := mload(0x40) + let g := add(f, 0x40) + let s + mstore(f, CONSTANT_X) + mstore(add(f, 0x20), CONSTANT_Y) + mstore(g, PUB_0_X) + mstore(add(g, 0x20), PUB_0_Y) + s := calldataload(input) + mstore(add(g, 0x40), s) + success := and(success, lt(s, R)) + success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) + success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) + mstore(g, PUB_1_X) + mstore(add(g, 0x20), PUB_1_Y) + s := calldataload(add(input, 32)) + mstore(add(g, 0x40), s) + success := and(success, lt(s, R)) + success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) + success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) + + x := mload(f) + y := mload(add(f, 0x20)) + } + if (!success) { + // Either Public input not in field, or verification key invalid. + // We assume the contract is correctly generated, so the verification key is valid. + revert PublicInputNotInField(); + } + } + + /// Compress a proof. + /// @notice Will revert with InvalidProof if the curve points are invalid, + /// but does not verify the proof itself. + /// @param proof The uncompressed Groth16 proof. Elements are in the same order as for + /// verifyProof. I.e. Groth16 points (A, B, C) encoded as in EIP-197. + /// @return compressed The compressed proof. Elements are in the same order as for + /// verifyCompressedProof. I.e. points (A, B, C) in compressed format. + function compressProof(uint256[8] calldata proof) + public + view + returns (uint256[4] memory compressed) + { + compressed[0] = compress_g1(proof[0], proof[1]); + (compressed[2], compressed[1]) = compress_g2(proof[3], proof[2], proof[5], proof[4]); + compressed[3] = compress_g1(proof[6], proof[7]); + } + + /// Verify a Groth16 proof with compressed points. + /// @notice Reverts with InvalidProof if the proof is invalid or + /// with PublicInputNotInField the public input is not reduced. + /// @notice There is no return value. If the function does not revert, the + /// proof was successfully verified. + /// @param compressedProof the points (A, B, C) in compressed format + /// matching the output of compressProof. + /// @param input the public input field elements in the scalar field Fr. + /// Elements must be reduced. + function verifyCompressedProof(uint256[4] calldata compressedProof, uint256[2] calldata input) + public + view + { + uint256[24] memory pairings; + + { + (uint256 Ax, uint256 Ay) = decompress_g1(compressedProof[0]); + (uint256 Bx0, uint256 Bx1, uint256 By0, uint256 By1) = + decompress_g2(compressedProof[2], compressedProof[1]); + (uint256 Cx, uint256 Cy) = decompress_g1(compressedProof[3]); + (uint256 Lx, uint256 Ly) = publicInputMSM(input); + + // Verify the pairing + // Note: The precompile expects the F2 coefficients in big-endian order. + // Note: The pairing precompile rejects unreduced values, so we won't check that here. + // e(A, B) + pairings[0] = Ax; + pairings[1] = Ay; + pairings[2] = Bx1; + pairings[3] = Bx0; + pairings[4] = By1; + pairings[5] = By0; + // e(C, -δ) + pairings[6] = Cx; + pairings[7] = Cy; + pairings[8] = DELTA_NEG_X_1; + pairings[9] = DELTA_NEG_X_0; + pairings[10] = DELTA_NEG_Y_1; + pairings[11] = DELTA_NEG_Y_0; + // e(α, -β) + pairings[12] = ALPHA_X; + pairings[13] = ALPHA_Y; + pairings[14] = BETA_NEG_X_1; + pairings[15] = BETA_NEG_X_0; + pairings[16] = BETA_NEG_Y_1; + pairings[17] = BETA_NEG_Y_0; + // e(L_pub, -γ) + pairings[18] = Lx; + pairings[19] = Ly; + pairings[20] = GAMMA_NEG_X_1; + pairings[21] = GAMMA_NEG_X_0; + pairings[22] = GAMMA_NEG_Y_1; + pairings[23] = GAMMA_NEG_Y_0; + + // Check pairing equation. + bool success; + uint256[1] memory output; + assembly ("memory-safe") { + success := staticcall(gas(), PRECOMPILE_VERIFY, pairings, 0x300, output, 0x20) + } + if (!success || output[0] != 1) { + // Either proof or verification key invalid. + // We assume the contract is correctly generated, so the verification key is valid. + revert ProofInvalid(); + } + } + } + + /// Verify an uncompressed Groth16 proof. + /// @notice Reverts with InvalidProof if the proof is invalid or + /// with PublicInputNotInField the public input is not reduced. + /// @notice There is no return value. If the function does not revert, the + /// proof was successfully verified. + /// @param proof the points (A, B, C) in EIP-197 format matching the output + /// of compressProof. + /// @param input the public input field elements in the scalar field Fr. + /// Elements must be reduced. + function Verify(uint256[8] calldata proof, uint256[2] calldata input) public view { + (uint256 x, uint256 y) = publicInputMSM(input); + + // Note: The precompile expects the F2 coefficients in big-endian order. + // Note: The pairing precompile rejects unreduced values, so we won't check that here. + bool success; + assembly ("memory-safe") { + let f := mload(0x40) // Free memory pointer. + + // Copy points (A, B, C) to memory. They are already in correct encoding. + // This is pairing e(A, B) and G1 of e(C, -δ). + calldatacopy(f, proof, 0x100) + + // Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory. + // OPT: This could be better done using a single codecopy, but + // Solidity (unlike standalone Yul) doesn't provide a way to + // to do this. + mstore(add(f, 0x100), DELTA_NEG_X_1) + mstore(add(f, 0x120), DELTA_NEG_X_0) + mstore(add(f, 0x140), DELTA_NEG_Y_1) + mstore(add(f, 0x160), DELTA_NEG_Y_0) + mstore(add(f, 0x180), ALPHA_X) + mstore(add(f, 0x1a0), ALPHA_Y) + mstore(add(f, 0x1c0), BETA_NEG_X_1) + mstore(add(f, 0x1e0), BETA_NEG_X_0) + mstore(add(f, 0x200), BETA_NEG_Y_1) + mstore(add(f, 0x220), BETA_NEG_Y_0) + mstore(add(f, 0x240), x) + mstore(add(f, 0x260), y) + mstore(add(f, 0x280), GAMMA_NEG_X_1) + mstore(add(f, 0x2a0), GAMMA_NEG_X_0) + mstore(add(f, 0x2c0), GAMMA_NEG_Y_1) + mstore(add(f, 0x2e0), GAMMA_NEG_Y_0) + + // Check pairing equation. + success := staticcall(gas(), PRECOMPILE_VERIFY, f, 0x300, f, 0x20) + // Also check returned value (both are either 1 or 0). + success := and(success, mload(f)) + } + if (!success) { + // Either proof or verification key invalid. + // We assume the contract is correctly generated, so the verification key is valid. + revert ProofInvalid(); + } + } +} diff --git a/contracts/src/v3.0.0-rc3/PlonkVerifier.sol b/contracts/src/v3.0.0-rc3/PlonkVerifier.sol new file mode 100644 index 0000000..b52f3cc --- /dev/null +++ b/contracts/src/v3.0.0-rc3/PlonkVerifier.sol @@ -0,0 +1,1379 @@ +// SPDX-License-Identifier: Apache-2.0 + +// Copyright 2023 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + +pragma solidity ^0.8.0; + +contract PlonkVerifier { + uint256 private constant R_MOD = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + uint256 private constant R_MOD_MINUS_ONE = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 private constant P_MOD = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + uint256 private constant G2_SRS_0_X_0 = + 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 private constant G2_SRS_0_X_1 = + 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 private constant G2_SRS_0_Y_0 = + 4082367875863433681332203403145435568316851327593401208105741076214120093531; + uint256 private constant G2_SRS_0_Y_1 = + 8495653923123431417604973247489272438418190587263600148770280649306958101930; + + uint256 private constant G2_SRS_1_X_0 = + 15805639136721018565402881920352193254830339253282065586954346329754995870280; + uint256 private constant G2_SRS_1_X_1 = + 19089565590083334368588890253123139704298730990782503769911324779715431555531; + uint256 private constant G2_SRS_1_Y_0 = + 9779648407879205346559610309258181044130619080926897934572699915909528404984; + uint256 private constant G2_SRS_1_Y_1 = + 6779728121489434657638426458390319301070371227460768374343986326751507916979; + + uint256 private constant G1_SRS_X = + 14312776538779914388377568895031746459131577658076416373430523308756343304251; + uint256 private constant G1_SRS_Y = + 11763105256161367503191792604679297387056316997144156930871823008787082098465; + + // ----------------------- vk --------------------- + uint256 private constant VK_NB_PUBLIC_INPUTS = 2; + uint256 private constant VK_DOMAIN_SIZE = 16777216; + uint256 private constant VK_INV_DOMAIN_SIZE = + 21888241567198334088790460357988866238279339518792980768180410072331574733841; + uint256 private constant VK_OMEGA = + 5709868443893258075976348696661355716898495876243883251619397131511003808859; + uint256 private constant VK_QL_COM_X = + 6698926252499501918627049539857227069908963353308522713401817428479361568440; + uint256 private constant VK_QL_COM_Y = + 390398004416183979452133282904065487059356531982837080656872214854553489350; + uint256 private constant VK_QR_COM_X = + 15880456667347413803865543437928881464825011023890441259779169206403913363151; + uint256 private constant VK_QR_COM_Y = + 3767941190808440189902161405604124601331914695906424222482338276374206831132; + uint256 private constant VK_QM_COM_X = + 5880611536603228408869722577745139096541545452210666651972026582265463007511; + uint256 private constant VK_QM_COM_Y = + 1224143639924163872305752448189325623163513756607992331286640139697358890946; + uint256 private constant VK_QO_COM_X = + 10784511595954287406993173499667136603239479748310285717260107338983244276060; + uint256 private constant VK_QO_COM_Y = + 18906558344705317932195383600423433585385784884571943386801247393368669782537; + uint256 private constant VK_QK_COM_X = + 18276155924633489895778193287517112765753318704356124480385636026579796724584; + uint256 private constant VK_QK_COM_Y = + 21690870202009328210781414048649457998194032922905372471880728783340513442890; + + uint256 private constant VK_S1_COM_X = + 15880661300853021639231473742380264628736914186438251569837407188944320716554; + uint256 private constant VK_S1_COM_Y = + 17368402498745842963461937676623436150527636742807769735472062133579682935390; + + uint256 private constant VK_S2_COM_X = + 17774064061947492896572463203478116570275709112580707484534909374676668977524; + uint256 private constant VK_S2_COM_Y = + 10372960929593342938703206496348658292612468496655535789104353649836524032299; + + uint256 private constant VK_S3_COM_X = + 21131795236225698179116006663026974130944823263770762203882565449801882913775; + uint256 private constant VK_S3_COM_Y = + 6122699356523015511637022172421089077159502502652656594712329899009208296070; + + uint256 private constant VK_COSET_SHIFT = 5; + + uint256 private constant VK_QCP_0_X = + 9522352021536039370701096527024757579826875694034309808870403911322444208289; + uint256 private constant VK_QCP_0_Y = + 18911718139779028078468950841548487462498208718101892018848709759471198128993; + + uint256 private constant VK_INDEX_COMMIT_API_0 = 8957791; + uint256 private constant VK_NB_CUSTOM_GATES = 1; + + // ------------------------------------------------ + + // size of the proof without call custom gate + uint256 private constant FIXED_PROOF_SIZE = 0x300; + + // offset proof + + uint256 private constant PROOF_L_COM_X = 0x0; + uint256 private constant PROOF_L_COM_Y = 0x20; + uint256 private constant PROOF_R_COM_X = 0x40; + uint256 private constant PROOF_R_COM_Y = 0x60; + uint256 private constant PROOF_O_COM_X = 0x80; + uint256 private constant PROOF_O_COM_Y = 0xa0; + + // h = h_0 + x^{n+2}h_1 + x^{2(n+2)}h_2 + uint256 private constant PROOF_H_0_COM_X = 0xc0; + uint256 private constant PROOF_H_0_COM_Y = 0xe0; + uint256 private constant PROOF_H_1_COM_X = 0x100; + uint256 private constant PROOF_H_1_COM_Y = 0x120; + uint256 private constant PROOF_H_2_COM_X = 0x140; + uint256 private constant PROOF_H_2_COM_Y = 0x160; + + // "evaluations of wire polynomials at zeta + uint256 private constant PROOF_L_AT_ZETA = 0x180; + uint256 private constant PROOF_R_AT_ZETA = 0x1a0; + uint256 private constant PROOF_O_AT_ZETA = 0x1c0; + + // S1(zeta),S2(zeta) + uint256 private constant PROOF_S1_AT_ZETA = 0x1e0; // Sσ1(zeta) + uint256 private constant PROOF_S2_AT_ZETA = 0x200; // Sσ2(zeta) + + // [Z] + uint256 private constant PROOF_GRAND_PRODUCT_COMMITMENT_X = 0x220; + uint256 private constant PROOF_GRAND_PRODUCT_COMMITMENT_Y = 0x240; + + uint256 private constant PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA = 0x260; // z(w*zeta) + + // Folded proof for the opening of linearised poly, l, r, o, s_1, s_2, qcp + uint256 private constant PROOF_BATCH_OPENING_AT_ZETA_X = 0x280; + uint256 private constant PROOF_BATCH_OPENING_AT_ZETA_Y = 0x2a0; + + uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_X = 0x2c0; + uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_Y = 0x2e0; + + uint256 private constant PROOF_OPENING_QCP_AT_ZETA = 0x300; + uint256 private constant PROOF_BSB_COMMITMENTS = 0x320; + + // -------- offset state + + // challenges to check the claimed quotient + + uint256 private constant STATE_ALPHA = 0x0; + uint256 private constant STATE_BETA = 0x20; + uint256 private constant STATE_GAMMA = 0x40; + uint256 private constant STATE_ZETA = 0x60; + uint256 private constant STATE_ALPHA_SQUARE_LAGRANGE_0 = 0x80; + uint256 private constant STATE_FOLDED_H_X = 0xa0; + uint256 private constant STATE_FOLDED_H_Y = 0xc0; + uint256 private constant STATE_LINEARISED_POLYNOMIAL_X = 0xe0; + uint256 private constant STATE_LINEARISED_POLYNOMIAL_Y = 0x100; + uint256 private constant STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA = 0x120; + uint256 private constant STATE_FOLDED_CLAIMED_VALUES = 0x140; // Folded proof for the opening of H, linearised poly, l, r, o, s_1, s_2, qcp + uint256 private constant STATE_FOLDED_DIGESTS_X = 0x160; // linearised poly, l, r, o, s_1, s_2, qcp + uint256 private constant STATE_FOLDED_DIGESTS_Y = 0x180; + uint256 private constant STATE_PI = 0x1a0; + uint256 private constant STATE_ZETA_POWER_N_MINUS_ONE = 0x1c0; + uint256 private constant STATE_GAMMA_KZG = 0x1e0; + uint256 private constant STATE_SUCCESS = 0x200; + uint256 private constant STATE_CHECK_VAR = 0x220; // /!\ this slot is used for debugging only + uint256 private constant STATE_LAST_MEM = 0x240; + + // -------- utils (for Fiat Shamir) + uint256 private constant FS_ALPHA = 0x616C706861; // "alpha" + uint256 private constant FS_BETA = 0x62657461; // "beta" + uint256 private constant FS_GAMMA = 0x67616d6d61; // "gamma" + uint256 private constant FS_ZETA = 0x7a657461; // "zeta" + uint256 private constant FS_GAMMA_KZG = 0x67616d6d61; // "gamma" + + // -------- errors + uint256 private constant ERROR_STRING_ID = + 0x08c379a000000000000000000000000000000000000000000000000000000000; // selector for function Error(string) + + // -------- utils (for hash_fr) + uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128 + uint256 private constant HASH_FR_ZERO_UINT256 = 0; + uint8 private constant HASH_FR_LEN_IN_BYTES = 48; + uint8 private constant HASH_FR_SIZE_DOMAIN = 11; + uint8 private constant HASH_FR_ONE = 1; + uint8 private constant HASH_FR_TWO = 2; + + // -------- precompiles + uint8 private constant SHA2 = 0x2; + uint8 private constant MOD_EXP = 0x5; + uint8 private constant EC_ADD = 0x6; + uint8 private constant EC_MUL = 0x7; + uint8 private constant EC_PAIR = 0x8; + + /// Verify a Plonk proof. + /// Reverts if the proof or the public inputs are malformed. + /// @param proof serialised plonk proof (using gnark's MarshalSolidity) + /// @param public_inputs (must be reduced) + /// @return success true if the proof passes false otherwise + function Verify(bytes calldata proof, uint256[] calldata public_inputs) + public + view + returns (bool success) + { + assembly { + let mem := mload(0x40) + let freeMem := add(mem, STATE_LAST_MEM) + + // sanity checks + check_number_of_public_inputs(public_inputs.length) + check_inputs_size(public_inputs.length, public_inputs.offset) + check_proof_size(proof.length) + check_proof_openings_size(proof.offset) + + // compute the challenges + let prev_challenge_non_reduced + prev_challenge_non_reduced := + derive_gamma(proof.offset, public_inputs.length, public_inputs.offset) + prev_challenge_non_reduced := derive_beta(prev_challenge_non_reduced) + prev_challenge_non_reduced := derive_alpha(proof.offset, prev_challenge_non_reduced) + derive_zeta(proof.offset, prev_challenge_non_reduced) + + // evaluation of Z=Xⁿ-1 at ζ, we save this value + let zeta := mload(add(mem, STATE_ZETA)) + let zeta_power_n_minus_one := + addmod(pow(zeta, VK_DOMAIN_SIZE, freeMem), sub(R_MOD, 1), R_MOD) + mstore(add(mem, STATE_ZETA_POWER_N_MINUS_ONE), zeta_power_n_minus_one) + + // public inputs contribution + let l_pi := sum_pi_wo_api_commit(public_inputs.offset, public_inputs.length, freeMem) + let l_pi_commit := sum_pi_commit(proof.offset, public_inputs.length, freeMem) + l_pi := addmod(l_pi_commit, l_pi, R_MOD) + mstore(add(mem, STATE_PI), l_pi) + + compute_alpha_square_lagrange_0() + compute_opening_linearised_polynomial(proof.offset) + fold_h(proof.offset) + compute_commitment_linearised_polynomial(proof.offset) + compute_gamma_kzg(proof.offset) + fold_state(proof.offset) + batch_verify_multi_points(proof.offset) + + success := mload(add(mem, STATE_SUCCESS)) + + // Beginning errors ------------------------------------------------- + + function error_nb_public_inputs() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0x1d) + mstore(add(ptError, 0x44), "wrong number of public inputs") + revert(ptError, 0x64) + } + + /// Called when an exponentiation mod r fails + function error_mod_exp() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0xc) + mstore(add(ptError, 0x44), "error mod exp") + revert(ptError, 0x64) + } + + /// Called when an operation on Bn254 fails + /// @dev for instance when calling EcMul on a point not on Bn254. + function error_ec_op() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0x12) + mstore(add(ptError, 0x44), "error ec operation") + revert(ptError, 0x64) + } + + /// Called when one of the public inputs is not reduced. + function error_inputs_size() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0x18) + mstore(add(ptError, 0x44), "inputs are bigger than r") + revert(ptError, 0x64) + } + + /// Called when the size proof is not as expected + /// @dev to avoid overflow attack for instance + function error_proof_size() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0x10) + mstore(add(ptError, 0x44), "wrong proof size") + revert(ptError, 0x64) + } + + /// Called when one the openings is bigger than r + /// The openings are the claimed evalutions of a polynomial + /// in a Kzg proof. + function error_proof_openings_size() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0x16) + mstore(add(ptError, 0x44), "openings bigger than r") + revert(ptError, 0x64) + } + + function error_pairing() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0xd) + mstore(add(ptError, 0x44), "error pairing") + revert(ptError, 0x64) + } + + function error_verify() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0xc) + mstore(add(ptError, 0x44), "error verify") + revert(ptError, 0x64) + } + + function error_random_generation() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0x14) + mstore(add(ptError, 0x44), "error random gen kzg") + revert(ptError, 0x64) + } + // end errors ------------------------------------------------- + + // Beginning checks ------------------------------------------------- + + /// @param s actual number of public inputs + function check_number_of_public_inputs(s) { + if iszero(eq(s, VK_NB_PUBLIC_INPUTS)) { error_nb_public_inputs() } + } + + /// Checks that the public inputs are < R_MOD. + /// @param s number of public inputs + /// @param p pointer to the public inputs array + function check_inputs_size(s, p) { + for { let i } lt(i, s) { i := add(i, 1) } { + if gt(calldataload(p), R_MOD_MINUS_ONE) { error_inputs_size() } + p := add(p, 0x20) + } + } + + /// Checks if the proof is of the correct size + /// @param actual_proof_size size of the proof (not the expected size) + function check_proof_size(actual_proof_size) { + let expected_proof_size := add(FIXED_PROOF_SIZE, mul(VK_NB_CUSTOM_GATES, 0x60)) + if iszero(eq(actual_proof_size, expected_proof_size)) { error_proof_size() } + } + + /// Checks if the multiple openings of the polynomials are < R_MOD. + /// @param aproof pointer to the beginning of the proof + /// @dev the 'a' prepending proof is to have a local name + function check_proof_openings_size(aproof) { + // PROOF_L_AT_ZETA + let p := add(aproof, PROOF_L_AT_ZETA) + if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } + + // PROOF_R_AT_ZETA + p := add(aproof, PROOF_R_AT_ZETA) + if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } + + // PROOF_O_AT_ZETA + p := add(aproof, PROOF_O_AT_ZETA) + if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } + + // PROOF_S1_AT_ZETA + p := add(aproof, PROOF_S1_AT_ZETA) + if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } + + // PROOF_S2_AT_ZETA + p := add(aproof, PROOF_S2_AT_ZETA) + if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } + + // PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA + p := add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA) + if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } + + // PROOF_OPENING_QCP_AT_ZETA + + p := add(aproof, PROOF_OPENING_QCP_AT_ZETA) + for { let i := 0 } lt(i, VK_NB_CUSTOM_GATES) { i := add(i, 1) } { + if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } + p := add(p, 0x20) + } + } + // end checks ------------------------------------------------- + + // Beginning challenges ------------------------------------------------- + + /// Derive gamma as Sha256() + /// @param aproof pointer to the proof + /// @param nb_pi number of public inputs + /// @param pi pointer to the array of public inputs + /// @return the challenge gamma, not reduced + /// @notice The transcript is the concatenation (in this order) of: + /// * the word "gamma" in ascii, equal to [0x67,0x61,0x6d, 0x6d, 0x61] and encoded as a uint256. + /// * the commitments to the permutation polynomials S1, S2, S3, where we concatenate the coordinates of those points + /// * the commitments of Ql, Qr, Qm, Qo, Qk + /// * the public inputs + /// * the commitments of the wires related to the custom gates (commitments_wires_commit_api) + /// * commitments to L, R, O (proof__com_) + /// The data described above is written starting at mPtr. "gamma" lies on 5 bytes, + /// and is encoded as a uint256 number n. In basis b = 256, the number looks like this + /// [0 0 0 .. 0x67 0x61 0x6d, 0x6d, 0x61]. The first non zero entry is at position 27=0x1b + /// Gamma reduced (the actual challenge) is stored at add(state, state_gamma) + function derive_gamma(aproof, nb_pi, pi) -> gamma_not_reduced { + let state := mload(0x40) + let mPtr := add(state, STATE_LAST_MEM) + + mstore(mPtr, FS_GAMMA) // "gamma" + + mstore(add(mPtr, 0x20), VK_S1_COM_X) + mstore(add(mPtr, 0x40), VK_S1_COM_Y) + mstore(add(mPtr, 0x60), VK_S2_COM_X) + mstore(add(mPtr, 0x80), VK_S2_COM_Y) + mstore(add(mPtr, 0xa0), VK_S3_COM_X) + mstore(add(mPtr, 0xc0), VK_S3_COM_Y) + mstore(add(mPtr, 0xe0), VK_QL_COM_X) + mstore(add(mPtr, 0x100), VK_QL_COM_Y) + mstore(add(mPtr, 0x120), VK_QR_COM_X) + mstore(add(mPtr, 0x140), VK_QR_COM_Y) + mstore(add(mPtr, 0x160), VK_QM_COM_X) + mstore(add(mPtr, 0x180), VK_QM_COM_Y) + mstore(add(mPtr, 0x1a0), VK_QO_COM_X) + mstore(add(mPtr, 0x1c0), VK_QO_COM_Y) + mstore(add(mPtr, 0x1e0), VK_QK_COM_X) + mstore(add(mPtr, 0x200), VK_QK_COM_Y) + + mstore(add(mPtr, 0x220), VK_QCP_0_X) + mstore(add(mPtr, 0x240), VK_QCP_0_Y) + + // public inputs + let _mPtr := add(mPtr, 0x260) + let size_pi_in_bytes := mul(nb_pi, 0x20) + calldatacopy(_mPtr, pi, size_pi_in_bytes) + _mPtr := add(_mPtr, size_pi_in_bytes) + + // commitments to l, r, o + let size_commitments_lro_in_bytes := 0xc0 + calldatacopy(_mPtr, aproof, size_commitments_lro_in_bytes) + _mPtr := add(_mPtr, size_commitments_lro_in_bytes) + + // total size is : + // sizegamma(=0x5) + 11*64(=0x2c0) + // + nb_public_inputs*0x20 + // + nb_custom gates*0x40 + let size := add(0x2c5, size_pi_in_bytes) + + size := add(size, mul(VK_NB_CUSTOM_GATES, 0x40)) + let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), size, mPtr, 0x20) //0x1b -> 000.."gamma" + if iszero(l_success) { error_verify() } + gamma_not_reduced := mload(mPtr) + mstore(add(state, STATE_GAMMA), mod(gamma_not_reduced, R_MOD)) + } + + /// derive beta as Sha256 + /// @param gamma_not_reduced the previous challenge (gamma) not reduced + /// @return beta_not_reduced the next challenge, beta, not reduced + /// @notice the transcript consists of the previous challenge only. + /// The reduced version of beta is stored at add(state, state_beta) + function derive_beta(gamma_not_reduced) -> beta_not_reduced { + let state := mload(0x40) + let mPtr := add(mload(0x40), STATE_LAST_MEM) + + // beta + mstore(mPtr, FS_BETA) // "beta" + mstore(add(mPtr, 0x20), gamma_not_reduced) + let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1c), 0x24, mPtr, 0x20) //0x1b -> 000.."gamma" + if iszero(l_success) { error_verify() } + beta_not_reduced := mload(mPtr) + mstore(add(state, STATE_BETA), mod(beta_not_reduced, R_MOD)) + } + + /// derive alpha as sha256 + /// @param aproof pointer to the proof object + /// @param beta_not_reduced the previous challenge (beta) not reduced + /// @return alpha_not_reduced the next challenge, alpha, not reduced + /// @notice the transcript consists of the previous challenge (beta) + /// not reduced, the commitments to the wires associated to the QCP_i, + /// and the commitment to the grand product polynomial + function derive_alpha(aproof, beta_not_reduced) -> alpha_not_reduced { + let state := mload(0x40) + let mPtr := add(mload(0x40), STATE_LAST_MEM) + let full_size := 0x65 // size("alpha") + 0x20 (previous challenge) + + // alpha + mstore(mPtr, FS_ALPHA) // "alpha" + let _mPtr := add(mPtr, 0x20) + mstore(_mPtr, beta_not_reduced) + _mPtr := add(_mPtr, 0x20) + + // Bsb22Commitments + let proof_bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) + let size_bsb_commitments := mul(0x40, VK_NB_CUSTOM_GATES) + calldatacopy(_mPtr, proof_bsb_commitments, size_bsb_commitments) + _mPtr := add(_mPtr, size_bsb_commitments) + full_size := add(full_size, size_bsb_commitments) + + // [Z], the commitment to the grand product polynomial + calldatacopy(_mPtr, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), 0x40) + let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), full_size, mPtr, 0x20) + if iszero(l_success) { error_verify() } + + alpha_not_reduced := mload(mPtr) + mstore(add(state, STATE_ALPHA), mod(alpha_not_reduced, R_MOD)) + } + + /// derive zeta as sha256 + /// @param aproof pointer to the proof object + /// @param alpha_not_reduced the previous challenge (alpha) not reduced + /// The transcript consists of the previous challenge and the commitment to + /// the quotient polynomial h. + function derive_zeta(aproof, alpha_not_reduced) { + let state := mload(0x40) + let mPtr := add(mload(0x40), STATE_LAST_MEM) + + // zeta + mstore(mPtr, FS_ZETA) // "zeta" + mstore(add(mPtr, 0x20), alpha_not_reduced) + calldatacopy(add(mPtr, 0x40), add(aproof, PROOF_H_0_COM_X), 0xc0) + let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1c), 0xe4, mPtr, 0x20) + if iszero(l_success) { error_verify() } + let zeta_not_reduced := mload(mPtr) + mstore(add(state, STATE_ZETA), mod(zeta_not_reduced, R_MOD)) + } + // END challenges ------------------------------------------------- + + // BEGINNING compute_pi ------------------------------------------------- + + /// sum_pi_wo_api_commit computes the public inputs contributions, + /// except for the public inputs coming from the custom gate + /// @param ins pointer to the public inputs + /// @param n number of public inputs + /// @param mPtr free memory + /// @return pi_wo_commit public inputs contribution (except the public inputs coming from the custom gate) + function sum_pi_wo_api_commit(ins, n, mPtr) -> pi_wo_commit { + let state := mload(0x40) + let z := mload(add(state, STATE_ZETA)) + let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) + + let li := mPtr + batch_compute_lagranges_at_z(z, zpnmo, n, li) + + let tmp := 0 + for { let i := 0 } lt(i, n) { i := add(i, 1) } { + tmp := mulmod(mload(li), calldataload(ins), R_MOD) + pi_wo_commit := addmod(pi_wo_commit, tmp, R_MOD) + li := add(li, 0x20) + ins := add(ins, 0x20) + } + } + + /// batch_compute_lagranges_at_z computes [L_0(z), .., L_{n-1}(z)] + /// @param z point at which the Lagranges are evaluated + /// @param zpnmo ζⁿ-1 + /// @param n_pub number of public inputs (number of Lagranges to compute) + /// @param mPtr pointer to which the results are stored + function batch_compute_lagranges_at_z(z, zpnmo, n_pub, mPtr) { + let zn := mulmod(zpnmo, VK_INV_DOMAIN_SIZE, R_MOD) // 1/n * (ζⁿ - 1) + + let _w := 1 + let _mPtr := mPtr + for { let i := 0 } lt(i, n_pub) { i := add(i, 1) } { + mstore(_mPtr, addmod(z, sub(R_MOD, _w), R_MOD)) + _w := mulmod(_w, VK_OMEGA, R_MOD) + _mPtr := add(_mPtr, 0x20) + } + batch_invert(mPtr, n_pub, _mPtr) + _mPtr := mPtr + _w := 1 + for { let i := 0 } lt(i, n_pub) { i := add(i, 1) } { + mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn, R_MOD), _w, R_MOD)) + _mPtr := add(_mPtr, 0x20) + _w := mulmod(_w, VK_OMEGA, R_MOD) + } + } + + /// @notice Montgomery trick for batch inversion mod R_MOD + /// @param ins pointer to the data to batch invert + /// @param number of elements to batch invert + /// @param mPtr free memory + function batch_invert(ins, nb_ins, mPtr) { + mstore(mPtr, 1) + let offset := 0 + for { let i := 0 } lt(i, nb_ins) { i := add(i, 1) } { + let prev := mload(add(mPtr, offset)) + let cur := mload(add(ins, offset)) + cur := mulmod(prev, cur, R_MOD) + offset := add(offset, 0x20) + mstore(add(mPtr, offset), cur) + } + ins := add(ins, sub(offset, 0x20)) + mPtr := add(mPtr, offset) + let inv := pow(mload(mPtr), sub(R_MOD, 2), add(mPtr, 0x20)) + for { let i := 0 } lt(i, nb_ins) { i := add(i, 1) } { + mPtr := sub(mPtr, 0x20) + let tmp := mload(ins) + let cur := mulmod(inv, mload(mPtr), R_MOD) + mstore(ins, cur) + inv := mulmod(inv, tmp, R_MOD) + ins := sub(ins, 0x20) + } + } + + /// Public inputs (the ones coming from the custom gate) contribution + /// @param aproof pointer to the proof + /// @param nb_public_inputs number of public inputs + /// @param mPtr pointer to free memory + /// @return pi_commit custom gate public inputs contribution + function sum_pi_commit(aproof, nb_public_inputs, mPtr) -> pi_commit { + let state := mload(0x40) + let z := mload(add(state, STATE_ZETA)) + let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) + + let p := add(aproof, PROOF_BSB_COMMITMENTS) + + let h_fr, ith_lagrange + + h_fr := hash_fr(calldataload(p), calldataload(add(p, 0x20)), mPtr) + ith_lagrange := + compute_ith_lagrange_at_z( + z, zpnmo, add(nb_public_inputs, VK_INDEX_COMMIT_API_0), mPtr + ) + pi_commit := addmod(pi_commit, mulmod(h_fr, ith_lagrange, R_MOD), R_MOD) + } + + /// Computes L_i(zeta) = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) where: + /// @param z zeta + /// @param zpmno ζⁿ-1 + /// @param i i-th lagrange + /// @param mPtr free memory + /// @return res = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) + function compute_ith_lagrange_at_z(z, zpnmo, i, mPtr) -> res { + let w := pow(VK_OMEGA, i, mPtr) // w**i + i := addmod(z, sub(R_MOD, w), R_MOD) // z-w**i + w := mulmod(w, VK_INV_DOMAIN_SIZE, R_MOD) // w**i/n + i := pow(i, sub(R_MOD, 2), mPtr) // (z-w**i)**-1 + w := mulmod(w, i, R_MOD) // w**i/n*(z-w)**-1 + res := mulmod(w, zpnmo, R_MOD) + } + + /// @dev https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 + /// @param x x coordinate of a point on Bn254(𝔽_p) + /// @param y y coordinate of a point on Bn254(𝔽_p) + /// @param mPtr free memory + /// @return res an element mod R_MOD + function hash_fr(x, y, mPtr) -> res { + // [0x00, .. , 0x00 || x, y, || 0, 48, 0, dst, HASH_FR_SIZE_DOMAIN] + // <- 64 bytes -> <-64b -> <- 1 bytes each -> + + // [0x00, .., 0x00] 64 bytes of zero + mstore(mPtr, HASH_FR_ZERO_UINT256) + mstore(add(mPtr, 0x20), HASH_FR_ZERO_UINT256) + + // msg = x || y , both on 32 bytes + mstore(add(mPtr, 0x40), x) + mstore(add(mPtr, 0x60), y) + + // 0 || 48 || 0 all on 1 byte + mstore8(add(mPtr, 0x80), 0) + mstore8(add(mPtr, 0x81), HASH_FR_LEN_IN_BYTES) + mstore8(add(mPtr, 0x82), 0) + + // "BSB22-Plonk" = [42, 53, 42, 32, 32, 2d, 50, 6c, 6f, 6e, 6b,] + mstore8(add(mPtr, 0x83), 0x42) + mstore8(add(mPtr, 0x84), 0x53) + mstore8(add(mPtr, 0x85), 0x42) + mstore8(add(mPtr, 0x86), 0x32) + mstore8(add(mPtr, 0x87), 0x32) + mstore8(add(mPtr, 0x88), 0x2d) + mstore8(add(mPtr, 0x89), 0x50) + mstore8(add(mPtr, 0x8a), 0x6c) + mstore8(add(mPtr, 0x8b), 0x6f) + mstore8(add(mPtr, 0x8c), 0x6e) + mstore8(add(mPtr, 0x8d), 0x6b) + + // size domain + mstore8(add(mPtr, 0x8e), HASH_FR_SIZE_DOMAIN) + + let l_success := staticcall(gas(), SHA2, mPtr, 0x8f, mPtr, 0x20) + if iszero(l_success) { error_verify() } + + let b0 := mload(mPtr) + + // [b0 || one || dst || HASH_FR_SIZE_DOMAIN] + // <-64bytes -> <- 1 byte each -> + mstore8(add(mPtr, 0x20), HASH_FR_ONE) // 1 + + mstore8(add(mPtr, 0x21), 0x42) // dst + mstore8(add(mPtr, 0x22), 0x53) + mstore8(add(mPtr, 0x23), 0x42) + mstore8(add(mPtr, 0x24), 0x32) + mstore8(add(mPtr, 0x25), 0x32) + mstore8(add(mPtr, 0x26), 0x2d) + mstore8(add(mPtr, 0x27), 0x50) + mstore8(add(mPtr, 0x28), 0x6c) + mstore8(add(mPtr, 0x29), 0x6f) + mstore8(add(mPtr, 0x2a), 0x6e) + mstore8(add(mPtr, 0x2b), 0x6b) + + mstore8(add(mPtr, 0x2c), HASH_FR_SIZE_DOMAIN) // size domain + l_success := staticcall(gas(), SHA2, mPtr, 0x2d, mPtr, 0x20) + if iszero(l_success) { error_verify() } + + // b1 is located at mPtr. We store b2 at add(mPtr, 0x20) + + // [b0^b1 || two || dst || HASH_FR_SIZE_DOMAIN] + // <-64bytes -> <- 1 byte each -> + mstore(add(mPtr, 0x20), xor(mload(mPtr), b0)) + mstore8(add(mPtr, 0x40), HASH_FR_TWO) + + mstore8(add(mPtr, 0x41), 0x42) // dst + mstore8(add(mPtr, 0x42), 0x53) + mstore8(add(mPtr, 0x43), 0x42) + mstore8(add(mPtr, 0x44), 0x32) + mstore8(add(mPtr, 0x45), 0x32) + mstore8(add(mPtr, 0x46), 0x2d) + mstore8(add(mPtr, 0x47), 0x50) + mstore8(add(mPtr, 0x48), 0x6c) + mstore8(add(mPtr, 0x49), 0x6f) + mstore8(add(mPtr, 0x4a), 0x6e) + mstore8(add(mPtr, 0x4b), 0x6b) + + mstore8(add(mPtr, 0x4c), HASH_FR_SIZE_DOMAIN) // size domain + + let offset := add(mPtr, 0x20) + l_success := staticcall(gas(), SHA2, offset, 0x2d, offset, 0x20) + if iszero(l_success) { error_verify() } + + // at this point we have mPtr = [ b1 || b2] where b1 is on 32byes and b2 in 16bytes. + // we interpret it as a big integer mod r in big endian (similar to regular decimal notation) + // the result is then 2**(8*16)*mPtr[:32] + mPtr[32:48] + res := mulmod(mload(mPtr), HASH_FR_BB, R_MOD) // <- res = 2**128 * mPtr[:32] + let b1 := shr(128, mload(add(mPtr, 0x20))) // b1 <- [0, 0, .., 0 || b2[:16] ] + res := addmod(res, b1, R_MOD) + } + + // END compute_pi ------------------------------------------------- + + /// @notice compute α² * 1/n * (ζ{n}-1)/(ζ - 1) where + /// * α = challenge derived in derive_gamma_beta_alpha_zeta + /// * n = vk_domain_size + /// * ω = vk_omega (generator of the multiplicative cyclic group of order n in (ℤ/rℤ)*) + /// * ζ = zeta (challenge derived with Fiat Shamir) + function compute_alpha_square_lagrange_0() { + let state := mload(0x40) + let mPtr := add(mload(0x40), STATE_LAST_MEM) + + let res := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) + let den := addmod(mload(add(state, STATE_ZETA)), sub(R_MOD, 1), R_MOD) + den := pow(den, sub(R_MOD, 2), mPtr) + den := mulmod(den, VK_INV_DOMAIN_SIZE, R_MOD) + res := mulmod(den, res, R_MOD) + + let l_alpha := mload(add(state, STATE_ALPHA)) + res := mulmod(res, l_alpha, R_MOD) + res := mulmod(res, l_alpha, R_MOD) + mstore(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0), res) + } + + /// @notice follows alg. p.13 of https://eprint.iacr.org/2019/953.pdf + /// with t₁ = t₂ = 1, and the proofs are ([digest] + [quotient] +purported evaluation): + /// * [state_folded_state_digests], [proof_batch_opening_at_zeta_x], state_folded_evals + /// * [proof_grand_product_commitment], [proof_opening_at_zeta_omega_x], [proof_grand_product_at_zeta_omega] + /// @param aproof pointer to the proof + function batch_verify_multi_points(aproof) { + let state := mload(0x40) + let mPtr := add(state, STATE_LAST_MEM) + + // derive a random number. As there is no random generator, we + // do an FS like challenge derivation, depending on both digests and + // ζ to ensure that the prover cannot control the random number. + // Note: adding the other point ζω is not needed, as ω is known beforehand. + mstore(mPtr, mload(add(state, STATE_FOLDED_DIGESTS_X))) + mstore(add(mPtr, 0x20), mload(add(state, STATE_FOLDED_DIGESTS_Y))) + mstore(add(mPtr, 0x40), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X))) + mstore(add(mPtr, 0x60), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_Y))) + mstore(add(mPtr, 0x80), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X))) + mstore(add(mPtr, 0xa0), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_Y))) + mstore(add(mPtr, 0xc0), calldataload(add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X))) + mstore(add(mPtr, 0xe0), calldataload(add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_Y))) + mstore(add(mPtr, 0x100), mload(add(state, STATE_ZETA))) + mstore(add(mPtr, 0x120), mload(add(state, STATE_GAMMA_KZG))) + let random := staticcall(gas(), SHA2, mPtr, 0x140, mPtr, 0x20) + if iszero(random) { error_random_generation() } + random := mod(mload(mPtr), R_MOD) // use the same variable as we are one variable away from getting stack-too-deep error... + + let folded_quotients := mPtr + mPtr := add(folded_quotients, 0x40) + mstore(folded_quotients, calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X))) + mstore( + add(folded_quotients, 0x20), + calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_Y)) + ) + point_acc_mul_calldata( + folded_quotients, add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X), random, mPtr + ) + + let folded_digests := add(state, STATE_FOLDED_DIGESTS_X) + point_acc_mul_calldata( + folded_digests, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), random, mPtr + ) + + let folded_evals := add(state, STATE_FOLDED_CLAIMED_VALUES) + fr_acc_mul_calldata( + folded_evals, add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA), random + ) + + let folded_evals_commit := mPtr + mPtr := add(folded_evals_commit, 0x40) + mstore(folded_evals_commit, G1_SRS_X) + mstore(add(folded_evals_commit, 0x20), G1_SRS_Y) + mstore(add(folded_evals_commit, 0x40), mload(folded_evals)) + let check_staticcall := + staticcall(gas(), 7, folded_evals_commit, 0x60, folded_evals_commit, 0x40) + if iszero(check_staticcall) { error_verify() } + + let folded_evals_commit_y := add(folded_evals_commit, 0x20) + mstore(folded_evals_commit_y, sub(P_MOD, mload(folded_evals_commit_y))) + point_add(folded_digests, folded_digests, folded_evals_commit, mPtr) + + let folded_points_quotients := mPtr + mPtr := add(mPtr, 0x40) + point_mul_calldata( + folded_points_quotients, + add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X), + mload(add(state, STATE_ZETA)), + mPtr + ) + let zeta_omega := mulmod(mload(add(state, STATE_ZETA)), VK_OMEGA, R_MOD) + random := mulmod(random, zeta_omega, R_MOD) + point_acc_mul_calldata( + folded_points_quotients, + add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X), + random, + mPtr + ) + + point_add(folded_digests, folded_digests, folded_points_quotients, mPtr) + + let folded_quotients_y := add(folded_quotients, 0x20) + mstore(folded_quotients_y, sub(P_MOD, mload(folded_quotients_y))) + + mstore(mPtr, mload(folded_digests)) + + mstore(add(mPtr, 0x20), mload(add(folded_digests, 0x20))) + mstore(add(mPtr, 0x40), G2_SRS_0_X_0) // the 4 lines are the canonical G2 point on BN254 + mstore(add(mPtr, 0x60), G2_SRS_0_X_1) + mstore(add(mPtr, 0x80), G2_SRS_0_Y_0) + mstore(add(mPtr, 0xa0), G2_SRS_0_Y_1) + mstore(add(mPtr, 0xc0), mload(folded_quotients)) + mstore(add(mPtr, 0xe0), mload(add(folded_quotients, 0x20))) + mstore(add(mPtr, 0x100), G2_SRS_1_X_0) + mstore(add(mPtr, 0x120), G2_SRS_1_X_1) + mstore(add(mPtr, 0x140), G2_SRS_1_Y_0) + mstore(add(mPtr, 0x160), G2_SRS_1_Y_1) + check_pairing_kzg(mPtr) + } + + /// @notice check_pairing_kzg checks the result of the final pairing product of the batched + /// kzg verification. The purpose of this function is to avoid exhausting the stack + /// in the function batch_verify_multi_points. + /// @param mPtr pointer storing the tuple of pairs + function check_pairing_kzg(mPtr) { + let state := mload(0x40) + + let l_success := staticcall(gas(), 8, mPtr, 0x180, 0x00, 0x20) + if iszero(l_success) { error_pairing() } + let res_pairing := mload(0x00) + mstore(add(state, STATE_SUCCESS), res_pairing) + } + + /// @notice Fold the opening proofs at ζ: + /// * at state+state_folded_digest we store: [Linearised_polynomial]+γ[L] + γ²[R] + γ³[O] + γ⁴[S₁] +γ⁵[S₂] + ∑ᵢγ⁵⁺ⁱ[Pi_{i}] + /// * at state+state_folded_claimed_values we store: Linearised_polynomial(ζ)+γL(ζ) + γ²R(ζ)+ γ³O(ζ) + γ⁴S₁(ζ) +γ⁵S₂(ζ) + ∑ᵢγ⁵⁺ⁱPi_{i}(ζ) + /// @param aproof pointer to the proof + /// acc_gamma stores the γⁱ + function fold_state(aproof) { + let state := mload(0x40) + let mPtr := add(mload(0x40), STATE_LAST_MEM) + let mPtr20 := add(mPtr, 0x20) + let mPtr40 := add(mPtr, 0x40) + + let l_gamma_kzg := mload(add(state, STATE_GAMMA_KZG)) + let acc_gamma := l_gamma_kzg + let state_folded_digests := add(state, STATE_FOLDED_DIGESTS_X) + + mstore(state_folded_digests, mload(add(state, STATE_LINEARISED_POLYNOMIAL_X))) + mstore( + add(state, STATE_FOLDED_DIGESTS_Y), + mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y)) + ) + mstore( + add(state, STATE_FOLDED_CLAIMED_VALUES), + mload(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA)) + ) + + point_acc_mul_calldata( + state_folded_digests, add(aproof, PROOF_L_COM_X), acc_gamma, mPtr + ) + fr_acc_mul_calldata( + add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_L_AT_ZETA), acc_gamma + ) + + acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) + point_acc_mul_calldata( + state_folded_digests, add(aproof, PROOF_R_COM_X), acc_gamma, mPtr + ) + fr_acc_mul_calldata( + add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_R_AT_ZETA), acc_gamma + ) + + acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) + point_acc_mul_calldata( + state_folded_digests, add(aproof, PROOF_O_COM_X), acc_gamma, mPtr + ) + fr_acc_mul_calldata( + add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_O_AT_ZETA), acc_gamma + ) + + acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) + mstore(mPtr, VK_S1_COM_X) + mstore(mPtr20, VK_S1_COM_Y) + point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) + fr_acc_mul_calldata( + add(state, STATE_FOLDED_CLAIMED_VALUES), + add(aproof, PROOF_S1_AT_ZETA), + acc_gamma + ) + + acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) + mstore(mPtr, VK_S2_COM_X) + mstore(mPtr20, VK_S2_COM_Y) + point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) + fr_acc_mul_calldata( + add(state, STATE_FOLDED_CLAIMED_VALUES), + add(aproof, PROOF_S2_AT_ZETA), + acc_gamma + ) + let poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) + + acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) + mstore(mPtr, VK_QCP_0_X) + mstore(mPtr20, VK_QCP_0_Y) + point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) + fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), poqaz, acc_gamma) + poqaz := add(poqaz, 0x20) + } + + /// @notice generate the challenge (using Fiat Shamir) to fold the opening proofs + /// at ζ. + /// The process for deriving γ is the same as in derive_gamma but this time the inputs are + /// in this order (the [] means it's a commitment): + /// * ζ + /// * [Linearised polynomial] + /// * [L], [R], [O] + /// * [S₁] [S₂] + /// * [Pi_{i}] (wires associated to custom gates) + /// Then there are the purported evaluations of the previous committed polynomials: + /// * Linearised_polynomial(ζ) + /// * L(ζ), R(ζ), O(ζ), S₁(ζ), S₂(ζ) + /// * Pi_{i}(ζ) + /// * Z(ζω) + /// @param aproof pointer to the proof + function compute_gamma_kzg(aproof) { + let state := mload(0x40) + let mPtr := add(mload(0x40), STATE_LAST_MEM) + mstore(mPtr, FS_GAMMA_KZG) // "gamma" + mstore(add(mPtr, 0x20), mload(add(state, STATE_ZETA))) + mstore(add(mPtr, 0x40), mload(add(state, STATE_LINEARISED_POLYNOMIAL_X))) + mstore(add(mPtr, 0x60), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y))) + calldatacopy(add(mPtr, 0x80), add(aproof, PROOF_L_COM_X), 0xc0) + mstore(add(mPtr, 0x140), VK_S1_COM_X) + mstore(add(mPtr, 0x160), VK_S1_COM_Y) + mstore(add(mPtr, 0x180), VK_S2_COM_X) + mstore(add(mPtr, 0x1a0), VK_S2_COM_Y) + + let offset := 0x1c0 + + mstore(add(mPtr, offset), VK_QCP_0_X) + mstore(add(mPtr, add(offset, 0x20)), VK_QCP_0_Y) + offset := add(offset, 0x40) + mstore( + add(mPtr, offset), mload(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA)) + ) + mstore(add(mPtr, add(offset, 0x20)), calldataload(add(aproof, PROOF_L_AT_ZETA))) + mstore(add(mPtr, add(offset, 0x40)), calldataload(add(aproof, PROOF_R_AT_ZETA))) + mstore(add(mPtr, add(offset, 0x60)), calldataload(add(aproof, PROOF_O_AT_ZETA))) + mstore(add(mPtr, add(offset, 0x80)), calldataload(add(aproof, PROOF_S1_AT_ZETA))) + mstore(add(mPtr, add(offset, 0xa0)), calldataload(add(aproof, PROOF_S2_AT_ZETA))) + + let _mPtr := add(mPtr, add(offset, 0xc0)) + + let _poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) + calldatacopy(_mPtr, _poqaz, mul(VK_NB_CUSTOM_GATES, 0x20)) + _mPtr := add(_mPtr, mul(VK_NB_CUSTOM_GATES, 0x20)) + + mstore(_mPtr, calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA))) + + let start_input := 0x1b // 00.."gamma" + let size_input := add(0x14, mul(VK_NB_CUSTOM_GATES, 3)) // number of 32bytes elmts = 0x14 (zeta+3*6 for the digests+openings) + 3*VK_NB_CUSTOM_GATES (for the commitments of the selectors) + 1 (opening of Z at ζω) + size_input := add(0x5, mul(size_input, 0x20)) // size in bytes: 15*32 bytes + 5 bytes for gamma + let check_staticcall := + staticcall( + gas(), + SHA2, + add(mPtr, start_input), + size_input, + add(state, STATE_GAMMA_KZG), + 0x20 + ) + if iszero(check_staticcall) { error_verify() } + mstore(add(state, STATE_GAMMA_KZG), mod(mload(add(state, STATE_GAMMA_KZG)), R_MOD)) + } + + function compute_commitment_linearised_polynomial_ec(aproof, s1, s2) { + let state := mload(0x40) + let mPtr := add(mload(0x40), STATE_LAST_MEM) + + mstore(mPtr, VK_QL_COM_X) + mstore(add(mPtr, 0x20), VK_QL_COM_Y) + point_mul( + add(state, STATE_LINEARISED_POLYNOMIAL_X), + mPtr, + calldataload(add(aproof, PROOF_L_AT_ZETA)), + add(mPtr, 0x40) + ) + + mstore(mPtr, VK_QR_COM_X) + mstore(add(mPtr, 0x20), VK_QR_COM_Y) + point_acc_mul( + add(state, STATE_LINEARISED_POLYNOMIAL_X), + mPtr, + calldataload(add(aproof, PROOF_R_AT_ZETA)), + add(mPtr, 0x40) + ) + + let rl := + mulmod( + calldataload(add(aproof, PROOF_L_AT_ZETA)), + calldataload(add(aproof, PROOF_R_AT_ZETA)), + R_MOD + ) + mstore(mPtr, VK_QM_COM_X) + mstore(add(mPtr, 0x20), VK_QM_COM_Y) + point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, rl, add(mPtr, 0x40)) + + mstore(mPtr, VK_QO_COM_X) + mstore(add(mPtr, 0x20), VK_QO_COM_Y) + point_acc_mul( + add(state, STATE_LINEARISED_POLYNOMIAL_X), + mPtr, + calldataload(add(aproof, PROOF_O_AT_ZETA)), + add(mPtr, 0x40) + ) + + mstore(mPtr, VK_QK_COM_X) + mstore(add(mPtr, 0x20), VK_QK_COM_Y) + point_add( + add(state, STATE_LINEARISED_POLYNOMIAL_X), + add(state, STATE_LINEARISED_POLYNOMIAL_X), + mPtr, + add(mPtr, 0x40) + ) + + let qcp_opening_at_zeta := add(aproof, PROOF_OPENING_QCP_AT_ZETA) + let bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) + for { let i := 0 } lt(i, VK_NB_CUSTOM_GATES) { i := add(i, 1) } { + mstore(mPtr, calldataload(bsb_commitments)) + mstore(add(mPtr, 0x20), calldataload(add(bsb_commitments, 0x20))) + point_acc_mul( + add(state, STATE_LINEARISED_POLYNOMIAL_X), + mPtr, + calldataload(qcp_opening_at_zeta), + add(mPtr, 0x40) + ) + qcp_opening_at_zeta := add(qcp_opening_at_zeta, 0x20) + bsb_commitments := add(bsb_commitments, 0x40) + } + + mstore(mPtr, VK_S3_COM_X) + mstore(add(mPtr, 0x20), VK_S3_COM_Y) + point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, s1, add(mPtr, 0x40)) + + mstore(mPtr, calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X))) + mstore(add(mPtr, 0x20), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_Y))) + point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, s2, add(mPtr, 0x40)) + + point_add( + add(state, STATE_LINEARISED_POLYNOMIAL_X), + add(state, STATE_LINEARISED_POLYNOMIAL_X), + add(state, STATE_FOLDED_H_X), + mPtr + ) + } + + /// @notice Compute the commitment to the linearized polynomial equal to + /// L(ζ)[Qₗ]+r(ζ)[Qᵣ]+R(ζ)L(ζ)[Qₘ]+O(ζ)[Qₒ]+[Qₖ]+Σᵢqc'ᵢ(ζ)[BsbCommitmentᵢ] + + /// α*( Z(μζ)(L(ζ)+β*S₁(ζ)+γ)*(R(ζ)+β*S₂(ζ)+γ)[S₃]-[Z](L(ζ)+β*id_{1}(ζ)+γ)*(R(ζ)+β*id_{2}(ζ)+γ)*(O(ζ)+β*id_{3}(ζ)+γ) ) + + /// α²*L₁(ζ)[Z] - Z_{H}(ζ)*(([H₀] + ζᵐ⁺²*[H₁] + ζ²⁽ᵐ⁺²⁾*[H₂]) + /// where + /// * id_1 = id, id_2 = vk_coset_shift*id, id_3 = vk_coset_shift^{2}*id + /// * the [] means that it's a commitment (i.e. a point on Bn254(F_p)) + /// * Z_{H}(ζ) = ζ^n-1 + /// @param aproof pointer to the proof + function compute_commitment_linearised_polynomial(aproof) { + let state := mload(0x40) + let l_beta := mload(add(state, STATE_BETA)) + let l_gamma := mload(add(state, STATE_GAMMA)) + let l_zeta := mload(add(state, STATE_ZETA)) + let l_alpha := mload(add(state, STATE_ALPHA)) + + let u := + mulmod(calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)), l_beta, R_MOD) + let v := mulmod(l_beta, calldataload(add(aproof, PROOF_S1_AT_ZETA)), R_MOD) + v := addmod(v, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD) + v := addmod(v, l_gamma, R_MOD) + + let w := mulmod(l_beta, calldataload(add(aproof, PROOF_S2_AT_ZETA)), R_MOD) + w := addmod(w, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD) + w := addmod(w, l_gamma, R_MOD) + + let s1 := mulmod(u, v, R_MOD) + s1 := mulmod(s1, w, R_MOD) + s1 := mulmod(s1, l_alpha, R_MOD) + + let coset_square := mulmod(VK_COSET_SHIFT, VK_COSET_SHIFT, R_MOD) + let betazeta := mulmod(l_beta, l_zeta, R_MOD) + u := addmod(betazeta, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD) + u := addmod(u, l_gamma, R_MOD) + + v := mulmod(betazeta, VK_COSET_SHIFT, R_MOD) + v := addmod(v, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD) + v := addmod(v, l_gamma, R_MOD) + + w := mulmod(betazeta, coset_square, R_MOD) + w := addmod(w, calldataload(add(aproof, PROOF_O_AT_ZETA)), R_MOD) + w := addmod(w, l_gamma, R_MOD) + + let s2 := mulmod(u, v, R_MOD) + s2 := mulmod(s2, w, R_MOD) + s2 := sub(R_MOD, s2) + s2 := mulmod(s2, l_alpha, R_MOD) + s2 := addmod(s2, mload(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0)), R_MOD) + + // at this stage: + // * s₁ = α*Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*β + // * s₂ = -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) + + compute_commitment_linearised_polynomial_ec(aproof, s1, s2) + } + + /// @notice compute -z_h(ζ)*([H₁] + ζⁿ⁺²[H₂] + ζ²⁽ⁿ⁺²⁾[H₃]) and store the result at + /// state + state_folded_h + /// @param aproof pointer to the proof + function fold_h(aproof) { + let state := mload(0x40) + let n_plus_two := add(VK_DOMAIN_SIZE, 2) + let mPtr := add(mload(0x40), STATE_LAST_MEM) + let zeta_power_n_plus_two := pow(mload(add(state, STATE_ZETA)), n_plus_two, mPtr) + point_mul_calldata( + add(state, STATE_FOLDED_H_X), + add(aproof, PROOF_H_2_COM_X), + zeta_power_n_plus_two, + mPtr + ) + point_add_calldata( + add(state, STATE_FOLDED_H_X), + add(state, STATE_FOLDED_H_X), + add(aproof, PROOF_H_1_COM_X), + mPtr + ) + point_mul( + add(state, STATE_FOLDED_H_X), + add(state, STATE_FOLDED_H_X), + zeta_power_n_plus_two, + mPtr + ) + point_add_calldata( + add(state, STATE_FOLDED_H_X), + add(state, STATE_FOLDED_H_X), + add(aproof, PROOF_H_0_COM_X), + mPtr + ) + point_mul( + add(state, STATE_FOLDED_H_X), + add(state, STATE_FOLDED_H_X), + mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)), + mPtr + ) + let folded_h_y := mload(add(state, STATE_FOLDED_H_Y)) + folded_h_y := sub(P_MOD, folded_h_y) + mstore(add(state, STATE_FOLDED_H_Y), folded_h_y) + } + + /// @notice check that the opening of the linearised polynomial at zeta is equal to + /// - [ PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ) ] + /// @param aproof pointer to the proof + function compute_opening_linearised_polynomial(aproof) { + let state := mload(0x40) + + // (l(ζ)+β*s1(ζ)+γ) + let s1 + s1 := + mulmod( + calldataload(add(aproof, PROOF_S1_AT_ZETA)), + mload(add(state, STATE_BETA)), + R_MOD + ) + s1 := addmod(s1, mload(add(state, STATE_GAMMA)), R_MOD) + s1 := addmod(s1, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD) + + // (r(ζ)+β*s2(ζ)+γ) + let s2 + s2 := + mulmod( + calldataload(add(aproof, PROOF_S2_AT_ZETA)), + mload(add(state, STATE_BETA)), + R_MOD + ) + s2 := addmod(s2, mload(add(state, STATE_GAMMA)), R_MOD) + s2 := addmod(s2, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD) + + // (o(ζ)+γ) + let o + o := + addmod( + calldataload(add(aproof, PROOF_O_AT_ZETA)), + mload(add(state, STATE_GAMMA)), + R_MOD + ) + + // α*Z(μζ)*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) + s1 := mulmod(s1, s2, R_MOD) + s1 := mulmod(s1, o, R_MOD) + s1 := mulmod(s1, mload(add(state, STATE_ALPHA)), R_MOD) + s1 := + mulmod(s1, calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)), R_MOD) + + // PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ) + s1 := addmod(s1, mload(add(state, STATE_PI)), R_MOD) + s2 := mload(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0)) + s2 := sub(R_MOD, s2) + s1 := addmod(s1, s2, R_MOD) + s1 := sub(R_MOD, s1) + + mstore(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA), s1) + } + + // BEGINNING utils math functions ------------------------------------------------- + + /// @param dst pointer storing the result + /// @param p pointer to the first point + /// @param q pointer to the second point + /// @param mPtr pointer to free memory + function point_add(dst, p, q, mPtr) { + mstore(mPtr, mload(p)) + mstore(add(mPtr, 0x20), mload(add(p, 0x20))) + mstore(add(mPtr, 0x40), mload(q)) + mstore(add(mPtr, 0x60), mload(add(q, 0x20))) + let l_success := staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40) + if iszero(l_success) { error_ec_op() } + } + + /// @param dst pointer storing the result + /// @param p pointer to the first point (calldata) + /// @param q pointer to the second point (calladata) + /// @param mPtr pointer to free memory + function point_add_calldata(dst, p, q, mPtr) { + mstore(mPtr, mload(p)) + mstore(add(mPtr, 0x20), mload(add(p, 0x20))) + mstore(add(mPtr, 0x40), calldataload(q)) + mstore(add(mPtr, 0x60), calldataload(add(q, 0x20))) + let l_success := staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40) + if iszero(l_success) { error_ec_op() } + } + + /// @parma dst pointer storing the result + /// @param src pointer to a point on Bn254(𝔽_p) + /// @param s scalar + /// @param mPtr free memory + function point_mul(dst, src, s, mPtr) { + mstore(mPtr, mload(src)) + mstore(add(mPtr, 0x20), mload(add(src, 0x20))) + mstore(add(mPtr, 0x40), s) + let l_success := staticcall(gas(), EC_MUL, mPtr, 0x60, dst, 0x40) + if iszero(l_success) { error_ec_op() } + } + + /// @parma dst pointer storing the result + /// @param src pointer to a point on Bn254(𝔽_p) on calldata + /// @param s scalar + /// @param mPtr free memory + function point_mul_calldata(dst, src, s, mPtr) { + mstore(mPtr, calldataload(src)) + mstore(add(mPtr, 0x20), calldataload(add(src, 0x20))) + mstore(add(mPtr, 0x40), s) + let l_success := staticcall(gas(), EC_MUL, mPtr, 0x60, dst, 0x40) + if iszero(l_success) { error_ec_op() } + } + + /// @notice dst <- dst + [s]src (Elliptic curve) + /// @param dst pointer accumulator point storing the result + /// @param src pointer to the point to multiply and add + /// @param s scalar + /// @param mPtr free memory + function point_acc_mul(dst, src, s, mPtr) { + mstore(mPtr, mload(src)) + mstore(add(mPtr, 0x20), mload(add(src, 0x20))) + mstore(add(mPtr, 0x40), s) + let l_success := staticcall(gas(), 7, mPtr, 0x60, mPtr, 0x40) + mstore(add(mPtr, 0x40), mload(dst)) + mstore(add(mPtr, 0x60), mload(add(dst, 0x20))) + l_success := and(l_success, staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40)) + if iszero(l_success) { error_ec_op() } + } + + /// @notice dst <- dst + [s]src (Elliptic curve) + /// @param dst pointer accumulator point storing the result + /// @param src pointer to the point to multiply and add (on calldata) + /// @param s scalar + /// @mPtr free memory + function point_acc_mul_calldata(dst, src, s, mPtr) { + mstore(mPtr, calldataload(src)) + mstore(add(mPtr, 0x20), calldataload(add(src, 0x20))) + mstore(add(mPtr, 0x40), s) + let l_success := staticcall(gas(), 7, mPtr, 0x60, mPtr, 0x40) + mstore(add(mPtr, 0x40), mload(dst)) + mstore(add(mPtr, 0x60), mload(add(dst, 0x20))) + l_success := and(l_success, staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40)) + if iszero(l_success) { error_ec_op() } + } + + /// @notice dst <- dst + src*s (Fr) dst,src are addresses, s is a value + /// @param dst pointer storing the result + /// @param src pointer to the scalar to multiply and add (on calldata) + /// @param s scalar + function fr_acc_mul_calldata(dst, src, s) { + let tmp := mulmod(calldataload(src), s, R_MOD) + mstore(dst, addmod(mload(dst), tmp, R_MOD)) + } + + /// @param x element to exponentiate + /// @param e exponent + /// @param mPtr free memory + /// @return res x ** e mod r + function pow(x, e, mPtr) -> res { + mstore(mPtr, 0x20) + mstore(add(mPtr, 0x20), 0x20) + mstore(add(mPtr, 0x40), 0x20) + mstore(add(mPtr, 0x60), x) + mstore(add(mPtr, 0x80), e) + mstore(add(mPtr, 0xa0), R_MOD) + let check_staticcall := staticcall(gas(), MOD_EXP, mPtr, 0xc0, mPtr, 0x20) + if eq(check_staticcall, 0) { error_mod_exp() } + res := mload(mPtr) + } + } + } +} diff --git a/contracts/src/v3.0.0-rc3/SP1VerifierGroth16.sol b/contracts/src/v3.0.0-rc3/SP1VerifierGroth16.sol new file mode 100644 index 0000000..af3c378 --- /dev/null +++ b/contracts/src/v3.0.0-rc3/SP1VerifierGroth16.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol"; +import {Groth16Verifier} from "./Groth16Verifier.sol"; + +/// @title SP1 Verifier +/// @author Succinct Labs +/// @notice This contracts implements a solidity verifier for SP1. +contract SP1Verifier is Groth16Verifier, ISP1VerifierWithHash { + /// @notice Thrown when the verifier selector from this proof does not match the one in this + /// verifier. This indicates that this proof was sent to the wrong verifier. + /// @param received The verifier selector from the first 4 bytes of the proof. + /// @param expected The verifier selector from the first 4 bytes of the VERIFIER_HASH(). + error WrongVerifierSelector(bytes4 received, bytes4 expected); + + /// @notice Thrown when the proof is invalid. + error InvalidProof(); + + function VERSION() external pure returns (string memory) { + return "v3.0.0-rc3"; + } + + /// @inheritdoc ISP1VerifierWithHash + function VERIFIER_HASH() public pure returns (bytes32) { + return 0x91ff06f39e5cd2f9f006af3648c2eaea784d33f41e5e763d8a25ba5d999a15c3; + } + + /// @notice Hashes the public values to a field elements inside Bn254. + /// @param publicValues The public values. + function hashPublicValues(bytes calldata publicValues) public pure returns (bytes32) { + return sha256(publicValues) & bytes32(uint256((1 << 253) - 1)); + } + + /// @notice Verifies a proof with given public values and vkey. + /// @param programVKey The verification key for the RISC-V program. + /// @param publicValues The public values encoded as bytes. + /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes. + function verifyProof( + bytes32 programVKey, + bytes calldata publicValues, + bytes calldata proofBytes + ) external view { + bytes4 receivedSelector = bytes4(proofBytes[:4]); + bytes4 expectedSelector = bytes4(VERIFIER_HASH()); + if (receivedSelector != expectedSelector) { + revert WrongVerifierSelector(receivedSelector, expectedSelector); + } + + bytes32 publicValuesDigest = hashPublicValues(publicValues); + uint256[2] memory inputs; + inputs[0] = uint256(programVKey); + inputs[1] = uint256(publicValuesDigest); + uint256[8] memory proof = abi.decode(proofBytes[4:], (uint256[8])); + this.Verify(proof, inputs); + } +} diff --git a/contracts/src/v3.0.0-rc3/SP1VerifierPlonk.sol b/contracts/src/v3.0.0-rc3/SP1VerifierPlonk.sol new file mode 100644 index 0000000..787559b --- /dev/null +++ b/contracts/src/v3.0.0-rc3/SP1VerifierPlonk.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol"; +import {PlonkVerifier} from "./PlonkVerifier.sol"; + +/// @title SP1 Verifier +/// @author Succinct Labs +/// @notice This contracts implements a solidity verifier for SP1. +contract SP1Verifier is PlonkVerifier, ISP1VerifierWithHash { + /// @notice Thrown when the verifier selector from this proof does not match the one in this + /// verifier. This indicates that this proof was sent to the wrong verifier. + /// @param received The verifier selector from the first 4 bytes of the proof. + /// @param expected The verifier selector from the first 4 bytes of the VERIFIER_HASH(). + error WrongVerifierSelector(bytes4 received, bytes4 expected); + + /// @notice Thrown when the proof is invalid. + error InvalidProof(); + + function VERSION() external pure returns (string memory) { + return "v3.0.0-rc3"; + } + + /// @inheritdoc ISP1VerifierWithHash + function VERIFIER_HASH() public pure returns (bytes32) { + return 0x8fd4de72c19847e867bb1609db3cf91ecd6228e01aa061039b02d3059bc43d88; + } + + /// @notice Hashes the public values to a field elements inside Bn254. + /// @param publicValues The public values. + function hashPublicValues(bytes calldata publicValues) public pure returns (bytes32) { + return sha256(publicValues) & bytes32(uint256((1 << 253) - 1)); + } + + /// @notice Verifies a proof with given public values and vkey. + /// @param programVKey The verification key for the RISC-V program. + /// @param publicValues The public values encoded as bytes. + /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes. + function verifyProof( + bytes32 programVKey, + bytes calldata publicValues, + bytes calldata proofBytes + ) external view { + bytes4 receivedSelector = bytes4(proofBytes[:4]); + bytes4 expectedSelector = bytes4(VERIFIER_HASH()); + if (receivedSelector != expectedSelector) { + revert WrongVerifierSelector(receivedSelector, expectedSelector); + } + + bytes32 publicValuesDigest = hashPublicValues(publicValues); + uint256[] memory inputs = new uint256[](2); + inputs[0] = uint256(programVKey); + inputs[1] = uint256(publicValuesDigest); + bool success = this.Verify(proofBytes[4:], inputs); + if (!success) { + revert InvalidProof(); + } + } +} diff --git a/src/bin/artifacts.rs b/src/bin/artifacts.rs index dd4097a..467f5ee 100644 --- a/src/bin/artifacts.rs +++ b/src/bin/artifacts.rs @@ -2,31 +2,45 @@ use anyhow::Result; use log::info; use sp1_sdk::install::try_install_circuit_artifacts; use sp1_sdk::utils::setup_logger; +use std::fs::{create_dir_all, read, read_dir, write}; +use std::path::PathBuf; fn main() -> Result<()> { dotenv::dotenv().ok(); setup_logger(); - let artifacts_dir = try_install_circuit_artifacts(); - - info!("Artifacts installed to: {:?}", artifacts_dir); - - // Read all Solidity files from the artifacts_dir. - let sol_files = std::fs::read_dir(artifacts_dir)? - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.path().extension().and_then(|ext| ext.to_str()) == Some("sol")) - .collect::>(); - - // Write each Solidity file to the contracts directory. - let contracts_src_dir = std::path::Path::new("contracts/src"); - for sol_file in sol_files { - let sol_file_path = sol_file.path(); - let sol_file_contents = std::fs::read(&sol_file_path)?; - std::fs::write( - contracts_src_dir.join(sol_file_path.file_name().unwrap()), - sol_file_contents, - )?; + let artifact_types = ["plonk", "groth16"]; + let mut artifact_dirs = Vec::new(); + + for &artifact_type in &artifact_types { + let artifacts_dir = try_install_circuit_artifacts(artifact_type); + info!( + "{} artifacts installed to: {:?}", + artifact_type, artifacts_dir + ); + artifact_dirs.push(artifacts_dir); + } + + // Read all Solidity files from the artifacts directories. + let contracts_src_dir = PathBuf::from("contracts/src"); + create_dir_all(&contracts_src_dir)?; + + for artifacts_dir in artifact_dirs { + let sol_files = read_dir(artifacts_dir)? + .filter_map(|entry| entry.ok()) + .filter(|entry| entry.path().extension().and_then(|ext| ext.to_str()) == Some("sol")) + .collect::>(); + + // Write each Solidity file to the contracts directory. + for sol_file in sol_files { + let sol_file_path = sol_file.path(); + let sol_file_contents = read(&sol_file_path)?; + write( + contracts_src_dir.join(sol_file_path.file_name().unwrap()), + sol_file_contents, + )?; + } } Ok(()) From 20d8187bec85d96b26d1028ccf7e03f569914456 Mon Sep 17 00:00:00 2001 From: mattstam Date: Wed, 9 Oct 2024 16:22:37 -0700 Subject: [PATCH 2/3] deployed --- README.md | 8 ++++---- contracts/deployments/11155111.json | 4 +++- contracts/deployments/11155420.json | 4 +++- contracts/deployments/17000.json | 4 +++- contracts/deployments/421614.json | 4 +++- contracts/deployments/534351.json | 4 +++- contracts/deployments/84532.json | 4 +++- .../script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol | 2 +- contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol | 2 +- 9 files changed, 24 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 2634313..a7b9764 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ FOUNDRY_PROFILE=deploy forge script ./script/deploy/SP1VerifierGateway.s.sol:SP1 To deploy a specific SP1 Verifier version and add it to the gateway, run: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0-rc1/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast ``` -Change `v3.0.0-rc1` to the desired version to add. +Change `v3.0.0-rc3` to the desired version to add. To re-verify already existing deployments, remove the `--broadcast` flag. @@ -71,10 +71,10 @@ To re-verify already existing deployments, remove the `--broadcast` flag. To freeze a verifier on the gateway, run: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0-rc1/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast --sig "freeze()" +FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast --sig "freeze()" ``` -Change `v3.0.0-rc1` to the desired version to freeze. +Change `v3.0.0-rc3` to the desired version to freeze. ## For Developers: Integrate SP1 Contracts diff --git a/contracts/deployments/11155111.json b/contracts/deployments/11155111.json index 6befa0d..88f6533 100644 --- a/contracts/deployments/11155111.json +++ b/contracts/deployments/11155111.json @@ -10,5 +10,7 @@ "V1_2_0_SP1_VERIFIER_PLONK": "0xc7Ed5531Fd663809Fc2C618f221933Cb3334e54B", "V2_0_0_SP1_VERIFIER_GROTH16": "0x202dd4a519b2cAaCc9455BB670FE7950c0e40026", "V2_0_0_SP1_VERIFIER_PLONK": "0xaeE21CeadF7A03b3034DAE4f190bFE5F861b6ebf", - "V3_0_0_RC1_SP1_VERIFIER_GROTH16": "0x8dB92f28D7C30154d38E55DbA1054b5A7Fc5A829" + "V3_0_0_RC1_SP1_VERIFIER_GROTH16": "0x8dB92f28D7C30154d38E55DbA1054b5A7Fc5A829", + "V3_0_0_RC3_SP1_VERIFIER_GROTH16": "0x890E1c4ff98453f1201e5cB65F6C588FD28748b0", + "V3_0_0_RC3_SP1_VERIFIER_PLONK": "0x31aeD863BecC509B9e16403c52C07560A0d4ecBf" } \ No newline at end of file diff --git a/contracts/deployments/11155420.json b/contracts/deployments/11155420.json index c54d7c4..ccfab9d 100644 --- a/contracts/deployments/11155420.json +++ b/contracts/deployments/11155420.json @@ -4,5 +4,7 @@ "V2_0_0_SP1_VERIFIER_GROTH16": "0x202dd4a519b2cAaCc9455BB670FE7950c0e40026", "V2_0_0_SP1_VERIFIER_PLONK": "0xaeE21CeadF7A03b3034DAE4f190bFE5F861b6ebf", "V3_0_0_RC1_SP1_VERIFIER_GROTH16": "0x8dB92f28D7C30154d38E55DbA1054b5A7Fc5A829", - "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A" + "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A", + "V3_0_0_RC3_SP1_VERIFIER_GROTH16": "0x890E1c4ff98453f1201e5cB65F6C588FD28748b0", + "V3_0_0_RC3_SP1_VERIFIER_PLONK": "0x31aeD863BecC509B9e16403c52C07560A0d4ecBf" } \ No newline at end of file diff --git a/contracts/deployments/17000.json b/contracts/deployments/17000.json index 83b7e38..80f6067 100644 --- a/contracts/deployments/17000.json +++ b/contracts/deployments/17000.json @@ -11,5 +11,7 @@ "V2_0_0_SP1_VERIFIER_GROTH16": "0x202dd4a519b2cAaCc9455BB670FE7950c0e40026", "V2_0_0_SP1_VERIFIER_PLONK": "0xaeE21CeadF7A03b3034DAE4f190bFE5F861b6ebf", "V3_0_0_RC1_SP1_VERIFIER_GROTH16": "0x8dB92f28D7C30154d38E55DbA1054b5A7Fc5A829", - "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A" + "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A", + "V3_0_0_RC3_SP1_VERIFIER_GROTH16": "0x890E1c4ff98453f1201e5cB65F6C588FD28748b0", + "V3_0_0_RC3_SP1_VERIFIER_PLONK": "0x31aeD863BecC509B9e16403c52C07560A0d4ecBf" } \ No newline at end of file diff --git a/contracts/deployments/421614.json b/contracts/deployments/421614.json index 83b7e38..80f6067 100644 --- a/contracts/deployments/421614.json +++ b/contracts/deployments/421614.json @@ -11,5 +11,7 @@ "V2_0_0_SP1_VERIFIER_GROTH16": "0x202dd4a519b2cAaCc9455BB670FE7950c0e40026", "V2_0_0_SP1_VERIFIER_PLONK": "0xaeE21CeadF7A03b3034DAE4f190bFE5F861b6ebf", "V3_0_0_RC1_SP1_VERIFIER_GROTH16": "0x8dB92f28D7C30154d38E55DbA1054b5A7Fc5A829", - "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A" + "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A", + "V3_0_0_RC3_SP1_VERIFIER_GROTH16": "0x890E1c4ff98453f1201e5cB65F6C588FD28748b0", + "V3_0_0_RC3_SP1_VERIFIER_PLONK": "0x31aeD863BecC509B9e16403c52C07560A0d4ecBf" } \ No newline at end of file diff --git a/contracts/deployments/534351.json b/contracts/deployments/534351.json index 83b7e38..80f6067 100644 --- a/contracts/deployments/534351.json +++ b/contracts/deployments/534351.json @@ -11,5 +11,7 @@ "V2_0_0_SP1_VERIFIER_GROTH16": "0x202dd4a519b2cAaCc9455BB670FE7950c0e40026", "V2_0_0_SP1_VERIFIER_PLONK": "0xaeE21CeadF7A03b3034DAE4f190bFE5F861b6ebf", "V3_0_0_RC1_SP1_VERIFIER_GROTH16": "0x8dB92f28D7C30154d38E55DbA1054b5A7Fc5A829", - "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A" + "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A", + "V3_0_0_RC3_SP1_VERIFIER_GROTH16": "0x890E1c4ff98453f1201e5cB65F6C588FD28748b0", + "V3_0_0_RC3_SP1_VERIFIER_PLONK": "0x31aeD863BecC509B9e16403c52C07560A0d4ecBf" } \ No newline at end of file diff --git a/contracts/deployments/84532.json b/contracts/deployments/84532.json index 83b7e38..80f6067 100644 --- a/contracts/deployments/84532.json +++ b/contracts/deployments/84532.json @@ -11,5 +11,7 @@ "V2_0_0_SP1_VERIFIER_GROTH16": "0x202dd4a519b2cAaCc9455BB670FE7950c0e40026", "V2_0_0_SP1_VERIFIER_PLONK": "0xaeE21CeadF7A03b3034DAE4f190bFE5F861b6ebf", "V3_0_0_RC1_SP1_VERIFIER_GROTH16": "0x8dB92f28D7C30154d38E55DbA1054b5A7Fc5A829", - "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A" + "V3_0_0_RC1_SP1_VERIFIER_PLONK": "0xCf5bB55AaE25b5A66CEfbe85d81b7b144472102A", + "V3_0_0_RC3_SP1_VERIFIER_GROTH16": "0x890E1c4ff98453f1201e5cB65F6C588FD28748b0", + "V3_0_0_RC3_SP1_VERIFIER_PLONK": "0x31aeD863BecC509B9e16403c52C07560A0d4ecBf" } \ No newline at end of file diff --git a/contracts/script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol b/contracts/script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol index e307f3d..028fb7c 100644 --- a/contracts/script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol +++ b/contracts/script/deploy/v3.0.0-rc3/SP1VerifierGroth16.s.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import {BaseScript} from "../../utils/Base.s.sol"; -import {SP1Verifier} from "../../../src/v3.0.0-rc1/SP1VerifierGroth16.sol"; +import {SP1Verifier} from "../../../src/v3.0.0-rc3/SP1VerifierGroth16.sol"; import {SP1VerifierGateway} from "../../../src/SP1VerifierGateway.sol"; import {ISP1VerifierWithHash} from "../../../src/ISP1Verifier.sol"; diff --git a/contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol b/contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol index 5d4c8f0..6e6f095 100644 --- a/contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol +++ b/contracts/script/deploy/v3.0.0-rc3/SP1VerifierPlonk.s.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import {BaseScript} from "../../utils/Base.s.sol"; -import {SP1Verifier} from "../../../src/v3.0.0-rc1/SP1VerifierPlonk.sol"; +import {SP1Verifier} from "../../../src/v3.0.0-rc3/SP1VerifierPlonk.sol"; import {SP1VerifierGateway} from "../../../src/SP1VerifierGateway.sol"; import {ISP1VerifierWithHash} from "../../../src/ISP1Verifier.sol"; From eba16345a6f82badd04ef6a9a632b6b654044144 Mon Sep 17 00:00:00 2001 From: mattstam Date: Thu, 10 Oct 2024 10:53:35 -0700 Subject: [PATCH 3/3] tests --- contracts/test/SP1VerifierGroth16.t.sol | 6 +++--- contracts/test/SP1VerifierPlonk.t.sol | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/test/SP1VerifierGroth16.t.sol b/contracts/test/SP1VerifierGroth16.t.sol index 98d2099..4bb2976 100644 --- a/contracts/test/SP1VerifierGroth16.t.sol +++ b/contracts/test/SP1VerifierGroth16.t.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.20; import {Test, console} from "forge-std/Test.sol"; -import {SP1Verifier} from "../src/v3.0.0-rc1/SP1VerifierGroth16.sol"; +import {SP1Verifier} from "../src/v3.0.0-rc3/SP1VerifierGroth16.sol"; contract SP1VerifierGroth16Test is Test { bytes32 internal constant PROGRAM_VKEY = - bytes32(0x00db1ca9cf1872ef132764a5aef4069a050266d812fbd95dce4fa860e2279857); + bytes32(0x0031d9b929d13038eb7c25790617a5ff09d3e3f6d20fc3f0bb70ada6c20206cd); bytes internal constant PUBLIC_VALUES = hex"00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000001a6d0000000000000000000000000000000000000000000000000000000000002ac2"; bytes internal constant PROOF_VALID = - hex"5a1551d6138ff2379a9dc37c74bd85b5bf2c8aa677cb7655a6a91ac9609562dad8713a9d09ecb18f364d52de4e3946fa2f4ab75f60ffb3afad55de922579c02155c7aec71dc3335c901100e27a7e649236a89872133b0795880aa734ed6c8f4389fa29920da901c946af91c2cd6a44cd6146893d49360abd7e39a3df043212430aeb2fe20b75270abb643988229fa996298829e8dec6f48e75905a0d3a6cc24fa1309876196652e95d1e835255934761c05f89e95086e3fcfd832068a25baecbfb2fe71c2b73057a7f78e1417d61ab52943a1a3f2a0b8efbb4f8262b712797205c95fd6b03e2abc41070a37f6672fb56a0e90a61c893458fa35f693a14072f759d045d44"; + hex"91ff06f3018012469797b672088e11fce5cf3b24608cbdf85609cd5f514d72683583ac531f17401a7e6dc84bc674dc9fbbf30f4ec6208ab587267e46269b728ffcb5ac4d2c3951eaf5b3c082750ac6ca369772a0907fd5dc02b01f6ff23cd4396f8f510c1a453dd45f069c48b6b4e597cf169237a08594f914ee2c188f1b89c2444029f51890876a3e64d57483554d818c0b55c8ceeb08983d5ba682a7854a2dfd6403b824a130c4a04118265db2925450ce879e15473d91280ab46f5d5779ac22eff16b044faba38a646c92d4ab8454bf0142bb8cffdd56a6c922aff15d55a8f0ce70860b883b929f6ca1afe2f0c774862093adf13ea8eefdcd9186d0c7d6d25fbf8a51"; bytes internal constant PROOF_INVALID = hex"1b5a112d1e86fe060a33eb57cd5925bd7dc008d32908cdc747fa33650a996d292d4e"; diff --git a/contracts/test/SP1VerifierPlonk.t.sol b/contracts/test/SP1VerifierPlonk.t.sol index 0f07f50..6e9a70c 100644 --- a/contracts/test/SP1VerifierPlonk.t.sol +++ b/contracts/test/SP1VerifierPlonk.t.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.20; import {Test, console} from "forge-std/Test.sol"; -import {SP1Verifier} from "../src/v3.0.0-rc1/SP1VerifierPlonk.sol"; +import {SP1Verifier} from "../src/v3.0.0-rc3/SP1VerifierPlonk.sol"; contract SP1VerifierPlonkTest is Test { bytes32 internal constant PROGRAM_VKEY = - bytes32(0x00db1ca9cf1872ef132764a5aef4069a050266d812fbd95dce4fa860e2279857); + bytes32(0x0031d9b929d13038eb7c25790617a5ff09d3e3f6d20fc3f0bb70ada6c20206cd); bytes internal constant PUBLIC_VALUES = hex"00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000001a6d0000000000000000000000000000000000000000000000000000000000002ac2"; bytes internal constant PROOF_VALID = - hex"ffea2d2e0c7f6c4a0feccc7692e18d99dc16b071cd62c017a2d0bb18f73fa60e612b7ffe0528ffdf93b7b3e0057302f53c4cb875471c672b2c02d101e39e6c5e291540812c46dd4e558decb38a1480b497cbc826b435dd5f327972b0a8a45a694d787713212bcff516f1a679f328286659550a0466cc63c84a49581121201d7c98d749952008b8c0a2c83a4028e32418d8548fddc4481feb13b0a2396073fa1e56faec992cb8924777c823a581f33c092795be803e6a004a8ae16b9b7edf4d5b6047c89829face1d013326ae91b944adbac6f8195d320f82204af199f98274dff5b1f0d40ac090e5b80ec3a78c9544cf69e46b6efc4cd6361b2757f47a6fd2519ff49d8e1827d226f7159837f7449b6d1c062d2848847e3879a338fba9336307b44bc2031dc0ee955b64b7120f3e602aacd23d0ffc524c5c6d9ee540ffc5012eb57ea7b40689cdc0dbbda03cc7e4e0d639cb6e4fa874659cb0e8051336f5ae4c3702d7fa245928dc646ac701afb9a1f540e8b51bd279e401b99b91a5e5f96c13f7471a2c1eae88ca333acf41959b37e277d277580d50c709d8f84c72ddb81d85ff73f4e30c054203abfe489646ccffa50d18e7d9f5d78fac07ef313b8fc49f9a6505536122195b5485f9f5bc8a59740ec969b6081e50589767dbe270372b8d0eb2ecca5d05c2e25f27a2b0ce86c5b485de46235fadf58f0b3a0b8cddee95f81d4f178d9620153bcd8eec1da3aac7173ff70bb65a756b266ccbd1f981fcc4ed53e60616630ce5337e3c834ad44149ad668c9cb4fab88649af2be713431ea104d50ff35baf195fc1aa0b9732abfc0e9a22166aaa91e02a89d5add6f587cc7478554c8f4f790de472dd2d043f1b367632532b3ef8e01439ea589edc005e22ada1cc5956308b22e06674ff6af1078e16a6f67b72ca104fb183b5c8b1679123376c0399200fca2a32d8519461d465254560ad74e88aac20e2e8d465e8281115146beda6014128222f76b1558ddef907e98866417f70052b5a49767e41f9467c8a5ffb989a2dbe092723320566d586837f62971a2c410e383a83ac59a6fbbd03d9a7f3286fe21e0c02efbe6d33542e4daaa4f1b51068838dac6a816c0551679c9df3b09b40018512241d56c8eebe806a3de293ffbfb72ad00df6a915328f291d54f739f58553e41dcd0e60f9a7bdfc800f989475f5845efef1c5b3624d195c7dae681659c6d51d"; + hex"8fd4de721d6b0469a8040ae7157416844a099d215a218823b5eb39f5954beb654bb8a59f121e84cb80615c90a1ca83cbe6f4df4feae814933e9b8283e1ddbf4e9ef8673221c137d5464f5dd1375ed251fb67ec4d3aae7e7ac818fe7a2682fe7cab14dfb52175f23f1126869f63a2d78811783495fc6c3fc6cef4b4bb140883333fde86870c79a31a6dccfda11845a88deb8aea1b2739e24687a1b19550a1c6fad9fa438f118783416eb7cccc2b787b47039a0ae8fbb76ef0f84ac4bdf43c765d6f0f9d280b8db03225f82e8b6e2aee618d147f2547886c0f8f93e1f3bd844d7c549efe1c013420234a546cdaced9ae4c1be703b97f4250224e194152e13a7edd98984f5c008458712126d0fbedadbf6cf4cfc7c8be3f34a4bc4113ba8a1350f5134f315b065168bd7fa00715524c8c2a8912b54a1f37020d6f2b22e5a97153ee110540ef17909099a8c5fb056c7f8af19e6592d7ce841e1e4942fddb284c7a38aea4b2be1c6ce791a36c321b5185933ba44e42dfe9ddc4744b237f7090979261e39e4ce223d3b29ca347f5b765f6a7167901ee1819ff062b7a8e8c1af30cefb4950828491b0e4a3630525b4a02f129fd15fdc7c5c24f4b72668804b11bb7d4a9afe61c7f007ab65f996918dec04120c08dfb2a0cec01ef011c4f798c1432a88f9127a1700565edf0b4414852a52c61cd7dcb343416614bbbfe4f17437f68cc745432b70a25222217caf9aa90ff1fb961e30a3ce9279bcb8422dd2d2b371e461c7faaff78255e22f51ecb25a8695d9ddecbfbc0f42bbb85d515968a61f75fa68fb3ab28dd01943c624f59599167f96202ebb1d464f822b30639ac54baeeab57cf11364b6912e6ca69362c80e34ea68ff150ed0f70c881b0be58cba471ae4f1b21f2d688bd1fd245467fecd7807ce407a014b7a6ccac8460508773c447efc072db28fa2b0b217485075491257e42c4b5bb3544f6eae2686e0861032e9b9573b0266516f59e0e016fa249be783d736f912276f9918ac93a75ffba0a8b2f26921cdd0a6599a10d06f79ceca9bbd7636ed3a25f2055b4ae864b17f0d19d0aee604aac155f6b390fb70e573a97c08b4b149e3c235573fa9ecb7746d5c907f89d7e771fb560d02c0e8da26a5de94bc501051cb976085e693080afd6bb35752f171dbb662d1ec6df1fcc582d047dc5d9cfe1f5ea36d0e0d8befd4f9f13ec70aeb01c026c94deae2e"; bytes internal constant PROOF_INVALID = hex"616a42052115dd50acf8e57f10c32ca72a6940"; address internal verifier;