diff --git a/Cargo.lock b/Cargo.lock index b2eba1c80d..04361d85f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,14 +51,14 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -323,7 +323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d162f8524adfdfb0e4bd0505c734c985f3e2474eb022af32eef0d52a4f3935c" dependencies = [ "serde", - "winnow 0.7.9", + "winnow 0.7.10", ] [[package]] @@ -425,15 +425,6 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "ariadne" version = "0.2.0" @@ -852,9 +843,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878" +checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" dependencies = [ "aws-lc-sys", "zeroize", @@ -862,9 +853,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.28.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1" +checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" dependencies = [ "bindgen", "cc", @@ -900,9 +891,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.83.0" +version = "1.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51384750334005f40e1a334b0d54eca822a77eacdcf3c50fdf38f583c5eee7a2" +checksum = "d5c82dae9304e7ced2ff6cca43dceb2d6de534c95a506ff0f168a7463c9a885d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -935,9 +926,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.65.0" +version = "1.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8efec445fb78df585327094fcef4cad895b154b58711e504db7a93c41aa27151" +checksum = "0d4863da26489d1e6da91d7e12b10c17e86c14f94c53f416bd10e0a9c34057ba" dependencies = [ "aws-credential-types", "aws-runtime", @@ -958,9 +949,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.66.0" +version = "1.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e49cca619c10e7b002dc8e66928ceed66ab7f56c1a3be86c5437bf2d8d89bba" +checksum = "95caa3998d7237789b57b95a8e031f60537adab21fa84c91e35bef9455c652e4" dependencies = [ "aws-credential-types", "aws-runtime", @@ -981,9 +972,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.66.0" +version = "1.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7420479eac0a53f776cc8f0d493841ffe58ad9d9783f3947be7265784471b47a" +checksum = "4939f6f449a37308a78c5a910fd91265479bd2bb11d186f0b8fc114d89ec828d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1098,14 +1089,14 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aff1159006441d02e57204bf57a1b890ba68bedb6904ffd2873c1c4c11c546b" +checksum = "7e44697a9bded898dcd0b1cb997430d949b87f4f8940d91023ae9062bf218250" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "h2 0.4.9", + "h2 0.4.10", "http 0.2.12", "http 1.3.1", "http-body 0.4.6", @@ -1116,7 +1107,7 @@ dependencies = [ "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.26", + "rustls 0.23.27", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", @@ -1244,9 +1235,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -1612,11 +1603,10 @@ dependencies = [ [[package]] name = "c-kzg" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7e3c397401eb76228c89561cf22f85f41c95aa799ee9d860de3ea1cbc728fc" +checksum = "7318cfa722931cb5fe0838b98d3ce5621e75f6a6408abc21721d80de9223f2e4" dependencies = [ - "arbitrary", "blst", "cc", "glob", @@ -1692,9 +1682,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.21" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" dependencies = [ "jobserver", "libc", @@ -1779,9 +1769,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -1789,9 +1779,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstream", "anstyle", @@ -2002,9 +1992,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -2289,17 +2279,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "derive_more" version = "0.99.20" @@ -3082,9 +3061,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", @@ -3192,9 +3171,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", @@ -3418,9 +3397,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "hex" @@ -3565,7 +3544,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.9", + "h2 0.4.10", "http 1.3.1", "http-body 1.0.1", "httparse", @@ -3602,7 +3581,7 @@ dependencies = [ "http 1.3.1", "hyper 1.6.0", "hyper-util", - "rustls 0.23.26", + "rustls 0.23.27", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", @@ -3656,21 +3635,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -3679,31 +3659,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -3711,67 +3671,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -3791,9 +3738,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -3892,7 +3839,7 @@ version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.5.0", + "hermit-abi 0.5.1", "libc", "windows-sys 0.59.0", ] @@ -3960,7 +3907,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -4085,19 +4032,19 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] name = "libm" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" @@ -4197,9 +4144,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" @@ -4747,6 +4694,8 @@ dependencies = [ "derive_more 1.0.0", "eyre", "openvm-benchmarks-utils", + "openvm-bigint-circuit", + "openvm-bigint-transpiler", "openvm-circuit", "openvm-rv32im-circuit", "openvm-rv32im-transpiler", @@ -6421,6 +6370,15 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -6433,7 +6391,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.25", + "zerocopy", ] [[package]] @@ -6658,7 +6616,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "serde", ] @@ -6702,9 +6660,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags 2.9.0", ] @@ -7213,14 +7171,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.26" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "aws-lc-rs", "once_cell", "rustls-pki-types", - "rustls-webpki 0.103.1", + "rustls-webpki 0.103.3", "subtle", "zeroize", ] @@ -7260,9 +7218,12 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] [[package]] name = "rustls-webpki" @@ -7276,9 +7237,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "aws-lc-rs", "ring", @@ -8008,12 +7969,12 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix 1.0.7", "windows-sys 0.59.0", @@ -8218,9 +8179,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -8238,9 +8199,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -8280,7 +8241,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.26", + "rustls 0.23.27", "tokio", ] @@ -8355,7 +8316,7 @@ dependencies = [ "serde_spanned", "toml_datetime", "toml_write", - "winnow 0.7.9", + "winnow 0.7.10", ] [[package]] @@ -8575,12 +8536,6 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -8599,7 +8554,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -8922,13 +8877,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -8941,6 +8912,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -8953,6 +8930,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -8965,12 +8948,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -8983,6 +8978,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -8995,6 +8996,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -9007,6 +9014,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -9019,6 +9032,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.5.40" @@ -9030,9 +9049,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -9056,17 +9075,11 @@ dependencies = [ "bitflags 2.9.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -9097,9 +9110,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -9109,9 +9122,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -9119,33 +9132,13 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - [[package]] name = "zerocopy" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.25", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", + "zerocopy-derive", ] [[package]] @@ -9200,11 +9193,22 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -9213,9 +9217,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/benchmarks/execute/Cargo.toml b/benchmarks/execute/Cargo.toml index db554f5489..bcf726a6bb 100644 --- a/benchmarks/execute/Cargo.toml +++ b/benchmarks/execute/Cargo.toml @@ -16,6 +16,8 @@ openvm-stark-sdk.workspace = true openvm-transpiler.workspace = true openvm-rv32im-circuit.workspace = true openvm-rv32im-transpiler.workspace = true +openvm-bigint-circuit.workspace = true +openvm-bigint-transpiler.workspace = true # openvm-keccak256-circuit.workspace = true # openvm-keccak256-transpiler.workspace = true diff --git a/benchmarks/execute/benches/execute.rs b/benchmarks/execute/benches/execute.rs index bcd60f6811..6cb2a60cf3 100644 --- a/benchmarks/execute/benches/execute.rs +++ b/benchmarks/execute/benches/execute.rs @@ -1,10 +1,8 @@ -use std::path::PathBuf; - -use divan; use eyre::Result; use openvm_benchmarks_utils::{get_elf_path, get_programs_dir, read_elf_file}; +use openvm_bigint_circuit::Int256Rv32Config; +use openvm_bigint_transpiler::Int256TranspilerExtension; use openvm_circuit::arch::{instructions::exe::VmExe, VmExecutor}; -use openvm_rv32im_circuit::Rv32ImConfig; use openvm_rv32im_transpiler::{ Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension, }; @@ -16,13 +14,14 @@ static AVAILABLE_PROGRAMS: &[&str] = &[ "fibonacci_iterative", "quicksort", "bubblesort", + "factorial_iterative_u256", + "revm_snailtracer", // "pairing", // "keccak256", // "keccak256_iter", // "sha256", // "sha256_iter", // "revm_transfer", - // "revm_snailtracer", ]; fn main() { @@ -35,12 +34,13 @@ fn run_program(program: &str) -> Result<()> { let elf_path = get_elf_path(&program_dir); let elf = read_elf_file(&elf_path)?; - let vm_config = Rv32ImConfig::default(); + let vm_config = Int256Rv32Config::default(); let transpiler = Transpiler::::default() .with_extension(Rv32ITranspilerExtension) .with_extension(Rv32IoTranspilerExtension) - .with_extension(Rv32MTranspilerExtension); + .with_extension(Rv32MTranspilerExtension) + .with_extension(Int256TranspilerExtension); let exe = VmExe::from_elf(elf, transpiler)?; diff --git a/benchmarks/execute/src/main.rs b/benchmarks/execute/src/main.rs index 9115888898..cd97932f84 100644 --- a/benchmarks/execute/src/main.rs +++ b/benchmarks/execute/src/main.rs @@ -1,12 +1,16 @@ use clap::{Parser, ValueEnum}; use eyre::Result; use openvm_benchmarks_utils::{get_elf_path, get_programs_dir, read_elf_file}; -use openvm_circuit::arch::{instructions::exe::VmExe, VmExecutor}; -use openvm_rv32im_circuit::Rv32ImConfig; +use openvm_bigint_circuit::Int256Rv32Config; +use openvm_bigint_transpiler::Int256TranspilerExtension; +use openvm_circuit::arch::{instructions::exe::VmExe, VirtualMachine, VmExecutor}; use openvm_rv32im_transpiler::{ Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension, }; -use openvm_stark_sdk::{bench::run_with_metric_collection, p3_baby_bear::BabyBear}; +use openvm_stark_sdk::{ + bench::run_with_metric_collection, config::baby_bear_poseidon2::default_engine, + p3_baby_bear::BabyBear, +}; use openvm_transpiler::{transpiler::Transpiler, FromElf}; #[derive(Debug, Clone, ValueEnum)] @@ -22,13 +26,14 @@ static AVAILABLE_PROGRAMS: &[&str] = &[ "fibonacci_iterative", "quicksort", "bubblesort", + "factorial_iterative_u256", + "revm_snailtracer", // "pairing", // "keccak256", // "keccak256_iter", // "sha256", // "sha256_iter", // "revm_transfer", - // "revm_snailtracer", ]; #[derive(Parser)] @@ -113,19 +118,40 @@ fn main() -> Result<()> { // let config_path = program_dir.join(DEFAULT_APP_CONFIG_PATH); // let vm_config = read_config_toml_or_default(&config_path)?.app_vm_config; // let transpiler = vm_config.transpiler; - let vm_config = Rv32ImConfig::default(); + let vm_config = Int256Rv32Config::default(); let transpiler = Transpiler::::default() .with_extension(Rv32ITranspilerExtension) + .with_extension(Rv32MTranspilerExtension) .with_extension(Rv32IoTranspilerExtension) - .with_extension(Rv32MTranspilerExtension); + .with_extension(Int256TranspilerExtension); let exe = VmExe::from_elf(elf, transpiler)?; + let (widths, interactions): (Vec, Vec) = { + let vm = VirtualMachine::new(default_engine(), vm_config.clone()); + let pk = vm.keygen(); + let vk = pk.get_vk(); + vk.inner + .per_air + .iter() + .map(|vk| { + // TODO(ayush): figure out which width to use + // let total_width = vk.params.width.preprocessed.unwrap_or(0) + // + vk.params.width.cached_mains.iter().sum::() + // + vk.params.width.common_main + // + vk.params.width.after_challenge.iter().sum::(); + let total_width = vk.params.width.main_widths().iter().sum::(); + (total_width, vk.symbolic_constraints.interactions.len()) + }) + .unzip() + }; + let executor = VmExecutor::new(vm_config); executor - .execute_e1(exe, vec![]) + .execute_metered(exe.clone(), vec![], widths, interactions) .expect("Failed to execute program"); + tracing::info!("Completed program: {}", program); } tracing::info!("All programs executed successfully"); diff --git a/benchmarks/guest/factorial_iterative_u256/Cargo.toml b/benchmarks/guest/factorial_iterative_u256/Cargo.toml new file mode 100644 index 0000000000..a0abd084d8 --- /dev/null +++ b/benchmarks/guest/factorial_iterative_u256/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +[package] +name = "openvm-factorial-iterative-u256-program" +version = "0.0.0" +edition = "2021" + +[dependencies] +openvm = { path = "../../../crates/toolchain/openvm", features = ["std"] } +openvm-bigint-guest = { path = "../../../extensions/bigint/guest" } + +[features] +default = [] + +[profile.profiling] +inherits = "release" +debug = 2 +strip = false diff --git a/benchmarks/guest/factorial_iterative_u256/elf/openvm-factorial-iterative-u256-program.elf b/benchmarks/guest/factorial_iterative_u256/elf/openvm-factorial-iterative-u256-program.elf new file mode 100755 index 0000000000..222122b27b Binary files /dev/null and b/benchmarks/guest/factorial_iterative_u256/elf/openvm-factorial-iterative-u256-program.elf differ diff --git a/benchmarks/guest/factorial_iterative_u256/openvm.toml b/benchmarks/guest/factorial_iterative_u256/openvm.toml new file mode 100644 index 0000000000..b226887890 --- /dev/null +++ b/benchmarks/guest/factorial_iterative_u256/openvm.toml @@ -0,0 +1,4 @@ +[app_vm_config.rv32i] +[app_vm_config.rv32m] +[app_vm_config.io] +[app_vm_config.bigint] diff --git a/benchmarks/guest/factorial_iterative_u256/src/main.rs b/benchmarks/guest/factorial_iterative_u256/src/main.rs new file mode 100644 index 0000000000..359de19ae7 --- /dev/null +++ b/benchmarks/guest/factorial_iterative_u256/src/main.rs @@ -0,0 +1,16 @@ +use core::hint::black_box; +use openvm as _; +use openvm_bigint_guest::U256; + +// This will overflow but that is fine +const N: u32 = 65_000; + +pub fn main() { + let mut acc = U256::from_u32(1); + let mut i = U256::from_u32(N); + while i > black_box(U256::ZERO) { + acc *= i.clone(); + i -= U256::from_u32(1); + } + black_box(acc); +} diff --git a/benchmarks/guest/fibonacci_iterative/elf/openvm-fibonacci-iterative-program.elf b/benchmarks/guest/fibonacci_iterative/elf/openvm-fibonacci-iterative-program.elf index 888784fb83..a7b1753491 100755 Binary files a/benchmarks/guest/fibonacci_iterative/elf/openvm-fibonacci-iterative-program.elf and b/benchmarks/guest/fibonacci_iterative/elf/openvm-fibonacci-iterative-program.elf differ diff --git a/benchmarks/guest/fibonacci_iterative/src/main.rs b/benchmarks/guest/fibonacci_iterative/src/main.rs index 6c820f4af2..f7ab8ec0f6 100644 --- a/benchmarks/guest/fibonacci_iterative/src/main.rs +++ b/benchmarks/guest/fibonacci_iterative/src/main.rs @@ -1,15 +1,15 @@ use core::hint::black_box; -use openvm as _; +use openvm::io::reveal_u32; -const N: u64 = 500_000; +const N: u32 = 900_000; pub fn main() { - let mut a: u64 = 0; - let mut b: u64 = 1; + let mut a: u32 = 0; + let mut b: u32 = 1; for _ in 0..black_box(N) { - let c: u64 = a.wrapping_add(b); + let c: u32 = a.wrapping_add(b); a = b; b = c; } - black_box(a); + reveal_u32(a, 0); } diff --git a/benchmarks/guest/fibonacci_recursive/elf/openvm-fibonacci-recursive-program.elf b/benchmarks/guest/fibonacci_recursive/elf/openvm-fibonacci-recursive-program.elf index aaacde40d2..8696e249f0 100755 Binary files a/benchmarks/guest/fibonacci_recursive/elf/openvm-fibonacci-recursive-program.elf and b/benchmarks/guest/fibonacci_recursive/elf/openvm-fibonacci-recursive-program.elf differ diff --git a/benchmarks/guest/fibonacci_recursive/src/main.rs b/benchmarks/guest/fibonacci_recursive/src/main.rs index 15fcfc0109..9020bc91ef 100644 --- a/benchmarks/guest/fibonacci_recursive/src/main.rs +++ b/benchmarks/guest/fibonacci_recursive/src/main.rs @@ -1,14 +1,15 @@ use core::hint::black_box; -use openvm as _; +use openvm::io::reveal_u32; -const N: u64 = 26; +const N: u32 = 27; pub fn main() { let n = black_box(N); - black_box(fibonacci(n)); + let result = fibonacci(n); + reveal_u32(result, 0); } -fn fibonacci(n: u64) -> u64 { +fn fibonacci(n: u32) -> u32 { if n == 0 { 0 } else if n == 1 { diff --git a/crates/vm/derive/src/lib.rs b/crates/vm/derive/src/lib.rs index be61d04d56..08a0952ecd 100644 --- a/crates/vm/derive/src/lib.rs +++ b/crates/vm/derive/src/lib.rs @@ -144,14 +144,27 @@ pub fn ins_executor_e1_executor_derive(input: TokenStream) -> TokenStream { impl #impl_generics ::openvm_circuit::arch::InsExecutorE1 for #name #ty_generics #where_clause { fn execute_e1( &mut self, - state: ::openvm_circuit::arch::VmStateMut<::openvm_circuit::system::memory::online::GuestMemory, Ctx>, + state: &mut ::openvm_circuit::arch::VmStateMut<::openvm_circuit::system::memory::online::GuestMemory, Ctx>, instruction: &::openvm_circuit::arch::instructions::instruction::Instruction, ) -> ::openvm_circuit::arch::Result<()> where - F: ::openvm_stark_backend::p3_field::PrimeField32 + F: ::openvm_stark_backend::p3_field::PrimeField32, + Ctx: ::openvm_circuit::arch::execution_mode::E1E2ExecutionCtx, { self.0.execute_e1(state, instruction) } + + fn execute_metered( + &mut self, + state: &mut ::openvm_circuit::arch::VmStateMut<::openvm_circuit::system::memory::online::GuestMemory, ::openvm_circuit::arch::execution_mode::metered::MeteredCtx>, + instruction: &::openvm_circuit::arch::instructions::instruction::Instruction, + chip_index: usize, + ) -> ::openvm_circuit::arch::Result<()> + where + F: ::openvm_stark_backend::p3_field::PrimeField32, + { + self.0.execute_metered(state, instruction, chip_index) + } } } .into() @@ -180,25 +193,46 @@ pub fn ins_executor_e1_executor_derive(input: TokenStream) -> TokenStream { .expect("First generic must be type for Field"); // Use full path ::openvm_circuit... so it can be used either within or outside the vm // crate. Assume F is already generic of the field. - let execute_arms = variants.iter().map(|(variant_name, field)| { + let execute_e1_arms = variants.iter().map(|(variant_name, field)| { let field_ty = &field.ty; quote! { #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::InsExecutorE1<#first_ty_generic>>::execute_e1(x, state, instruction) } }).collect::>(); + let execute_metered_arms = variants.iter().map(|(variant_name, field)| { + let field_ty = &field.ty; + quote! { + #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::InsExecutorE1<#first_ty_generic>>::execute_metered(x, state, instruction, chip_index) + } + }).collect::>(); quote! { impl #impl_generics ::openvm_circuit::arch::InsExecutorE1<#first_ty_generic> for #name #ty_generics { fn execute_e1( &mut self, - state: ::openvm_circuit::arch::VmStateMut<::openvm_circuit::system::memory::online::GuestMemory, Ctx>, + state: &mut ::openvm_circuit::arch::VmStateMut<::openvm_circuit::system::memory::online::GuestMemory, Ctx>, instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<#first_ty_generic>, ) -> ::openvm_circuit::arch::Result<()> + where + #first_ty_generic: ::openvm_stark_backend::p3_field::PrimeField32, + Ctx: ::openvm_circuit::arch::execution_mode::E1E2ExecutionCtx, + { + match self { + #(#execute_e1_arms,)* + } + } + + fn execute_metered( + &mut self, + state: &mut ::openvm_circuit::arch::VmStateMut<::openvm_circuit::system::memory::online::GuestMemory, ::openvm_circuit::arch::execution_mode::metered::MeteredCtx>, + instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<#first_ty_generic>, + chip_index: usize, + ) -> ::openvm_circuit::arch::Result<()> where #first_ty_generic: ::openvm_stark_backend::p3_field::PrimeField32 { match self { - #(#execute_arms,)* + #(#execute_metered_arms,)* } } } diff --git a/crates/vm/src/arch/execution.rs b/crates/vm/src/arch/execution.rs index d64ee84cf2..6ac124aa42 100644 --- a/crates/vm/src/arch/execution.rs +++ b/crates/vm/src/arch/execution.rs @@ -11,7 +11,10 @@ use openvm_stark_backend::{ use serde::{Deserialize, Serialize}; use thiserror::Error; -use super::Streams; +use super::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, + Streams, +}; use crate::system::{ memory::{ online::{GuestMemory, TracingMemory}, @@ -115,8 +118,18 @@ pub trait InstructionExecutor { pub trait InsExecutorE1 { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Result<()> + where + F: PrimeField32, + Ctx: E1E2ExecutionCtx; + + fn execute_metered( + &mut self, + state: &mut VmStateMut, instruction: &Instruction, + chip_index: usize, ) -> Result<()> where F: PrimeField32; @@ -128,14 +141,28 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, ) -> Result<()> where F: PrimeField32, + Ctx: E1E2ExecutionCtx, { self.borrow_mut().execute_e1(state, instruction) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> + where + F: PrimeField32, + { + self.borrow_mut() + .execute_metered(state, instruction, chip_index) + } } impl> InstructionExecutor for RefCell { diff --git a/crates/vm/src/arch/execution_control.rs b/crates/vm/src/arch/execution_control.rs index adc8e93aa4..1be6a166fe 100644 --- a/crates/vm/src/arch/execution_control.rs +++ b/crates/vm/src/arch/execution_control.rs @@ -1,16 +1,7 @@ use openvm_instructions::instruction::Instruction; use openvm_stark_backend::p3_field::PrimeField32; -use super::{ - ExecutionError, ExecutionSegmentState, TracegenCtx, VmChipComplex, VmConfig, VmStateMut, -}; -use crate::{ - arch::{ExecutionState, InsExecutorE1, InstructionExecutor}, - system::memory::{online::GuestMemory, AddressMap, MemoryImage, PAGE_SIZE}, -}; - -/// Check segment every 100 instructions. -const SEGMENT_CHECK_INTERVAL: usize = 100; +use super::{ExecutionError, VmChipComplex, VmConfig, VmSegmentState}; /// Trait for execution control, determining segmentation and stopping conditions pub trait ExecutionControl @@ -21,241 +12,53 @@ where /// Host context type Ctx; - fn new(chip_complex: &VmChipComplex) -> Self; - - /// Determines if execution should stop - // TODO(ayush): rename to should_suspend - fn should_stop(&mut self, chip_complex: &VmChipComplex) - -> bool; - - /// Called before segment execution begins - fn on_segment_start( + /// Determines if execution should suspend + fn should_suspend( &mut self, - pc: u32, - chip_complex: &mut VmChipComplex, - ); + state: &mut VmSegmentState, + chip_complex: &VmChipComplex, + ) -> bool; - // TODO(ayush): maybe combine with on_terminate - /// Called after segment execution completes - fn on_segment_end( + /// Called before execution begins + fn on_start( &mut self, - pc: u32, + state: &mut VmSegmentState, chip_complex: &mut VmChipComplex, ); - /// Called after program termination - fn on_terminate( + /// Called after suspend or terminate + fn on_suspend_or_terminate( &mut self, - pc: u32, + state: &mut VmSegmentState, chip_complex: &mut VmChipComplex, - exit_code: u32, + exit_code: Option, ); - /// Execute a single instruction - // TODO(ayush): change instruction to Instruction / PInstruction - fn execute_instruction( + fn on_suspend( &mut self, - vm_state: &mut ExecutionSegmentState, - instruction: &Instruction, - chip_complex: &mut VmChipComplex, - ) -> Result<(), ExecutionError> - where - F: PrimeField32; -} - -/// Implementation of the ExecutionControl trait using the old segmentation strategy -pub struct TracegenExecutionControl { - pub final_memory: Option, - pub since_last_segment_check: usize, - air_names: Vec, -} - -impl TracegenExecutionControl { - pub fn new(air_names: Vec) -> Self { - Self { - final_memory: None, - since_last_segment_check: 0, - air_names, - } - } -} - -impl ExecutionControl for TracegenExecutionControl -where - F: PrimeField32, - VC: VmConfig, -{ - type Ctx = TracegenCtx; - - fn new(chip_complex: &VmChipComplex) -> Self { - Self { - final_memory: None, - since_last_segment_check: 0, - air_names: chip_complex.air_names(), - } - } - - fn should_stop( - &mut self, - chip_complex: &VmChipComplex, - ) -> bool { - // Avoid checking segment too often. - if self.since_last_segment_check != SEGMENT_CHECK_INTERVAL { - self.since_last_segment_check += 1; - return false; - } - self.since_last_segment_check = 0; - chip_complex.config().segmentation_strategy.should_segment( - &self.air_names, - &chip_complex.dynamic_trace_heights().collect::>(), - &chip_complex.current_trace_cells(), - ) - } - - fn on_segment_start( - &mut self, - pc: u32, - chip_complex: &mut VmChipComplex, - ) { - let timestamp = chip_complex.memory_controller().timestamp(); - chip_complex - .connector_chip_mut() - .begin(ExecutionState::new(pc, timestamp)); - } - - fn on_segment_end( - &mut self, - pc: u32, + state: &mut VmSegmentState, chip_complex: &mut VmChipComplex, ) { - let timestamp = chip_complex.memory_controller().timestamp(); - // End the current segment with connector chip - chip_complex - .connector_chip_mut() - .end(ExecutionState::new(pc, timestamp), None); - self.final_memory = Some(chip_complex.base.memory_controller.memory_image().clone()); + self.on_suspend_or_terminate(state, chip_complex, None); } fn on_terminate( &mut self, - pc: u32, + state: &mut VmSegmentState, chip_complex: &mut VmChipComplex, exit_code: u32, ) { - let timestamp = chip_complex.memory_controller().timestamp(); - chip_complex - .connector_chip_mut() - .end(ExecutionState::new(pc, timestamp), Some(exit_code)); - self.final_memory = Some(chip_complex.base.memory_controller.memory_image().clone()); - } - - /// Execute a single instruction - fn execute_instruction( - &mut self, - state: &mut ExecutionSegmentState, - instruction: &Instruction, - chip_complex: &mut VmChipComplex, - ) -> Result<(), ExecutionError> - where - F: PrimeField32, - { - let timestamp = chip_complex.memory_controller().timestamp(); - - let &Instruction { opcode, .. } = instruction; - - if let Some(executor) = chip_complex.inventory.get_mut_executor(&opcode) { - let memory_controller = &mut chip_complex.base.memory_controller; - let new_state = executor.execute( - memory_controller, - instruction, - ExecutionState::new(state.pc, timestamp), - )?; - state.pc = new_state.pc; - } else { - return Err(ExecutionError::DisabledOperation { - pc: state.pc, - opcode, - }); - }; - - Ok(()) - } -} - -/// Implementation of the ExecutionControl trait using the old segmentation strategy -pub struct E1ExecutionControl { - pub final_memory: Option, -} - -impl ExecutionControl for E1ExecutionControl -where - F: PrimeField32, - VC: VmConfig, - VC::Executor: InsExecutorE1, -{ - type Ctx = (); - - fn new(_chip_complex: &VmChipComplex) -> Self { - Self { final_memory: None } - } - - fn should_stop( - &mut self, - _chip_complex: &VmChipComplex, - ) -> bool { - false - } - - fn on_segment_start( - &mut self, - _pc: u32, - _chip_complex: &mut VmChipComplex, - ) { - } - - fn on_segment_end( - &mut self, - _pc: u32, - chip_complex: &mut VmChipComplex, - ) { - self.final_memory = Some(chip_complex.base.memory_controller.memory_image().clone()); - } - - fn on_terminate( - &mut self, - _pc: u32, - chip_complex: &mut VmChipComplex, - _exit_code: u32, - ) { - self.final_memory = Some(chip_complex.base.memory_controller.memory_image().clone()); + self.on_suspend_or_terminate(state, chip_complex, Some(exit_code)); } /// Execute a single instruction + // TODO(ayush): change instruction to Instruction / PInstruction fn execute_instruction( &mut self, - state: &mut ExecutionSegmentState, + state: &mut VmSegmentState, instruction: &Instruction, chip_complex: &mut VmChipComplex, ) -> Result<(), ExecutionError> where - F: PrimeField32, - { - let &Instruction { opcode, .. } = instruction; - - if let Some(executor) = chip_complex.inventory.get_mut_executor(&opcode) { - let vm_state = VmStateMut { - pc: &mut state.pc, - memory: state.memory.as_mut().unwrap(), - ctx: &mut (), - }; - executor.execute_e1(vm_state, instruction)?; - } else { - return Err(ExecutionError::DisabledOperation { - pc: state.pc, - opcode, - }); - }; - - Ok(()) - } + F: PrimeField32; } diff --git a/crates/vm/src/arch/execution_mode/e1.rs b/crates/vm/src/arch/execution_mode/e1.rs new file mode 100644 index 0000000000..0721e2158d --- /dev/null +++ b/crates/vm/src/arch/execution_mode/e1.rs @@ -0,0 +1,79 @@ +use openvm_instructions::instruction::Instruction; +use openvm_stark_backend::p3_field::PrimeField32; + +use crate::arch::{ + execution_control::ExecutionControl, execution_mode::E1E2ExecutionCtx, ExecutionError, + InsExecutorE1, VmChipComplex, VmConfig, VmSegmentState, VmStateMut, +}; + +pub type E1Ctx = (); + +impl E1E2ExecutionCtx for E1Ctx { + fn on_memory_operation(&mut self, _address_space: u32, _ptr: u32, _size: usize) {} +} + +/// Implementation of the ExecutionControl trait using the old segmentation strategy +#[derive(Default)] +pub struct E1ExecutionControl; + +impl ExecutionControl for E1ExecutionControl +where + F: PrimeField32, + VC: VmConfig, + VC::Executor: InsExecutorE1, +{ + type Ctx = E1Ctx; + + fn should_suspend( + &mut self, + _state: &mut VmSegmentState, + _chip_complex: &VmChipComplex, + ) -> bool { + false + } + + fn on_start( + &mut self, + _state: &mut VmSegmentState, + _chip_complex: &mut VmChipComplex, + ) { + } + + fn on_suspend_or_terminate( + &mut self, + _state: &mut VmSegmentState, + _chip_complex: &mut VmChipComplex, + _exit_code: Option, + ) { + } + + /// Execute a single instruction + fn execute_instruction( + &mut self, + state: &mut VmSegmentState, + instruction: &Instruction, + chip_complex: &mut VmChipComplex, + ) -> Result<(), ExecutionError> + where + F: PrimeField32, + { + let &Instruction { opcode, .. } = instruction; + + if let Some(executor) = chip_complex.inventory.get_mut_executor(&opcode) { + let mut vm_state = VmStateMut { + pc: &mut state.pc, + memory: state.memory.as_mut().unwrap(), + ctx: &mut state.ctx, + }; + executor.execute_e1(&mut vm_state, instruction)?; + } else { + return Err(ExecutionError::DisabledOperation { + pc: state.pc, + opcode, + }); + }; + state.clk += 1; + + Ok(()) + } +} diff --git a/crates/vm/src/arch/execution_mode/metered/bounded.rs b/crates/vm/src/arch/execution_mode/metered/bounded.rs new file mode 100644 index 0000000000..52b8609b03 --- /dev/null +++ b/crates/vm/src/arch/execution_mode/metered/bounded.rs @@ -0,0 +1,183 @@ +use openvm_instructions::riscv::RV32_IMM_AS; + +use crate::{ + arch::{execution_mode::E1E2ExecutionCtx, PUBLIC_VALUES_AIR_ID}, + system::memory::{dimensions::MemoryDimensions, CHUNK, CHUNK_BITS}, +}; + +// TODO(ayush): can segmentation also be triggered by timestamp overflow? should that be tracked? +#[derive(Debug)] +pub struct MeteredCtxBounded { + pub trace_heights: Vec, + + continuations_enabled: bool, + num_access_adapters: usize, + // TODO(ayush): take alignment into account for access adapters + #[allow(dead_code)] + as_byte_alignment_bits: Vec, + pub memory_dimensions: MemoryDimensions, + + // Indices of leaf nodes in the memory merkle tree + pub leaf_indices: Vec, +} + +impl MeteredCtxBounded { + pub fn new( + num_traces: usize, + continuations_enabled: bool, + num_access_adapters: usize, + as_byte_alignment_bits: Vec, + memory_dimensions: MemoryDimensions, + ) -> Self { + Self { + trace_heights: vec![0; num_traces], + continuations_enabled, + num_access_adapters, + as_byte_alignment_bits, + memory_dimensions, + leaf_indices: Vec::new(), + } + } +} + +impl MeteredCtxBounded { + fn update_boundary_merkle_heights(&mut self, address_space: u32, ptr: u32, size: usize) { + let boundary_idx = if self.continuations_enabled { + PUBLIC_VALUES_AIR_ID + } else { + PUBLIC_VALUES_AIR_ID + 1 + }; + let poseidon2_idx = self.trace_heights.len() - 2; + + let num_blocks = (size + CHUNK - 1) >> CHUNK_BITS; + for i in 0..num_blocks { + let addr = ptr.wrapping_add((i * CHUNK) as u32); + let block_id = addr >> CHUNK_BITS; + let leaf_id = self + .memory_dimensions + .label_to_index((address_space, block_id)); + + if let Err(insert_idx) = self.leaf_indices.binary_search(&leaf_id) { + self.leaf_indices.insert(insert_idx, leaf_id); + + self.trace_heights[boundary_idx] += 1; + self.trace_heights[poseidon2_idx] += 2; + + if self.continuations_enabled { + let pred_id = insert_idx.checked_sub(1).map(|idx| self.leaf_indices[idx]); + let succ_id = (insert_idx < self.leaf_indices.len() - 1) + .then(|| self.leaf_indices[insert_idx + 1]); + let height_change = calculate_merkle_node_updates( + pred_id, + succ_id, + leaf_id, + self.memory_dimensions.overall_height(), + ); + self.trace_heights[boundary_idx + 1] += height_change * 2; + self.trace_heights[poseidon2_idx] += height_change * 2; + } + } + } + } + + fn update_adapter_heights_batch(&mut self, size: usize, num: usize) { + let adapter_offset = if self.continuations_enabled { + PUBLIC_VALUES_AIR_ID + 2 + } else { + PUBLIC_VALUES_AIR_ID + 1 + }; + + apply_adapter_updates_batch(size, num, &mut self.trace_heights[adapter_offset..]); + } + + fn update_adapter_heights(&mut self, size: usize) { + self.update_adapter_heights_batch(size, 1); + } + + pub fn finalize_access_adapter_heights(&mut self) { + self.update_adapter_heights_batch(CHUNK, self.leaf_indices.len()); + } + + pub fn trace_heights_if_finalized(&mut self) -> Vec { + let num_leaves = self.leaf_indices.len(); + let mut access_adapter_updates = vec![0; self.num_access_adapters]; + apply_adapter_updates_batch(CHUNK, num_leaves, &mut access_adapter_updates); + + let adapter_offset = if self.continuations_enabled { + PUBLIC_VALUES_AIR_ID + 2 + } else { + PUBLIC_VALUES_AIR_ID + 1 + }; + self.trace_heights + .iter() + .enumerate() + .map(|(i, &height)| { + if i >= adapter_offset && i < adapter_offset + access_adapter_updates.len() { + height + access_adapter_updates[i - adapter_offset] + } else { + height + } + }) + .collect() + } +} + +impl E1E2ExecutionCtx for MeteredCtxBounded { + fn on_memory_operation(&mut self, address_space: u32, ptr: u32, size: usize) { + debug_assert!( + address_space != RV32_IMM_AS, + "address space must not be immediate" + ); + debug_assert!(size.is_power_of_two(), "size must be a power of 2"); + + // Handle access adapter updates + self.update_adapter_heights(size); + + // Handle merkle tree updates + // TODO(ayush): use a looser upper bound + // see if this can be approximated by total number of reads/writes for AS != register + self.update_boundary_merkle_heights(address_space, ptr, size); + } +} + +fn apply_adapter_updates_batch(size: usize, num: usize, trace_heights: &mut [usize]) { + let size_bits = size.ilog2() as usize; + for adapter_bits in (3..=size_bits).rev() { + trace_heights[adapter_bits - 1] += num << (size_bits - adapter_bits + 1); + } +} + +fn calculate_merkle_node_updates( + pred_id: Option, + succ_id: Option, + leaf_id: u64, + height: usize, +) -> usize { + // First node requires height many updates + if pred_id.is_none() && succ_id.is_none() { + return height; + } + + // Calculate the difference in divergence + let mut diff = 0; + + // Add new divergences between pred and leaf_index + if let Some(p) = pred_id { + let new_divergence = (p ^ leaf_id).ilog2() as usize; + diff += new_divergence; + } + + // Add new divergences between leaf_index and succ + if let Some(s) = succ_id { + let new_divergence = (leaf_id ^ s).ilog2() as usize; + diff += new_divergence; + } + + // Remove old divergence between pred and succ if both existed + if let (Some(p), Some(s)) = (pred_id, succ_id) { + let old_divergence = (p ^ s).ilog2() as usize; + diff -= old_divergence; + } + + diff +} diff --git a/crates/vm/src/arch/execution_mode/metered/exact.rs b/crates/vm/src/arch/execution_mode/metered/exact.rs new file mode 100644 index 0000000000..53dc49bea0 --- /dev/null +++ b/crates/vm/src/arch/execution_mode/metered/exact.rs @@ -0,0 +1,393 @@ +use std::collections::BTreeMap; + +use openvm_instructions::riscv::RV32_IMM_AS; + +use crate::{ + arch::{execution_mode::E1E2ExecutionCtx, PUBLIC_VALUES_AIR_ID}, + system::memory::{dimensions::MemoryDimensions, CHUNK, CHUNK_BITS}, +}; + +// TODO(ayush): can segmentation also be triggered by timestamp overflow? should that be tracked? +#[derive(Debug)] +pub struct MeteredCtxExact { + pub trace_heights: Vec, + + continuations_enabled: bool, + num_access_adapters: usize, + as_byte_alignment_bits: Vec, + pub memory_dimensions: MemoryDimensions, + + // Map from (addr_space, addr) -> (size, offset) + pub last_memory_access: BTreeMap<(u8, u32), (u8, u8)>, + // Indices of leaf nodes in the memory merkle tree + pub leaf_indices: Vec, +} + +impl MeteredCtxExact { + pub fn new( + num_traces: usize, + continuations_enabled: bool, + num_access_adapters: usize, + as_byte_alignment_bits: Vec, + memory_dimensions: MemoryDimensions, + ) -> Self { + Self { + trace_heights: vec![0; num_traces], + continuations_enabled, + num_access_adapters, + as_byte_alignment_bits, + memory_dimensions, + last_memory_access: BTreeMap::new(), + leaf_indices: Vec::new(), + } + } +} + +impl MeteredCtxExact { + fn update_boundary_merkle_heights(&mut self, address_space: u32, ptr: u32, size: usize) { + let boundary_idx = if self.continuations_enabled { + PUBLIC_VALUES_AIR_ID + } else { + PUBLIC_VALUES_AIR_ID + 1 + }; + let poseidon2_idx = self.trace_heights.len() - 2; + + let num_blocks = (size + CHUNK - 1) >> CHUNK_BITS; + for i in 0..num_blocks { + let addr = ptr.wrapping_add((i * CHUNK) as u32); + let block_id = addr >> CHUNK_BITS; + let leaf_id = self + .memory_dimensions + .label_to_index((address_space, block_id)); + + if let Err(insert_idx) = self.leaf_indices.binary_search(&leaf_id) { + self.leaf_indices.insert(insert_idx, leaf_id); + + self.trace_heights[boundary_idx] += 1; + // NOTE: this is an upper bound since poseidon chip removes duplicates + self.trace_heights[poseidon2_idx] += 2; + + if self.continuations_enabled { + let pred_id = insert_idx.checked_sub(1).map(|idx| self.leaf_indices[idx]); + let succ_id = (insert_idx < self.leaf_indices.len() - 1) + .then(|| self.leaf_indices[insert_idx + 1]); + let height_change = calculate_merkle_node_updates( + pred_id, + succ_id, + leaf_id, + self.memory_dimensions.overall_height(), + ); + self.trace_heights[boundary_idx + 1] += height_change * 2; + self.trace_heights[poseidon2_idx] += height_change * 2; + } + } + } + } + + #[allow(clippy::type_complexity)] + fn calculate_splits_and_merges( + &self, + address_space: u32, + ptr: u32, + size: usize, + ) -> (Vec<(u32, usize)>, Vec<(u32, usize)>) { + // Skip adapters if this is a repeated access to the same location with same size + let last_access = self.last_memory_access.get(&(address_space as u8, ptr)); + if matches!(last_access, Some(&(last_access_size, 0)) if size == last_access_size as usize) + { + return (vec![], vec![]); + } + + // Go to the start of block + let mut ptr_start = ptr; + if let Some(&(_, last_access_offset)) = last_access { + ptr_start = ptr.wrapping_sub(last_access_offset as u32); + } + + let align_bits = self.as_byte_alignment_bits[address_space as usize]; + let align = 1 << align_bits; + + // Split intersecting blocks to align bytes + let mut curr_block = ptr_start >> align_bits; + let end_block = curr_block + (size as u32 >> align_bits); + let mut splits = vec![]; + while curr_block < end_block { + let curr_block_size = if let Some(&(last_access_size, _)) = self + .last_memory_access + .get(&(address_space as u8, curr_block.wrapping_mul(align as u32))) + { + last_access_size as usize + } else { + // Initial memory access only happens at CHUNK boundary + let chunk_ratio = 1 << (CHUNK_BITS - align_bits); + let chunk_offset = curr_block & (chunk_ratio - 1); + curr_block -= chunk_offset; + CHUNK + }; + + if curr_block_size > align { + let curr_ptr = curr_block.wrapping_mul(align as u32); + splits.push((curr_ptr, curr_block_size)); + } + + curr_block += (curr_block_size >> align_bits) as u32; + } + // Merge added blocks from align to size bytes + let merges = vec![(ptr, size)]; + + (splits, merges) + } + + #[allow(clippy::type_complexity)] + fn apply_adapter_updates( + &mut self, + addr_space: u32, + ptr: u32, + size: usize, + trace_heights: &mut Option<&mut [usize]>, + memory_updates: &mut Option)>>, + ) { + let adapter_offset = if self.continuations_enabled { + PUBLIC_VALUES_AIR_ID + 2 + } else { + PUBLIC_VALUES_AIR_ID + 1 + }; + + let (splits, merges) = self.calculate_splits_and_merges(addr_space, ptr, size); + for (curr_ptr, curr_size) in splits { + if let Some(trace_heights) = trace_heights { + apply_single_adapter_heights_update(trace_heights, curr_size); + } else { + apply_single_adapter_heights_update( + &mut self.trace_heights[adapter_offset..], + curr_size, + ); + } + let updates = add_memory_access_split_with_return( + &mut self.last_memory_access, + (addr_space, curr_ptr), + curr_size, + self.as_byte_alignment_bits[addr_space as usize], + ); + if let Some(memory_updates) = memory_updates { + memory_updates.extend(&updates); + } + } + for (curr_ptr, curr_size) in merges { + if let Some(trace_heights) = trace_heights { + apply_single_adapter_heights_update(trace_heights, curr_size); + } else { + apply_single_adapter_heights_update( + &mut self.trace_heights[adapter_offset..], + curr_size, + ); + } + let updates = add_memory_access_merge_with_return( + &mut self.last_memory_access, + (addr_space, curr_ptr), + curr_size, + self.as_byte_alignment_bits[addr_space as usize], + ); + if let Some(memory_updates) = memory_updates { + memory_updates.extend(updates); + } + } + } + + fn update_adapter_heights(&mut self, addr_space: u32, ptr: u32, size: usize) { + self.apply_adapter_updates(addr_space, ptr, size, &mut None, &mut None); + } + + pub fn finalize_access_adapter_heights(&mut self) { + let indices_to_process: Vec<_> = self + .leaf_indices + .iter() + .map(|&idx| { + let (addr_space, block_id) = self.memory_dimensions.index_to_label(idx); + (addr_space, block_id) + }) + .collect(); + for (addr_space, block_id) in indices_to_process { + self.update_adapter_heights(addr_space, block_id * CHUNK as u32, CHUNK); + } + } + + pub fn trace_heights_if_finalized(&mut self) -> Vec { + let indices_to_process: Vec<_> = self + .leaf_indices + .iter() + .map(|&idx| { + let (addr_space, block_id) = self.memory_dimensions.index_to_label(idx); + (addr_space, block_id) + }) + .collect(); + + let mut access_adapter_updates = vec![0; self.num_access_adapters]; + let mut memory_updates = Some(vec![]); + for (addr_space, block_id) in indices_to_process { + let ptr = block_id * CHUNK as u32; + self.apply_adapter_updates( + addr_space, + ptr, + CHUNK, + &mut Some(&mut access_adapter_updates), + &mut memory_updates, + ); + } + + // Restore original memory state + for (key, old_value) in memory_updates.unwrap().into_iter().rev() { + match old_value { + Some(value) => { + self.last_memory_access.insert(key, value); + } + None => { + self.last_memory_access.remove(&key); + } + } + } + + let adapter_offset = if self.continuations_enabled { + PUBLIC_VALUES_AIR_ID + 2 + } else { + PUBLIC_VALUES_AIR_ID + 1 + }; + self.trace_heights + .iter() + .enumerate() + .map(|(i, &height)| { + if i >= adapter_offset && i < adapter_offset + access_adapter_updates.len() { + height + access_adapter_updates[i - adapter_offset] + } else { + height + } + }) + .collect() + } +} + +impl E1E2ExecutionCtx for MeteredCtxExact { + fn on_memory_operation(&mut self, address_space: u32, ptr: u32, size: usize) { + debug_assert!( + address_space != RV32_IMM_AS, + "address space must not be immediate" + ); + debug_assert!(size.is_power_of_two(), "size must be a power of 2"); + + // Handle access adapter updates + self.update_adapter_heights(address_space, ptr, size); + + // Handle merkle tree updates + // TODO(ayush): see if this can be approximated by total number of reads/writes for AS != register + self.update_boundary_merkle_heights(address_space, ptr, size); + } +} + +fn apply_single_adapter_heights_update(trace_heights: &mut [usize], size: usize) { + let size_bits = size.ilog2() as usize; + for adapter_bits in (3..=size_bits).rev() { + trace_heights[adapter_bits - 1] += 1 << (size_bits - adapter_bits); + } +} + +#[allow(clippy::type_complexity)] +fn add_memory_access( + memory_access_map: &mut BTreeMap<(u8, u32), (u8, u8)>, + (address_space, ptr): (u32, u32), + size: usize, + align_bits: usize, + is_split: bool, +) -> Vec<((u8, u32), Option<(u8, u8)>)> { + let align = 1 << align_bits; + debug_assert_eq!( + size & (align - 1), + 0, + "Size must be a multiple of alignment" + ); + + let num_chunks = size >> align_bits; + let mut old_values = Vec::with_capacity(num_chunks); + + for i in 0..num_chunks { + let curr_ptr = ptr.wrapping_add(i as u32 * align as u32); + let key = (address_space as u8, curr_ptr); + + let value = if is_split { + (align as u8, 0) + } else { + (size as u8, (i * align) as u8) + }; + + let old_value = memory_access_map.insert(key, value); + old_values.push((key, old_value)); + } + + old_values +} + +#[allow(clippy::type_complexity)] +fn add_memory_access_split_with_return( + memory_access_map: &mut BTreeMap<(u8, u32), (u8, u8)>, + (address_space, ptr): (u32, u32), + size: usize, + align_bits: usize, +) -> Vec<((u8, u32), Option<(u8, u8)>)> { + add_memory_access( + memory_access_map, + (address_space, ptr), + size, + align_bits, + true, + ) +} + +#[allow(clippy::type_complexity)] +fn add_memory_access_merge_with_return( + memory_access_map: &mut BTreeMap<(u8, u32), (u8, u8)>, + (address_space, ptr): (u32, u32), + size: usize, + align_bits: usize, +) -> Vec<((u8, u32), Option<(u8, u8)>)> { + add_memory_access( + memory_access_map, + (address_space, ptr), + size, + align_bits, + false, + ) +} + +fn calculate_merkle_node_updates( + pred_id: Option, + succ_id: Option, + leaf_id: u64, + height: usize, +) -> usize { + // First node requires height many updates + if pred_id.is_none() && succ_id.is_none() { + return height; + } + + // Calculate the difference in divergence + let mut diff = 0; + + // Add new divergences between pred and leaf_index + if let Some(p) = pred_id { + let new_divergence = (p ^ leaf_id).ilog2() as usize; + diff += new_divergence; + } + + // Add new divergences between leaf_index and succ + if let Some(s) = succ_id { + let new_divergence = (leaf_id ^ s).ilog2() as usize; + diff += new_divergence; + } + + // Remove old divergence between pred and succ if both existed + if let (Some(p), Some(s)) = (pred_id, succ_id) { + let old_divergence = (p ^ s).ilog2() as usize; + diff -= old_divergence; + } + + diff +} diff --git a/crates/vm/src/arch/execution_mode/metered/mod.rs b/crates/vm/src/arch/execution_mode/metered/mod.rs new file mode 100644 index 0000000000..67698e8b5a --- /dev/null +++ b/crates/vm/src/arch/execution_mode/metered/mod.rs @@ -0,0 +1,204 @@ +pub mod bounded; +pub mod exact; + +// pub use exact::MeteredCtxExact as MeteredCtx; +pub use bounded::MeteredCtxBounded as MeteredCtx; + +use openvm_instructions::instruction::Instruction; +use openvm_stark_backend::{p3_field::PrimeField32, ChipUsageGetter}; + +use crate::arch::{ + execution_control::ExecutionControl, ChipId, ExecutionError, InsExecutorE1, VmChipComplex, + VmConfig, VmSegmentState, VmStateMut, CONNECTOR_AIR_ID, DEFAULT_MAX_CELLS_PER_CHIP_IN_SEGMENT, + DEFAULT_MAX_SEGMENT_LEN, PROGRAM_AIR_ID, PUBLIC_VALUES_AIR_ID, +}; + +/// Check segment every 100 instructions. +const SEGMENT_CHECK_INTERVAL: usize = 100; + +// TODO(ayush): fix these values +const MAX_TRACE_HEIGHT: usize = DEFAULT_MAX_SEGMENT_LEN; +const MAX_TRACE_CELLS: usize = DEFAULT_MAX_CELLS_PER_CHIP_IN_SEGMENT; +const MAX_INTERACTIONS: usize = DEFAULT_MAX_SEGMENT_LEN * 100; + +pub struct MeteredExecutionControl<'a> { + pub widths: &'a [usize], + pub interactions: &'a [usize], + pub since_last_segment_check: usize, +} + +impl<'a> MeteredExecutionControl<'a> { + pub fn new(widths: &'a [usize], interactions: &'a [usize]) -> Self { + Self { + widths, + interactions, + since_last_segment_check: 0, + } + } + + /// Calculate the total cells used based on trace heights and widths + // TODO(ayush): account for preprocessed and permutation columns + fn calculate_total_cells(&self, trace_heights: &[usize]) -> usize { + trace_heights + .iter() + .zip(self.widths) + .map(|(&height, &width)| height.next_power_of_two() * width) + .sum() + } + + /// Calculate the total interactions based on trace heights and interaction counts + fn calculate_total_interactions(&self, trace_heights: &[usize]) -> usize { + trace_heights + .iter() + .zip(self.interactions) + // We add 1 for the zero messages from the padding rows + .map(|(&height, &interactions)| (height + 1) * interactions) + .sum() + } +} + +impl ExecutionControl for MeteredExecutionControl<'_> +where + F: PrimeField32, + VC: VmConfig, + VC::Executor: InsExecutorE1, +{ + type Ctx = MeteredCtx; + + fn should_suspend( + &mut self, + state: &mut VmSegmentState, + _chip_complex: &VmChipComplex, + ) -> bool { + // Avoid checking segment too often. + if self.since_last_segment_check != SEGMENT_CHECK_INTERVAL { + self.since_last_segment_check += 1; + return false; + } + self.since_last_segment_check = 0; + + let trace_heights = state.ctx.trace_heights_if_finalized(); + + let max_height = trace_heights.iter().map(|&h| h.next_power_of_two()).max(); + if let Some(height) = max_height { + if height > MAX_TRACE_HEIGHT { + tracing::info!( + "Suspending execution: trace height ({}) exceeds maximum ({})", + height, + MAX_TRACE_HEIGHT + ); + return true; + } + } + + let total_cells = self.calculate_total_cells(&trace_heights); + if total_cells > MAX_TRACE_CELLS { + tracing::info!( + "Suspending execution: total cells ({}) exceeds maximum ({})", + total_cells, + MAX_TRACE_CELLS + ); + return true; + } + + let total_interactions = self.calculate_total_interactions(&trace_heights); + if total_interactions > MAX_INTERACTIONS { + tracing::info!( + "Suspending execution: total interactions ({}) exceeds maximum ({})", + total_interactions, + MAX_INTERACTIONS + ); + return true; + } + + false + } + + fn on_start( + &mut self, + state: &mut VmSegmentState, + chip_complex: &mut VmChipComplex, + ) { + // Program | Connector | Public Values | Memory ... | Executors (except Public Values) | Range Checker + state.ctx.trace_heights[PROGRAM_AIR_ID] = chip_complex.program_chip().true_program_length; + state.ctx.trace_heights[CONNECTOR_AIR_ID] = 2; + + let mut offset = if chip_complex.config().has_public_values_chip() { + PUBLIC_VALUES_AIR_ID + 1 + } else { + PUBLIC_VALUES_AIR_ID + }; + offset += chip_complex.memory_controller().num_airs(); + + // Periphery chips with constant heights + for (i, chip_id) in chip_complex + .inventory + .insertion_order + .iter() + .rev() + .enumerate() + { + if let &ChipId::Periphery(id) = chip_id { + if let Some(constant_height) = + chip_complex.inventory.periphery[id].constant_trace_height() + { + state.ctx.trace_heights[offset + i] = constant_height; + } + } + } + + // Range checker chip + if let (Some(range_checker_height), Some(last_height)) = ( + chip_complex.range_checker_chip().constant_trace_height(), + state.ctx.trace_heights.last_mut(), + ) { + *last_height = range_checker_height; + } + } + + fn on_suspend_or_terminate( + &mut self, + state: &mut VmSegmentState, + _chip_complex: &mut VmChipComplex, + _exit_code: Option, + ) { + state.ctx.finalize_access_adapter_heights(); + } + + /// Execute a single instruction + fn execute_instruction( + &mut self, + state: &mut VmSegmentState, + instruction: &Instruction, + chip_complex: &mut VmChipComplex, + ) -> Result<(), ExecutionError> + where + F: PrimeField32, + { + let &Instruction { opcode, .. } = instruction; + + let mut offset = if chip_complex.config().has_public_values_chip() { + PUBLIC_VALUES_AIR_ID + 1 + } else { + PUBLIC_VALUES_AIR_ID + }; + offset += chip_complex.memory_controller().num_airs(); + + if let Some((executor, i)) = chip_complex.inventory.get_mut_executor_with_index(&opcode) { + let mut vm_state = VmStateMut { + pc: &mut state.pc, + memory: state.memory.as_mut().unwrap(), + ctx: &mut state.ctx, + }; + executor.execute_metered(&mut vm_state, instruction, offset + i)?; + } else { + return Err(ExecutionError::DisabledOperation { + pc: state.pc, + opcode, + }); + }; + state.clk += 1; + + Ok(()) + } +} diff --git a/crates/vm/src/arch/execution_mode/mod.rs b/crates/vm/src/arch/execution_mode/mod.rs new file mode 100644 index 0000000000..a77832cb05 --- /dev/null +++ b/crates/vm/src/arch/execution_mode/mod.rs @@ -0,0 +1,8 @@ +pub mod e1; +pub mod metered; +pub mod tracegen; + +// TODO(ayush): better name +pub trait E1E2ExecutionCtx { + fn on_memory_operation(&mut self, address_space: u32, ptr: u32, size: usize); +} diff --git a/crates/vm/src/arch/execution_mode/tracegen.rs b/crates/vm/src/arch/execution_mode/tracegen.rs new file mode 100644 index 0000000000..146cb58652 --- /dev/null +++ b/crates/vm/src/arch/execution_mode/tracegen.rs @@ -0,0 +1,117 @@ +use openvm_instructions::instruction::Instruction; +use openvm_stark_backend::p3_field::PrimeField32; + +use crate::{ + arch::{ + execution_control::ExecutionControl, ExecutionError, ExecutionState, InstructionExecutor, + VmChipComplex, VmConfig, VmSegmentState, + }, + system::memory::MemoryImage, +}; + +/// Check segment every 100 instructions. +const SEGMENT_CHECK_INTERVAL: usize = 100; + +pub type TracegenCtx = (); + +/// Implementation of the ExecutionControl trait using the old segmentation strategy +pub struct TracegenExecutionControl { + pub since_last_segment_check: usize, + air_names: Vec, + pub final_memory: Option, +} + +impl TracegenExecutionControl { + pub fn new(air_names: Vec) -> Self { + Self { + since_last_segment_check: 0, + air_names, + final_memory: None, + } + } +} + +impl ExecutionControl for TracegenExecutionControl +where + F: PrimeField32, + VC: VmConfig, +{ + type Ctx = TracegenCtx; + + fn should_suspend( + &mut self, + _state: &mut VmSegmentState, + chip_complex: &VmChipComplex, + ) -> bool { + // Avoid checking segment too often. + if self.since_last_segment_check != SEGMENT_CHECK_INTERVAL { + self.since_last_segment_check += 1; + return false; + } + self.since_last_segment_check = 0; + chip_complex.config().segmentation_strategy.should_segment( + &self.air_names, + &chip_complex.dynamic_trace_heights().collect::>(), + &chip_complex.current_trace_cells(), + ) + } + + fn on_start( + &mut self, + state: &mut VmSegmentState, + chip_complex: &mut VmChipComplex, + ) { + let timestamp = chip_complex.memory_controller().timestamp(); + chip_complex + .connector_chip_mut() + .begin(ExecutionState::new(state.pc, timestamp)); + } + + fn on_suspend_or_terminate( + &mut self, + state: &mut VmSegmentState, + chip_complex: &mut VmChipComplex, + exit_code: Option, + ) { + // TODO(ayush): this should ideally not be here + self.final_memory = Some(chip_complex.base.memory_controller.memory_image().clone()); + + let timestamp = chip_complex.memory_controller().timestamp(); + chip_complex + .connector_chip_mut() + .end(ExecutionState::new(state.pc, timestamp), exit_code); + } + + /// Execute a single instruction + fn execute_instruction( + &mut self, + state: &mut VmSegmentState, + instruction: &Instruction, + chip_complex: &mut VmChipComplex, + ) -> Result<(), ExecutionError> + where + F: PrimeField32, + { + let timestamp = chip_complex.memory_controller().timestamp(); + + let &Instruction { opcode, .. } = instruction; + + if let Some(executor) = chip_complex.inventory.get_mut_executor(&opcode) { + let memory_controller = &mut chip_complex.base.memory_controller; + let new_state = executor.execute( + memory_controller, + instruction, + ExecutionState::new(state.pc, timestamp), + )?; + state.pc = new_state.pc; + } else { + return Err(ExecutionError::DisabledOperation { + pc: state.pc, + opcode, + }); + }; + state.clk += 1; + + Ok(()) + } +} diff --git a/crates/vm/src/arch/extensions.rs b/crates/vm/src/arch/extensions.rs index b20e4f6630..f3a09d3151 100644 --- a/crates/vm/src/arch/extensions.rs +++ b/crates/vm/src/arch/extensions.rs @@ -211,7 +211,7 @@ pub struct VmInventory { pub periphery: Vec

, /// Order of insertion. The reverse of this will be the order the chips are destroyed /// to generate trace. - insertion_order: Vec, + pub insertion_order: Vec, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -337,6 +337,25 @@ impl VmInventory { self.executors.get_mut(*id) } + pub fn get_mut_executor_with_index(&mut self, opcode: &VmOpcode) -> Option<(&mut E, usize)> { + let id = *self.instruction_lookup.get(opcode)?; + + self.executors.get_mut(id).map(|executor| { + // TODO(ayush): cache this somewhere + let insertion_id = self + .insertion_order + .iter() + .rev() + .position(|chip_id| match chip_id { + ChipId::Executor(exec_id) => *exec_id == id, + _ => false, + }) + .unwrap(); + + (executor, insertion_id) + }) + } + pub fn executors(&self) -> &[E] { &self.executors } @@ -788,11 +807,11 @@ impl VmChipComplex { .as_any_kind_mut() .downcast_mut() .expect("Poseidon2 chip required for persistent memory"); - self.base.memory_controller.finalize(Some(hasher)) + self.base.memory_controller.finalize(Some(hasher)); } else { self.base .memory_controller - .finalize(None::<&mut Poseidon2PeripheryChip>) + .finalize(None::<&mut Poseidon2PeripheryChip>); }; } @@ -821,7 +840,7 @@ impl VmChipComplex { } // we always need to special case it because we need to fix the air id. - fn public_values_chip_idx(&self) -> Option { + pub(crate) fn public_values_chip_idx(&self) -> Option { self.config .has_public_values_chip() .then_some(Self::PV_EXECUTOR_IDX) diff --git a/crates/vm/src/arch/integration_api.rs b/crates/vm/src/arch/integration_api.rs index d53ed075fe..3f6808e3c8 100644 --- a/crates/vm/src/arch/integration_api.rs +++ b/crates/vm/src/arch/integration_api.rs @@ -15,7 +15,10 @@ use openvm_stark_backend::{ }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use super::{ExecutionState, InsExecutorE1, InstructionExecutor, Result, VmStateMut}; +use super::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, + ExecutionState, InsExecutorE1, InstructionExecutor, Result, VmStateMut, +}; use crate::system::memory::{ online::{GuestMemory, TracingMemory}, MemoryAuxColsFactory, MemoryController, SharedMemoryHelper, @@ -200,7 +203,7 @@ pub trait TraceStep { /// being used, and all other rows in the trace will be filled with zeroes. /// /// The provided `row_slice` will have length equal to the width of the AIR. - fn fill_trace_row(&self, mem_helper: &MemoryAuxColsFactory, row_slice: &mut [F]) { + fn fill_trace_row(&self, _mem_helper: &MemoryAuxColsFactory, _row_slice: &mut [F]) { unreachable!("fill_trace_row is not implemented") } @@ -208,7 +211,7 @@ pub trait TraceStep { /// By default the trace is padded with empty (all 0) rows to make the height a power of 2. /// /// The provided `row_slice` will have length equal to the width of the AIR. - fn fill_dummy_trace_row(&self, mem_helper: &MemoryAuxColsFactory, row_slice: &mut [F]) { + fn fill_dummy_trace_row(&self, _mem_helper: &MemoryAuxColsFactory, _row_slice: &mut [F]) { // By default, the row is filled with zeroes } /// Returns a list of public values to publish. @@ -387,22 +390,41 @@ where type ReadData; type WriteData; - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData; + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx; - fn write(&self, memory: &mut GuestMemory, instruction: &Instruction, data: &Self::WriteData); + fn write( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + data: &Self::WriteData, + ) where + Ctx: E1E2ExecutionCtx; } // TODO: Rename core/step to operator pub trait StepExecutorE1 { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx; + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, ) -> Result<()>; } -const DEFAULT_RECORDS_CAPACITY: usize = 1 << 20; - impl InsExecutorE1 for NewVmChipWrapper where F: PrimeField32, @@ -410,11 +432,23 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { self.step.execute_e1(state, instruction) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + self.step.execute_metered(state, instruction, chip_index) + } } #[derive(Clone, Copy, derive_new::new)] diff --git a/crates/vm/src/arch/mod.rs b/crates/vm/src/arch/mod.rs index 7ecb289cc9..fdb2b7e49a 100644 --- a/crates/vm/src/arch/mod.rs +++ b/crates/vm/src/arch/mod.rs @@ -4,6 +4,7 @@ mod config; mod execution; /// Module for controlling VM execution flow, including segmentation and instruction execution pub mod execution_control; +pub mod execution_mode; /// Traits and builders to compose collections of chips into a virtual machine. mod extensions; /// Traits and wrappers to facilitate VM chip integration diff --git a/crates/vm/src/arch/segment.rs b/crates/vm/src/arch/segment.rs index 3603db4253..4f325cef4e 100644 --- a/crates/vm/src/arch/segment.rs +++ b/crates/vm/src/arch/segment.rs @@ -1,3 +1,13 @@ +use super::{ + execution_control::ExecutionControl, ExecutionError, GenerationError, SystemConfig, + VmChipComplex, VmComplexTraceHeights, VmConfig, +}; +#[cfg(feature = "bench-metrics")] +use crate::metrics::VmMetrics; +use crate::{ + arch::{instructions::*, InstructionExecutor}, + system::memory::online::GuestMemory, +}; use backtrace::Backtrace; use openvm_instructions::{ exe::FnBounds, @@ -12,32 +22,36 @@ use openvm_stark_backend::{ utils::metrics_span, Chip, }; -use program::Program; -use super::{ - execution_control::{E1ExecutionControl, ExecutionControl, TracegenExecutionControl}, - ExecutionError, GenerationError, Streams, SystemConfig, VmChipComplex, VmComplexTraceHeights, - VmConfig, VmStateMut, -}; -#[cfg(feature = "bench-metrics")] -use crate::metrics::VmMetrics; -use crate::{ - arch::{instructions::*, InstructionExecutor}, - system::{ - connector::DEFAULT_SUSPEND_EXIT_CODE, - memory::{online::GuestMemory, paged_vec::PAGE_SIZE, AddressMap, MemoryImage}, - }, -}; +pub struct VmSegmentState { + pub clk: u64, + pub pc: u32, + pub memory: Option, + pub exit_code: Option, + pub ctx: Ctx, +} + +impl VmSegmentState { + pub fn new(clk: u64, pc: u32, memory: Option, ctx: Ctx) -> Self { + Self { + clk, + pc, + memory, + ctx, + exit_code: None, + } + } +} -pub struct VmSegmentExecutor +pub struct VmSegmentExecutor where F: PrimeField32, VC: VmConfig, - Ctrl: ExecutionControl, + Ctrl: ExecutionControl, { pub chip_complex: VmChipComplex, /// Execution control for determining segmentation and stopping conditions - pub control: Ctrl, + pub ctrl: Ctrl, pub trace_height_constraints: Vec, @@ -48,56 +62,24 @@ where pub metrics: VmMetrics, } -pub type E1VmSegmentExecutor = VmSegmentExecutor; - -// pub struct TracegenCtx; -pub type TracegenCtx = (); -pub type TracegenVmStateMut<'a> = VmStateMut<'a, GuestMemory, TracegenCtx>; - -pub type TracegenVmSegmentExecutor = - VmSegmentExecutor; - -#[derive(derive_new::new)] -pub struct ExecutionSegmentState { - pub memory: Option, - pub pc: u32, - pub exit_code: u32, - pub is_terminated: bool, -} - -impl VmSegmentExecutor +impl VmSegmentExecutor where F: PrimeField32, VC: VmConfig, - Ctrl: ExecutionControl, + Ctrl: ExecutionControl, { /// Creates a new execution segment from a program and initial state, using parent VM config pub fn new( - config: &VC, - program: Program, - init_streams: Streams, - initial_memory: Option, + chip_complex: VmChipComplex, trace_height_constraints: Vec, #[allow(unused_variables)] fn_bounds: FnBounds, + ctrl: Ctrl, ) -> Self { - let mut chip_complex = config.create_chip_complex().unwrap(); - chip_complex.set_streams(init_streams); - let program = if !config.system().profiling { - program.strip_debug_infos() - } else { - program - }; - chip_complex.set_program(program); - - if let Some(initial_memory) = initial_memory { - chip_complex.set_initial_memory(initial_memory); - } let air_names = chip_complex.air_names(); - let control = Ctrl::new(&chip_complex); Self { chip_complex, - control, + ctrl, air_names, trace_height_constraints, #[cfg(feature = "bench-metrics")] @@ -120,46 +102,40 @@ where } /// Stopping is triggered by should_stop() or if VM is terminated - pub fn execute_from_pc( + pub fn execute_from_state( &mut self, - pc: u32, - memory: Option, - ) -> Result { + state: &mut VmSegmentState, + ) -> Result<(), ExecutionError> { let mut prev_backtrace: Option = None; // Call the pre-execution hook - self.control.on_segment_start(pc, &mut self.chip_complex); + self.ctrl.on_start(state, &mut self.chip_complex); - let mut state = ExecutionSegmentState::new(memory, pc, 0, false); loop { // Fetch, decode and execute single instruction - let terminated_exit_code = self.execute_instruction(&mut state, &mut prev_backtrace)?; + self.execute_instruction(state, &mut prev_backtrace)?; - if let Some(exit_code) = terminated_exit_code { - state.is_terminated = true; - state.exit_code = exit_code; - self.control - .on_terminate(state.pc, &mut self.chip_complex, exit_code); + if let Some(exit_code) = state.exit_code { + self.ctrl + .on_terminate(state, &mut self.chip_complex, exit_code); break; } - if self.should_stop() { - state.exit_code = DEFAULT_SUSPEND_EXIT_CODE; - self.control - .on_segment_end(state.pc, &mut self.chip_complex); + if self.should_suspend(state) { + self.ctrl.on_suspend(state, &mut self.chip_complex); break; } } - Ok(state) + Ok(()) } /// Executes a single instruction and updates VM state // TODO(ayush): clean this up, separate to smaller functions fn execute_instruction( &mut self, - state: &mut ExecutionSegmentState, + state: &mut VmSegmentState, prev_backtrace: &mut Option, - ) -> Result, ExecutionError> { + ) -> Result<(), ExecutionError> { let pc = state.pc; let timestamp = self.chip_complex.memory_controller().timestamp(); @@ -172,7 +148,8 @@ where // Handle termination instruction if opcode == SystemOpcode::TERMINATE.global_opcode() { - return Ok(Some(c.as_canonical_u32())); + state.exit_code = Some(c.as_canonical_u32()); + return Ok(()); } // Extract debug info components @@ -218,7 +195,7 @@ where // Execute the instruction using the control implementation // TODO(AG): maybe avoid cloning the instruction? - self.control + self.ctrl .execute_instruction(state, &instruction.clone(), &mut self.chip_complex)?; // Update metrics if enabled @@ -227,20 +204,20 @@ where self.update_instruction_metrics(pc, opcode, dsl_instr); } - Ok(None) + Ok(()) } /// Returns bool of whether to switch to next segment or not. - fn should_stop(&mut self) -> bool { + fn should_suspend(&mut self, state: &mut VmSegmentState) -> bool { if !self.system_config().continuation_enabled { return false; } // Check with the execution control policy - self.control.should_stop(&self.chip_complex) + self.ctrl.should_suspend(state, &self.chip_complex) } - // TODO(ayush): not sure what to do of these + // TODO(ayush): this is not relevant for e1/e2 execution /// Generate ProofInput to prove the segment. Should be called after ::execute pub fn generate_proof_input( #[allow(unused_mut)] mut self, diff --git a/crates/vm/src/arch/segmentation_strategy.rs b/crates/vm/src/arch/segmentation_strategy.rs index a17ef97fde..000bc0f8e0 100644 --- a/crates/vm/src/arch/segmentation_strategy.rs +++ b/crates/vm/src/arch/segmentation_strategy.rs @@ -1,13 +1,13 @@ use std::sync::Arc; -const DEFAULT_MAX_SEGMENT_LEN: usize = (1 << 22) - 100; +pub const DEFAULT_MAX_SEGMENT_LEN: usize = (1 << 22) - 100; // a heuristic number for the maximum number of cells per chip in a segment // a few reasons for this number: // 1. `VmAirWrapper` is // the chip with the most cells in a segment from the reth-benchmark. // 2. `VmAirWrapper`: // its trace width is 36 and its after challenge trace width is 80. -const DEFAULT_MAX_CELLS_PER_CHIP_IN_SEGMENT: usize = DEFAULT_MAX_SEGMENT_LEN * 120; +pub const DEFAULT_MAX_CELLS_PER_CHIP_IN_SEGMENT: usize = DEFAULT_MAX_SEGMENT_LEN * 120; pub trait SegmentationStrategy: std::fmt::Debug + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe diff --git a/crates/vm/src/arch/testing/mod.rs b/crates/vm/src/arch/testing/mod.rs index bdd5691bce..fd0c73dc1a 100644 --- a/crates/vm/src/arch/testing/mod.rs +++ b/crates/vm/src/arch/testing/mod.rs @@ -1,9 +1,4 @@ -use std::{ - borrow::Borrow, - iter::zip, - rc::Rc, - sync::{Arc, Mutex}, -}; +use std::{borrow::Borrow, iter::zip}; use openvm_circuit_primitives::var_range::{ SharedVariableRangeCheckerChip, VariableRangeCheckerBus, diff --git a/crates/vm/src/arch/vm.rs b/crates/vm/src/arch/vm.rs index b861516622..ae5fd27d76 100644 --- a/crates/vm/src/arch/vm.rs +++ b/crates/vm/src/arch/vm.rs @@ -1,13 +1,14 @@ use std::{borrow::Borrow, collections::VecDeque, marker::PhantomData, mem, sync::Arc}; use openvm_circuit::system::program::trace::compute_exe_commit; -use openvm_instructions::exe::VmExe; +use openvm_instructions::{exe::VmExe, program::Program}; use openvm_stark_backend::{ config::{Com, Domain, StarkGenericConfig, Val}, engine::StarkEngine, keygen::types::{LinearConstraint, MultiStarkProvingKey, MultiStarkVerifyingKey}, p3_commit::PolynomialSpace, p3_field::{FieldAlgebra, PrimeField32}, + p3_util::log2_strict_usize, proof::Proof, prover::types::{CommittedTraceData, ProofInput}, utils::metrics_span, @@ -19,15 +20,20 @@ use thiserror::Error; use tracing::info_span; use super::{ - ExecutionError, InsExecutorE1, VmComplexTraceHeights, VmConfig, CONNECTOR_AIR_ID, - MERKLE_AIR_ID, PROGRAM_AIR_ID, PROGRAM_CACHED_TRACE_INDEX, + ExecutionError, InsExecutorE1, VmChipComplex, VmComplexTraceHeights, VmConfig, + VmInventoryError, CONNECTOR_AIR_ID, MERKLE_AIR_ID, PROGRAM_AIR_ID, PROGRAM_CACHED_TRACE_INDEX, }; #[cfg(feature = "bench-metrics")] use crate::metrics::VmMetrics; use crate::{ arch::{ - hasher::poseidon2::vm_poseidon2_hasher, segment::TracegenVmSegmentExecutor, - E1VmSegmentExecutor, + execution_mode::{ + e1::E1ExecutionControl, + metered::{MeteredCtx, MeteredExecutionControl}, + tracegen::TracegenExecutionControl, + }, + hasher::poseidon2::vm_poseidon2_hasher, + VmSegmentExecutor, VmSegmentState, }, system::{ connector::{VmConnectorPvs, DEFAULT_SUSPEND_EXIT_CODE}, @@ -101,17 +107,22 @@ pub struct VmExecutorResult { pub final_memory: Option, } -pub struct VmExecutorNextSegmentState { +pub struct VmState +where + F: PrimeField32, +{ + pub clk: u64, + pub pc: u32, pub memory: MemoryImage, pub input: Streams, - pub pc: u32, #[cfg(feature = "bench-metrics")] pub metrics: VmMetrics, } -impl VmExecutorNextSegmentState { - pub fn new(memory: MemoryImage, input: impl Into>, pc: u32) -> Self { +impl VmState { + pub fn new(clk: u64, pc: u32, memory: MemoryImage, input: impl Into>) -> Self { Self { + clk, memory, input: input.into(), pc, @@ -121,13 +132,14 @@ impl VmExecutorNextSegmentState { } } +type TracegenVmSegmentExecutor = VmSegmentExecutor; pub struct VmExecutorOneSegmentResult where F: PrimeField32, VC: VmConfig, { pub segment: TracegenVmSegmentExecutor, - pub next_state: Option>, + pub next_state: Option>, } impl VmExecutor @@ -176,7 +188,6 @@ where ) -> Result, E> { let mem_config = self.config.system().memory_config; let exe = exe.into(); - let mut segment_results = vec![]; let memory = AddressMap::from_sparse( mem_config.as_offset, 1 << mem_config.as_height, @@ -185,16 +196,16 @@ where ); let pc = exe.pc_start; - let mut state = VmExecutorNextSegmentState::new(memory, input, pc); + let mut state = VmState::new(0, pc, memory, input); #[cfg(feature = "bench-metrics")] { state.metrics.fn_bounds = exe.fn_bounds.clone(); } - let mut segment_idx = 0; - + let mut segment_results = vec![]; loop { + let segment_idx = segment_results.len(); let _span = info_span!("execute_segment", segment = segment_idx).entered(); let one_segment_result = self .execute_until_segment(exe.clone(), state) @@ -204,7 +215,6 @@ where break; } state = one_segment_result.next_state.unwrap(); - segment_idx += 1; } tracing::debug!("Number of continuation segments: {}", segment_results.len()); #[cfg(feature = "bench-metrics")] @@ -228,18 +238,25 @@ where pub fn execute_until_segment( &self, exe: impl Into>, - from_state: VmExecutorNextSegmentState, + from_state: VmState, ) -> Result, ExecutionError> { let exe = exe.into(); - let mut segment = TracegenVmSegmentExecutor::new( + let chip_complex = create_and_initialize_chip_complex( &self.config, exe.program.clone(), from_state.input, Some(from_state.memory), + ) + .unwrap(); + let ctrl = TracegenExecutionControl::new(chip_complex.air_names()); + let mut segment = TracegenVmSegmentExecutor::new( + chip_complex, self.trace_height_constraints.clone(), exe.fn_bounds.clone(), + ctrl, ); + #[cfg(feature = "bench-metrics")] { segment.metrics = from_state.metrics; @@ -247,11 +264,13 @@ where if let Some(overridden_heights) = self.overridden_heights.as_ref() { segment.set_override_trace_heights(overridden_heights.clone()); } - let state = metrics_span("execute_time_ms", || { - segment.execute_from_pc(from_state.pc, None) + + let mut exec_state = VmSegmentState::new(from_state.clk, from_state.pc, None, ()); + metrics_span("execute_time_ms", || { + segment.execute_from_state(&mut exec_state) })?; - if state.is_terminated { + if exec_state.exit_code.is_some() { return Ok(VmExecutorOneSegmentResult { segment, next_state: None, @@ -263,22 +282,21 @@ where "multiple segments require to enable continuations" ); assert_eq!( - state.pc, + exec_state.pc, segment.chip_complex.connector_chip().boundary_states[1] .unwrap() .pc ); - let final_memory = mem::take(&mut segment.control.final_memory) - .expect("final memory should be set in continuations segment"); let streams = segment.chip_complex.take_streams(); #[cfg(feature = "bench-metrics")] let metrics = segment.metrics.partial_take(); Ok(VmExecutorOneSegmentResult { segment, - next_state: Some(VmExecutorNextSegmentState { - memory: final_memory, + next_state: Some(VmState { + clk: exec_state.clk, + pc: exec_state.pc, + memory: exec_state.memory.unwrap().memory, input: streams, - pc: state.pc, #[cfg(feature = "bench-metrics")] metrics, }), @@ -301,7 +319,7 @@ where |err| err, )?; let last = last.expect("at least one segment must be executed"); - let final_memory = last.control.final_memory; + let final_memory = last.ctrl.final_memory; let end_state = last.chip_complex.connector_chip().boundary_states[1].expect("end state must be set"); if end_state.is_terminate != 1 { @@ -331,34 +349,44 @@ where ); let pc = exe.pc_start; - let mut state = VmExecutorNextSegmentState::new(memory, input, pc); + let mut state = VmState::new(0, pc, memory, input); let mut segment_idx = 0; loop { let _span = info_span!("execute_segment", segment = segment_idx).entered(); - let mut segment = E1VmSegmentExecutor::new( + let chip_complex = create_and_initialize_chip_complex( &self.config, - // TODO(ayush): avoid clones exe.program.clone(), state.input, None, + ) + .unwrap(); + let mut segment = VmSegmentExecutor::::new( + chip_complex, self.trace_height_constraints.clone(), exe.fn_bounds.clone(), + E1ExecutionControl, ); #[cfg(feature = "bench-metrics")] { segment.metrics = state.metrics; } - let exec_state = metrics_span("execute_time_ms", || { - segment.execute_from_pc(state.pc, Some(GuestMemory::new(state.memory))) + let mut exec_state = VmSegmentState::new( + state.clk, + state.pc, + Some(GuestMemory::new(state.memory)), + (), + ); + metrics_span("execute_time_ms", || { + segment.execute_from_state(&mut exec_state) })?; - if exec_state.is_terminated { + if let Some(exit_code) = exec_state.exit_code { // Check exit code for the final segment - if exec_state.exit_code != ExitCode::Success as u32 { - return Err(ExecutionError::FailedWithExitCode(exec_state.exit_code)); + if exit_code != ExitCode::Success as u32 { + return Err(ExecutionError::FailedWithExitCode(exit_code)); } tracing::debug!("Execution completed in {} segments", segment_idx + 1); #[cfg(feature = "bench-metrics")] @@ -371,17 +399,134 @@ where "multiple segments require to enable continuations" ); - let final_memory = mem::take(&mut segment.control.final_memory) - .expect("final memory should be set in continuations segment"); let streams = segment.chip_complex.take_streams(); #[cfg(feature = "bench-metrics")] let metrics = segment.metrics.partial_take(); - state = VmExecutorNextSegmentState { - memory: final_memory, + state = VmState { + clk: exec_state.clk, + pc: exec_state.pc, + memory: exec_state.memory.unwrap().memory, input: streams, + #[cfg(feature = "bench-metrics")] + metrics, + }; + + segment_idx += 1; + } + } + + pub fn execute_metered( + &self, + exe: impl Into>, + input: impl Into>, + widths: Vec, + interactions: Vec, + ) -> Result<(), ExecutionError> + where + VC::Executor: InsExecutorE1, + { + let mem_config = self.config.system().memory_config; + let exe = exe.into(); + let memory = AddressMap::from_sparse( + mem_config.as_offset, + 1 << mem_config.as_height, + 1 << mem_config.pointer_max_bits, + exe.init_memory.clone(), + ); + + let pc = exe.pc_start; + let mut state = VmState::new(0, pc, memory, input); + let mut segment_idx = 0; + + loop { + let _span = info_span!("execute_segment", segment = segment_idx).entered(); + + let chip_complex = create_and_initialize_chip_complex( + &self.config, + exe.program.clone(), + state.input, + None, + ) + .unwrap(); + let ctrl = MeteredExecutionControl::new(&widths, &interactions); + let mut segment = VmSegmentExecutor::::new( + chip_complex, + self.trace_height_constraints.clone(), + exe.fn_bounds.clone(), + ctrl, + ); + + #[cfg(feature = "bench-metrics")] + { + segment.metrics = state.metrics; + } + + let continuations_enabled = segment + .chip_complex + .memory_controller() + .continuation_enabled(); + let num_access_adapters = segment + .chip_complex + .memory_controller() + .access_adapters + .num_access_adapters(); + let ctx = MeteredCtx::new( + widths.len(), + continuations_enabled, + num_access_adapters, + segment + .chip_complex + .memory_controller() + .memory + .min_block_size + .iter() + .map(|&x| log2_strict_usize(x as usize)) + .collect(), + segment + .chip_complex + .memory_controller() + .mem_config() + .memory_dimensions(), + ); + + let mut exec_state = VmSegmentState::new( + state.clk, + state.pc, + Some(GuestMemory::new(state.memory)), + ctx, + ); + metrics_span("execute_time_ms", || { + segment.execute_from_state(&mut exec_state) + })?; + + if let Some(exit_code) = exec_state.exit_code { + // Check exit code for the final segment + if exit_code != ExitCode::Success as u32 { + return Err(ExecutionError::FailedWithExitCode(exit_code)); + } + tracing::debug!("Execution completed in {} segments", segment_idx + 1); + #[cfg(feature = "bench-metrics")] + metrics::counter!("num_segments").absolute((segment_idx + 1) as u64); + return Ok(()); + } + + assert!( + self.continuation_enabled(), + "multiple segments require to enable continuations" + ); + + let streams = segment.chip_complex.take_streams(); + + #[cfg(feature = "bench-metrics")] + let metrics = segment.metrics.partial_take(); + + state = VmState { + clk: exec_state.clk, pc: exec_state.pc, + memory: exec_state.memory.unwrap().memory, + input: streams, #[cfg(feature = "bench-metrics")] metrics, }; @@ -438,7 +583,7 @@ where |seg_idx, mut seg| { // Note: this will only be Some on the last segment; otherwise it is // already moved into next segment state - final_memory = mem::take(&mut seg.control.final_memory); + final_memory = mem::take(&mut seg.ctrl.final_memory); tracing::info_span!("trace_gen", segment = seg_idx) .in_scope(|| seg.generate_proof_input(committed_program.clone())) }, @@ -555,19 +700,28 @@ where exe: VmExe, input: impl Into>, ) -> Result, ExecutionError> { - let mut segment = TracegenVmSegmentExecutor::new( + let chip_complex = create_and_initialize_chip_complex( &self.config, exe.program.clone(), input.into(), None, + ) + .unwrap(); + let ctrl = TracegenExecutionControl::new(chip_complex.air_names()); + let mut segment = TracegenVmSegmentExecutor::new( + chip_complex, self.trace_height_constraints.clone(), exe.fn_bounds.clone(), + ctrl, ); + if let Some(overridden_heights) = self.overridden_heights.as_ref() { segment.set_override_trace_heights(overridden_heights.clone()); } + + let mut exec_state = VmSegmentState::new(0, exe.pc_start, None, ()); metrics_span("execute_time_ms", || { - segment.execute_from_pc(exe.pc_start, None) + segment.execute_from_state(&mut exec_state) })?; Ok(segment) } @@ -948,3 +1102,33 @@ where } } } + +/// Create and initialize a chip complex with program, streams, and optional memory +pub fn create_and_initialize_chip_complex( + config: &VC, + program: Program, + init_streams: Streams, + initial_memory: Option, +) -> Result, VmInventoryError> +where + F: PrimeField32, + VC: VmConfig, +{ + let mut chip_complex = config.create_chip_complex()?; + chip_complex.set_streams(init_streams); + + // Strip debug info if profiling is disabled + let program = if !config.system().profiling { + program.strip_debug_infos() + } else { + program + }; + + chip_complex.set_program(program); + + if let Some(initial_memory) = initial_memory { + chip_complex.set_initial_memory(initial_memory); + } + + Ok(chip_complex) +} diff --git a/crates/vm/src/system/memory/adapter/mod.rs b/crates/vm/src/system/memory/adapter/mod.rs index 821657e1d2..ea76117066 100644 --- a/crates/vm/src/system/memory/adapter/mod.rs +++ b/crates/vm/src/system/memory/adapter/mod.rs @@ -82,7 +82,8 @@ impl AccessAdapterInventory { where F: PrimeField32, { - self.chips[index].set_trace(RowMajorMatrix::new(trace, width)); + let trace = RowMajorMatrix::new(trace, width); + self.chips[index].set_trace(trace); } #[cfg(test)] diff --git a/crates/vm/src/system/memory/controller/dimensions.rs b/crates/vm/src/system/memory/controller/dimensions.rs index 1082d3adf0..87976d2fa0 100644 --- a/crates/vm/src/system/memory/controller/dimensions.rs +++ b/crates/vm/src/system/memory/controller/dimensions.rs @@ -30,6 +30,15 @@ impl MemoryDimensions { debug_assert!(block_id < (1 << self.address_height)); (((addr_space - self.as_offset) as u64) << self.address_height) + block_id as u64 } + + /// Convert an index in the memory merkle tree to an address label (address space, block id). + /// + /// This function performs the inverse operation of `label_to_index`. + pub fn index_to_label(&self, index: u64) -> (u32, u32) { + let block_id = (index & ((1 << self.address_height) - 1)) as u32; + let addr_space = (index >> self.address_height) as u32 + self.as_offset; + (addr_space, block_id) + } } impl MemoryConfig { diff --git a/crates/vm/src/system/memory/controller/mod.rs b/crates/vm/src/system/memory/controller/mod.rs index 28e0254c33..66d8cdde7c 100644 --- a/crates/vm/src/system/memory/controller/mod.rs +++ b/crates/vm/src/system/memory/controller/mod.rs @@ -44,6 +44,8 @@ pub mod dimensions; pub mod interface; pub const CHUNK: usize = 8; +pub const CHUNK_BITS: usize = CHUNK.ilog2() as usize; + /// The offset of the Merkle AIR in AIRs of MemoryController. pub const MERKLE_AIR_OFFSET: usize = 1; /// The offset of the boundary AIR in AIRs of MemoryController. @@ -572,11 +574,8 @@ impl MemoryController { for i in 0..self.access_adapters.num_access_adapters() { let width = self.memory.adapter_inventory_trace_cursor.width(i); - self.access_adapters.set_trace( - i, - self.memory.adapter_inventory_trace_cursor.extract_trace(i), - width, - ); + let trace = self.memory.adapter_inventory_trace_cursor.extract_trace(i); + self.access_adapters.set_trace(i, trace, width); } final_memory diff --git a/crates/vm/src/system/memory/mod.rs b/crates/vm/src/system/memory/mod.rs index 2e14cc9c86..0020e0708d 100644 --- a/crates/vm/src/system/memory/mod.rs +++ b/crates/vm/src/system/memory/mod.rs @@ -1,6 +1,6 @@ use openvm_circuit_primitives_derive::AlignedBorrow; -mod adapter; +pub mod adapter; mod controller; pub mod merkle; pub mod offline_checker; diff --git a/crates/vm/src/system/memory/online.rs b/crates/vm/src/system/memory/online.rs index f176f0d287..38d78c5f2c 100644 --- a/crates/vm/src/system/memory/online.rs +++ b/crates/vm/src/system/memory/online.rs @@ -190,9 +190,9 @@ pub struct TracingMemory { pub(super) meta: Vec>, /// For each `addr_space`, the minimum block size allowed for memory accesses. In other words, /// all memory accesses in `addr_space` must be aligned to this block size. - pub(super) min_block_size: Vec, - pub(super) access_adapter_inventory: AccessAdapterInventory, - pub(super) adapter_inventory_trace_cursor: AdapterInventoryTraceCursor, + pub min_block_size: Vec, + pub access_adapter_inventory: AccessAdapterInventory, + pub adapter_inventory_trace_cursor: AdapterInventoryTraceCursor, } impl TracingMemory { diff --git a/crates/vm/src/system/memory/paged_vec.rs b/crates/vm/src/system/memory/paged_vec.rs index 54c2f44023..6f3332734e 100644 --- a/crates/vm/src/system/memory/paged_vec.rs +++ b/crates/vm/src/system/memory/paged_vec.rs @@ -5,7 +5,6 @@ use openvm_instructions::exe::SparseMemoryImage; use openvm_stark_backend::p3_field::PrimeField32; use serde::{Deserialize, Serialize}; -use super::online::GuestMemory; use crate::arch::MemoryConfig; /// (address_space, pointer) diff --git a/crates/vm/src/system/memory/persistent.rs b/crates/vm/src/system/memory/persistent.rs index 3391e7f9e0..bdd1fa4d04 100644 --- a/crates/vm/src/system/memory/persistent.rs +++ b/crates/vm/src/system/memory/persistent.rs @@ -123,18 +123,18 @@ impl Air for PersistentBoundaryA pub struct PersistentBoundaryChip { pub air: PersistentBoundaryAir, - touched_labels: TouchedLabels, + pub touched_labels: TouchedLabels, overridden_height: Option, } #[derive(Debug)] -enum TouchedLabels { +pub enum TouchedLabels { Running(FxHashSet<(u32, u32)>), Final(Vec>), } #[derive(Debug)] -struct FinalTouchedLabel { +pub struct FinalTouchedLabel { address_space: u32, label: u32, init_values: [F; CHUNK], @@ -159,7 +159,8 @@ impl TouchedLabels { _ => panic!("Cannot touch after finalization"), } } - fn len(&self) -> usize { + + pub fn len(&self) -> usize { match self { TouchedLabels::Running(touched_labels) => touched_labels.len(), TouchedLabels::Final(touched_labels) => touched_labels.len(), diff --git a/crates/vm/src/system/memory/volatile/mod.rs b/crates/vm/src/system/memory/volatile/mod.rs index e01162c789..e345acddda 100644 --- a/crates/vm/src/system/memory/volatile/mod.rs +++ b/crates/vm/src/system/memory/volatile/mod.rs @@ -183,7 +183,7 @@ pub struct VolatileBoundaryChip { pub air: VolatileBoundaryAir, range_checker: SharedVariableRangeCheckerChip, overridden_height: Option, - final_memory: Option>, + pub final_memory: Option>, addr_space_max_bits: usize, pointer_max_bits: usize, } diff --git a/crates/vm/src/system/native_adapter/mod.rs b/crates/vm/src/system/native_adapter/mod.rs index 9fdde040ce..179a1fef29 100644 --- a/crates/vm/src/system/native_adapter/mod.rs +++ b/crates/vm/src/system/native_adapter/mod.rs @@ -28,7 +28,7 @@ use serde_big_array::BigArray; use super::memory::{online::TracingMemory, MemoryAuxColsFactory}; use crate::{ - arch::{AdapterExecutorE1, AdapterTraceStep}, + arch::{AdapterExecutorE1, AdapterTraceStep, VmStateMut}, system::memory::{online::GuestMemory, RecordId}, }; @@ -247,29 +247,39 @@ where type WriteData = [F; W]; #[inline(always)] - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData { assert!(R <= 2); let &Instruction { b, c, e, f, .. } = instruction; let mut reads = [F::ZERO; R]; if R >= 1 { - let [value] = - unsafe { memory.read::(e.as_canonical_u32(), b.as_canonical_u32()) }; + let [value] = unsafe { + state + .memory + .read::(e.as_canonical_u32(), b.as_canonical_u32()) + }; reads[0] = value; } if R >= 2 { - let [value] = - unsafe { memory.read::(f.as_canonical_u32(), c.as_canonical_u32()) }; + let [value] = unsafe { + state + .memory + .read::(f.as_canonical_u32(), c.as_canonical_u32()) + }; reads[1] = value; } reads } #[inline(always)] - fn write( + fn write( &self, - memory: &mut GuestMemory, + state: &mut VmStateMut, instruction: &Instruction, data: &Self::WriteData, ) { @@ -277,7 +287,11 @@ where let &Instruction { a, d, .. } = instruction; if W >= 1 { - unsafe { memory.write(d.as_canonical_u32(), a.as_canonical_u32(), data) }; + unsafe { + state + .memory + .write(d.as_canonical_u32(), a.as_canonical_u32(), data) + }; } } } diff --git a/crates/vm/src/system/phantom/mod.rs b/crates/vm/src/system/phantom/mod.rs index e5f0e91fc0..4e151c525b 100644 --- a/crates/vm/src/system/phantom/mod.rs +++ b/crates/vm/src/system/phantom/mod.rs @@ -26,6 +26,7 @@ use serde_big_array::BigArray; use super::memory::{online::GuestMemory, MemoryController}; use crate::{ arch::{ + execution_mode::{e1::E1Ctx, metered::MeteredCtx, E1E2ExecutionCtx}, ExecutionBridge, ExecutionBus, ExecutionError, ExecutionState, InsExecutorE1, InstructionExecutor, PcIncOrSet, PhantomSubExecutor, Streams, VmStateMut, }, @@ -130,11 +131,12 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, ) -> Result<(), ExecutionError> where F: PrimeField32, + Ctx: E1E2ExecutionCtx, { let &Instruction { opcode, a, b, c, .. @@ -176,6 +178,20 @@ where Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + _chip_index: usize, + ) -> Result<(), ExecutionError> + where + F: PrimeField32, + { + self.execute_e1(state, instruction)?; + + Ok(()) + } } impl InstructionExecutor for PhantomChip { @@ -193,12 +209,12 @@ impl InstructionExecutor for PhantomChip { is_valid: F::ONE, }); - let state = VmStateMut { + let mut state = VmStateMut { pc: &mut pc, memory: &mut memory.memory.data, - ctx: &mut (), + ctx: &mut E1Ctx::default(), }; - self.execute_e1(state, instruction)?; + self.execute_e1(&mut state, instruction)?; memory.increment_timestamp(); Ok(ExecutionState { diff --git a/crates/vm/src/system/poseidon2/trace.rs b/crates/vm/src/system/poseidon2/trace.rs index 2b6f3e6b0b..979585c830 100644 --- a/crates/vm/src/system/poseidon2/trace.rs +++ b/crates/vm/src/system/poseidon2/trace.rs @@ -8,7 +8,6 @@ use openvm_stark_backend::{ p3_matrix::dense::RowMajorMatrix, p3_maybe_rayon::prelude::*, prover::types::AirProofInput, - rap::get_air_name, AirRef, Chip, ChipUsageGetter, }; @@ -63,7 +62,7 @@ impl ChipUsageGetter for Poseidon2PeripheryBaseChip { fn air_name(&self) -> String { - get_air_name(&self.air) + format!("Poseidon2PeripheryAir", SBOX_REGISTERS) } fn current_trace_height(&self) -> usize { diff --git a/crates/vm/src/system/public_values/core.rs b/crates/vm/src/system/public_values/core.rs index a573ae8e1e..7b798606e9 100644 --- a/crates/vm/src/system/public_values/core.rs +++ b/crates/vm/src/system/public_values/core.rs @@ -17,6 +17,7 @@ use serde::{Deserialize, Serialize}; use crate::{ arch::{ + execution_mode::{e1::E1Ctx, metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterRuntimeContext, AdapterTraceStep, BasicAdapterInterface, MinimalInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmCoreChip, VmStateMut, @@ -211,10 +212,13 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { - let [value, index] = self.adapter.read(state.memory, instruction); + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { + let [value, index] = self.adapter.read(state, instruction); let idx: usize = index.as_canonical_u32() as usize; { @@ -233,6 +237,17 @@ where Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + _chip_index: usize, + ) -> Result<()> { + self.execute_e1(state, instruction)?; + + Ok(()) + } } // /// ATTENTION: If a specific public value is not provided, a default 0 will be used when diff --git a/extensions/rv32-adapters/src/eq_mod.rs b/extensions/rv32-adapters/src/eq_mod.rs index 9992f526cb..e8e2c88f47 100644 --- a/extensions/rv32-adapters/src/eq_mod.rs +++ b/extensions/rv32-adapters/src/eq_mod.rs @@ -6,8 +6,9 @@ use std::{ use itertools::izip; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, BasicAdapterInterface, - ExecutionBridge, ExecutionState, MinimalInstruction, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + BasicAdapterInterface, ExecutionBridge, ExecutionState, MinimalInstruction, VmAdapterAir, + VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, @@ -25,8 +26,8 @@ use openvm_instructions::{ riscv::{RV32_MEMORY_AS, RV32_REGISTER_AS}, }; use openvm_rv32im_circuit::adapters::{ - memory_read, memory_write, new_read_rv32_register, tracing_read, tracing_write, RV32_CELL_BITS, - RV32_REGISTER_NUM_LIMBS, + memory_read_from_state, memory_write_from_state, new_read_rv32_register_from_state, + tracing_read, tracing_write, RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS, }; use openvm_stark_backend::{ interaction::InteractionBuilder, @@ -394,7 +395,14 @@ impl< type ReadData = [[u8; TOTAL_READ_SIZE]; NUM_READS]; type WriteData = [u8; RV32_REGISTER_NUM_LIMBS]; - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { let Instruction { b, c, d, e, .. } = *instruction; let d = d.as_canonical_u32(); @@ -405,23 +413,25 @@ impl< // Read register values let rs_vals = from_fn(|i| { let addr = if i == 0 { b } else { c }; - new_read_rv32_register(memory, d, addr.as_canonical_u32()) + new_read_rv32_register_from_state(state, d, addr.as_canonical_u32()) }); // Read memory values rs_vals.map(|address| { assert!(address as usize + TOTAL_READ_SIZE - 1 < (1 << self.pointer_max_bits)); - memory_read(memory, e, address) + memory_read_from_state(state, e, address) }) } - fn write( + fn write( &self, - memory: &mut GuestMemory, + state: &mut VmStateMut, instruction: &Instruction, data: &Self::WriteData, - ) { + ) where + Ctx: E1E2ExecutionCtx, + { let Instruction { a, d, .. } = *instruction; - memory_write(memory, d.as_canonical_u32(), a.as_canonical_u32(), data); + memory_write_from_state(state, d.as_canonical_u32(), a.as_canonical_u32(), data); } } diff --git a/extensions/rv32-adapters/src/heap.rs b/extensions/rv32-adapters/src/heap.rs index acc00eba11..d596092e39 100644 --- a/extensions/rv32-adapters/src/heap.rs +++ b/extensions/rv32-adapters/src/heap.rs @@ -2,8 +2,8 @@ use std::borrow::{Borrow, BorrowMut}; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, BasicAdapterInterface, - ExecutionBridge, MinimalInstruction, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + BasicAdapterInterface, ExecutionBridge, MinimalInstruction, VmAdapterAir, VmStateMut, }, system::memory::{ offline_checker::MemoryBridge, @@ -172,19 +172,26 @@ impl) -> Self::ReadData { - let read_data = AdapterExecutorE1::::read(&self.0, memory, instruction); + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { + let read_data = AdapterExecutorE1::::read(&self.0, state, instruction); read_data.map(|r| r[0]) } - #[inline(always)] - fn write( + fn write( &self, - memory: &mut GuestMemory, + state: &mut VmStateMut, instruction: &Instruction, data: &Self::WriteData, - ) { - AdapterExecutorE1::::write(&self.0, memory, instruction, data); + ) where + Ctx: E1E2ExecutionCtx, + { + AdapterExecutorE1::::write(&self.0, state, instruction, data); } } diff --git a/extensions/rv32-adapters/src/heap_branch.rs b/extensions/rv32-adapters/src/heap_branch.rs index 1ce1873bb4..8997b78f2f 100644 --- a/extensions/rv32-adapters/src/heap_branch.rs +++ b/extensions/rv32-adapters/src/heap_branch.rs @@ -6,8 +6,9 @@ use std::{ use itertools::izip; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, BasicAdapterInterface, - ExecutionBridge, ExecutionState, ImmInstruction, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + BasicAdapterInterface, ExecutionBridge, ExecutionState, ImmInstruction, VmAdapterAir, + VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryReadAuxCols}, @@ -25,7 +26,8 @@ use openvm_instructions::{ riscv::{RV32_MEMORY_AS, RV32_REGISTER_AS}, }; use openvm_rv32im_circuit::adapters::{ - memory_read, new_read_rv32_register, tracing_read, RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS, + memory_read_from_state, new_read_rv32_register_from_state, tracing_read, RV32_CELL_BITS, + RV32_REGISTER_NUM_LIMBS, }; use openvm_stark_backend::{ interaction::InteractionBuilder, @@ -187,42 +189,6 @@ impl } } } -impl AdapterExecutorE1 - for Rv32HeapBranchAdapterStep -{ - type ReadData = [[u8; READ_SIZE]; NUM_READS]; - type WriteData = (); - - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { - let Instruction { a, b, d, e, .. } = *instruction; - - let d = d.as_canonical_u32(); - let e = e.as_canonical_u32(); - debug_assert_eq!(d, RV32_REGISTER_AS); - debug_assert_eq!(e, RV32_MEMORY_AS); - - // Read register values - let rs_vals = from_fn(|i| { - let addr = if i == 0 { a } else { b }; - new_read_rv32_register(memory, d, addr.as_canonical_u32()) - }); - - // Read memory values - rs_vals.map(|address| { - assert!(address as usize + READ_SIZE - 1 < (1 << self.pointer_max_bits)); - memory_read(memory, e, address) - }) - } - - fn write( - &self, - _memory: &mut GuestMemory, - _instruction: &Instruction, - _data: &Self::WriteData, - ) { - // This function intentionally does nothing - } -} impl AdapterTraceStep for Rv32HeapBranchAdapterStep @@ -319,3 +285,49 @@ where ); } } + +impl AdapterExecutorE1 + for Rv32HeapBranchAdapterStep +{ + type ReadData = [[u8; READ_SIZE]; NUM_READS]; + type WriteData = (); + + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { + let Instruction { a, b, d, e, .. } = *instruction; + + let d = d.as_canonical_u32(); + let e = e.as_canonical_u32(); + debug_assert_eq!(d, RV32_REGISTER_AS); + debug_assert_eq!(e, RV32_MEMORY_AS); + + // Read register values + let rs_vals = from_fn(|i| { + let addr = if i == 0 { a } else { b }; + new_read_rv32_register_from_state(state, d, addr.as_canonical_u32()) + }); + + // Read memory values + rs_vals.map(|address| { + assert!(address as usize + READ_SIZE - 1 < (1 << self.pointer_max_bits)); + memory_read_from_state(state, e, address) + }) + } + + fn write( + &self, + _state: &mut VmStateMut, + _instruction: &Instruction, + _data: &Self::WriteData, + ) where + Ctx: E1E2ExecutionCtx, + { + // This function intentionally does nothing + } +} diff --git a/extensions/rv32-adapters/src/vec_heap.rs b/extensions/rv32-adapters/src/vec_heap.rs index 85d8b05822..924cff2f3c 100644 --- a/extensions/rv32-adapters/src/vec_heap.rs +++ b/extensions/rv32-adapters/src/vec_heap.rs @@ -7,8 +7,8 @@ use std::{ use itertools::izip; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, ExecutionBridge, ExecutionState, - VecHeapAdapterInterface, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + ExecutionBridge, ExecutionState, VecHeapAdapterInterface, VmAdapterAir, VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, @@ -26,8 +26,9 @@ use openvm_instructions::{ riscv::{RV32_MEMORY_AS, RV32_REGISTER_AS}, }; use openvm_rv32im_circuit::adapters::{ - abstract_compose, memory_read, memory_write, new_read_rv32_register, tracing_read, - tracing_write, RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS, + abstract_compose, memory_read_from_state, memory_write_from_state, + new_read_rv32_register_from_state, tracing_read, tracing_write, RV32_CELL_BITS, + RV32_REGISTER_NUM_LIMBS, }; use openvm_stark_backend::{ interaction::InteractionBuilder, @@ -382,12 +383,12 @@ impl< let rd_val = u32::from_le_bytes(cols.rd_val.map(|x| x.as_canonical_u32() as u8)); assert!(rd_val as usize + WRITE_SIZE * BLOCKS_PER_WRITE - 1 < (1 << self.pointer_max_bits)); - for i in 0..BLOCKS_PER_WRITE { + for (i, block) in data.iter().enumerate() { tracing_write( memory, e, rd_val + (i * WRITE_SIZE) as u32, - &data[i], + block, &mut cols.writes_aux[i], ); } @@ -463,7 +464,14 @@ impl< type ReadData = [[[u8; READ_SIZE]; BLOCKS_PER_READ]; NUM_READS]; type WriteData = [[u8; WRITE_SIZE]; BLOCKS_PER_WRITE]; - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { let Instruction { b, c, d, e, .. } = *instruction; let d = d.as_canonical_u32(); @@ -474,7 +482,7 @@ impl< // Read register values let rs_vals = from_fn(|i| { let addr = if i == 0 { b } else { c }; - new_read_rv32_register(memory, d, addr.as_canonical_u32()) + new_read_rv32_register_from_state(state, d, addr.as_canonical_u32()) }); // Read memory values @@ -482,26 +490,29 @@ impl< assert!( address as usize + READ_SIZE * BLOCKS_PER_READ - 1 < (1 << self.pointer_max_bits) ); - from_fn(|i| memory_read(memory, e, address + (i * READ_SIZE) as u32)) + from_fn(|i| memory_read_from_state(state, e, address + (i * READ_SIZE) as u32)) }) } - fn write( + fn write( &self, - memory: &mut GuestMemory, + state: &mut VmStateMut, instruction: &Instruction, data: &Self::WriteData, - ) { + ) where + Ctx: E1E2ExecutionCtx, + { let Instruction { a, d, e, .. } = *instruction; - let rd_val = new_read_rv32_register(memory, d.as_canonical_u32(), a.as_canonical_u32()); + let rd_val = + new_read_rv32_register_from_state(state, d.as_canonical_u32(), a.as_canonical_u32()); assert!(rd_val as usize + WRITE_SIZE * BLOCKS_PER_WRITE - 1 < (1 << self.pointer_max_bits)); - for i in 0..BLOCKS_PER_WRITE { - memory_write( - memory, + for (i, block) in data.iter().enumerate() { + memory_write_from_state( + state, e.as_canonical_u32(), rd_val + (i * WRITE_SIZE) as u32, - &data[i], + block, ); } } diff --git a/extensions/rv32-adapters/src/vec_heap_two_reads.rs b/extensions/rv32-adapters/src/vec_heap_two_reads.rs index 9eeab26654..2929ece00b 100644 --- a/extensions/rv32-adapters/src/vec_heap_two_reads.rs +++ b/extensions/rv32-adapters/src/vec_heap_two_reads.rs @@ -7,8 +7,8 @@ use std::{ use itertools::izip; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, ExecutionBridge, ExecutionState, - VecHeapTwoReadsAdapterInterface, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + ExecutionBridge, ExecutionState, VecHeapTwoReadsAdapterInterface, VmAdapterAir, VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, @@ -26,8 +26,9 @@ use openvm_instructions::{ riscv::{RV32_MEMORY_AS, RV32_REGISTER_AS}, }; use openvm_rv32im_circuit::adapters::{ - abstract_compose, memory_read, memory_write, new_read_rv32_register, tracing_read, - tracing_write, RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS, + abstract_compose, memory_read_from_state, memory_write_from_state, + new_read_rv32_register_from_state, tracing_read, tracing_write, RV32_CELL_BITS, + RV32_REGISTER_NUM_LIMBS, }; use openvm_stark_backend::{ interaction::InteractionBuilder, @@ -440,12 +441,12 @@ impl< let rd_val = u32::from_le_bytes(cols.rd_val.map(|x| x.as_canonical_u32() as u8)); assert!(rd_val as usize + WRITE_SIZE * BLOCKS_PER_WRITE - 1 < (1 << self.pointer_max_bits)); - for i in 0..BLOCKS_PER_WRITE { + for (i, block) in data.iter().enumerate() { tracing_write( memory, e, rd_val + (i * WRITE_SIZE) as u32, - &data[i], + block, &mut cols.writes_aux[i], ); } @@ -521,7 +522,14 @@ impl< ); type WriteData = [[u8; WRITE_SIZE]; BLOCKS_PER_WRITE]; - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { let Instruction { b, c, d, e, .. } = *instruction; let d = d.as_canonical_u32(); @@ -530,35 +538,40 @@ impl< debug_assert_eq!(e, RV32_MEMORY_AS); // Read register values - let rs1_val = new_read_rv32_register(memory, d, b.as_canonical_u32()); - let rs2_val = new_read_rv32_register(memory, d, c.as_canonical_u32()); + let rs1_val = new_read_rv32_register_from_state(state, d, b.as_canonical_u32()); + let rs2_val = new_read_rv32_register_from_state(state, d, c.as_canonical_u32()); assert!(rs1_val as usize + READ_SIZE * BLOCKS_PER_READ1 - 1 < (1 << self.pointer_max_bits)); assert!(rs2_val as usize + READ_SIZE * BLOCKS_PER_READ2 - 1 < (1 << self.pointer_max_bits)); // Read memory values - let read_data1 = from_fn(|i| memory_read(memory, e, rs1_val + (i * READ_SIZE) as u32)); - let read_data2 = from_fn(|i| memory_read(memory, e, rs2_val + (i * READ_SIZE) as u32)); + let read_data1 = + from_fn(|i| memory_read_from_state(state, e, rs1_val + (i * READ_SIZE) as u32)); + let read_data2 = + from_fn(|i| memory_read_from_state(state, e, rs2_val + (i * READ_SIZE) as u32)); (read_data1, read_data2) } - fn write( + fn write( &self, - memory: &mut GuestMemory, + state: &mut VmStateMut, instruction: &Instruction, data: &Self::WriteData, - ) { + ) where + Ctx: E1E2ExecutionCtx, + { let Instruction { a, d, e, .. } = *instruction; - let rd_val = new_read_rv32_register(memory, d.as_canonical_u32(), a.as_canonical_u32()); + let rd_val = + new_read_rv32_register_from_state(state, d.as_canonical_u32(), a.as_canonical_u32()); assert!(rd_val as usize + WRITE_SIZE * BLOCKS_PER_WRITE - 1 < (1 << self.pointer_max_bits)); - for i in 0..BLOCKS_PER_WRITE { - memory_write( - memory, + for (i, block) in data.iter().enumerate() { + memory_write_from_state( + state, e.as_canonical_u32(), rd_val + (i * WRITE_SIZE) as u32, - &data[i], + block, ); } } diff --git a/extensions/rv32im/circuit/src/adapters/alu.rs b/extensions/rv32im/circuit/src/adapters/alu.rs index a4b930f919..242a11f90b 100644 --- a/extensions/rv32im/circuit/src/adapters/alu.rs +++ b/extensions/rv32im/circuit/src/adapters/alu.rs @@ -2,8 +2,9 @@ use std::borrow::{Borrow, BorrowMut}; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, BasicAdapterInterface, - ExecutionBridge, ExecutionState, MinimalInstruction, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + BasicAdapterInterface, ExecutionBridge, ExecutionState, MinimalInstruction, VmAdapterAir, + VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, @@ -30,7 +31,7 @@ use openvm_stark_backend::{ use super::{ tracing_read, tracing_read_imm, tracing_write, RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS, }; -use crate::adapters::{memory_read, memory_write}; +use crate::adapters::{memory_read_from_state, memory_write_from_state}; #[repr(C)] #[derive(AlignedBorrow)] @@ -285,7 +286,14 @@ where type WriteData = [[u8; RV32_REGISTER_NUM_LIMBS]; 1]; #[inline(always)] - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { let Instruction { b, c, d, e, .. } = instruction; debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS); @@ -294,11 +302,11 @@ where ); let rs1: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, RV32_REGISTER_AS, b.as_canonical_u32()); + memory_read_from_state(state, RV32_REGISTER_AS, b.as_canonical_u32()); let rs2 = if e.as_canonical_u32() == RV32_REGISTER_AS { let rs2: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, RV32_REGISTER_AS, c.as_canonical_u32()); + memory_read_from_state(state, RV32_REGISTER_AS, c.as_canonical_u32()); rs2 } else { let imm = c.as_canonical_u32(); @@ -312,11 +320,18 @@ where } #[inline(always)] - fn write(&self, memory: &mut GuestMemory, instruction: &Instruction, rd: &Self::WriteData) { + fn write( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + rd: &Self::WriteData, + ) where + Ctx: E1E2ExecutionCtx, + { let Instruction { a, d, .. } = instruction; debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS); - memory_write(memory, d.as_canonical_u32(), a.as_canonical_u32(), &rd[0]); + memory_write_from_state(state, d.as_canonical_u32(), a.as_canonical_u32(), &rd[0]); } } diff --git a/extensions/rv32im/circuit/src/adapters/branch.rs b/extensions/rv32im/circuit/src/adapters/branch.rs index c760f54995..7af331d7c5 100644 --- a/extensions/rv32im/circuit/src/adapters/branch.rs +++ b/extensions/rv32im/circuit/src/adapters/branch.rs @@ -2,8 +2,9 @@ use std::borrow::{Borrow, BorrowMut}; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, BasicAdapterInterface, - ExecutionBridge, ExecutionState, ImmInstruction, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + BasicAdapterInterface, ExecutionBridge, ExecutionState, ImmInstruction, VmAdapterAir, + VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryReadAuxCols}, @@ -22,7 +23,7 @@ use openvm_stark_backend::{ }; use super::RV32_REGISTER_NUM_LIMBS; -use crate::adapters::{memory_read, tracing_read}; +use crate::adapters::{memory_read_from_state, tracing_read}; #[repr(C)] #[derive(AlignedBorrow)] @@ -194,26 +195,35 @@ where type WriteData = (); #[inline(always)] - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { let Instruction { a, b, d, e, .. } = instruction; debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS); debug_assert_eq!(e.as_canonical_u32(), RV32_REGISTER_AS); let rs1: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, RV32_REGISTER_AS, a.as_canonical_u32()); + memory_read_from_state(state, RV32_REGISTER_AS, a.as_canonical_u32()); let rs2: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, RV32_REGISTER_AS, b.as_canonical_u32()); + memory_read_from_state(state, RV32_REGISTER_AS, b.as_canonical_u32()); [rs1, rs2] } #[inline(always)] - fn write( + fn write( &self, - _memory: &mut GuestMemory, + _state: &mut VmStateMut, _instruction: &Instruction, _data: &Self::WriteData, - ) { + ) where + Ctx: E1E2ExecutionCtx, + { } } diff --git a/extensions/rv32im/circuit/src/adapters/jalr.rs b/extensions/rv32im/circuit/src/adapters/jalr.rs index a2eeb9a11f..29bc4552df 100644 --- a/extensions/rv32im/circuit/src/adapters/jalr.rs +++ b/extensions/rv32im/circuit/src/adapters/jalr.rs @@ -2,8 +2,9 @@ use std::borrow::{Borrow, BorrowMut}; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, BasicAdapterInterface, - ExecutionBridge, ExecutionState, SignedImmInstruction, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + BasicAdapterInterface, ExecutionBridge, ExecutionState, SignedImmInstruction, VmAdapterAir, + VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, @@ -21,10 +22,11 @@ use openvm_stark_backend::{ p3_air::{AirBuilder, BaseAir}, p3_field::{Field, FieldAlgebra, PrimeField32}, }; -use serde::{Deserialize, Serialize}; use super::RV32_REGISTER_NUM_LIMBS; -use crate::adapters::{memory_read, memory_write, tracing_read, tracing_write}; +use crate::adapters::{ + memory_read_from_state, memory_write_from_state, tracing_read, tracing_write, +}; #[repr(C)] #[derive(Debug, Clone, AlignedBorrow)] @@ -242,24 +244,33 @@ where type WriteData = [u8; RV32_REGISTER_NUM_LIMBS]; #[inline(always)] - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { let Instruction { b, d, .. } = instruction; debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS); let rs1: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, RV32_REGISTER_AS, b.as_canonical_u32()); + memory_read_from_state(state, RV32_REGISTER_AS, b.as_canonical_u32()); rs1 } #[inline(always)] - fn write( + fn write( &self, - memory: &mut GuestMemory, + state: &mut VmStateMut, instruction: &Instruction, data: &Self::WriteData, - ) { + ) where + Ctx: E1E2ExecutionCtx, + { let Instruction { a, d, f: enabled, .. } = instruction; @@ -267,7 +278,7 @@ where debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS); if *enabled != F::ZERO { - memory_write(memory, RV32_REGISTER_AS, a.as_canonical_u32(), data); + memory_write_from_state(state, RV32_REGISTER_AS, a.as_canonical_u32(), data); } } } diff --git a/extensions/rv32im/circuit/src/adapters/loadstore.rs b/extensions/rv32im/circuit/src/adapters/loadstore.rs index 951bf7099d..9ca3135af2 100644 --- a/extensions/rv32im/circuit/src/adapters/loadstore.rs +++ b/extensions/rv32im/circuit/src/adapters/loadstore.rs @@ -6,8 +6,8 @@ use std::{ use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, ExecutionBridge, ExecutionState, - VmAdapterAir, VmAdapterInterface, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + ExecutionBridge, ExecutionState, VmAdapterAir, VmAdapterInterface, VmStateMut, }, system::memory::{ offline_checker::{MemoryBaseAuxCols, MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, @@ -35,7 +35,8 @@ use openvm_stark_backend::{ use super::RV32_REGISTER_NUM_LIMBS; use crate::adapters::{ - memory_read, memory_write, tracing_read, tracing_write_with_base_aux, RV32_CELL_BITS, + memory_read, memory_read_from_state, memory_write_from_state, tracing_read, + tracing_write_with_base_aux, RV32_CELL_BITS, }; /// LoadStore Adapter handles all memory and register operations, so it must be aware @@ -563,7 +564,14 @@ where ); type WriteData = [u8; RV32_REGISTER_NUM_LIMBS]; - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, a, @@ -583,7 +591,7 @@ where ); let rs1_bytes: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, d.as_canonical_u32(), b.as_canonical_u32()); + memory_read_from_state(state, d.as_canonical_u32(), b.as_canonical_u32()); let rs1_val = u32::from_le_bytes(rs1_bytes); let imm = c.as_canonical_u32(); @@ -602,28 +610,32 @@ where let read_data: [u8; RV32_REGISTER_NUM_LIMBS] = match local_opcode { LOADW | LOADB | LOADH | LOADBU | LOADHU => { - memory_read(memory, e.as_canonical_u32(), ptr_val) + memory_read_from_state(state, e.as_canonical_u32(), ptr_val) + } + STOREW | STOREH | STOREB => { + memory_read_from_state(state, RV32_REGISTER_AS, a.as_canonical_u32()) } - STOREW | STOREH | STOREB => memory_read(memory, RV32_REGISTER_AS, a.as_canonical_u32()), }; // For stores, we need the previous memory content to preserve unchanged bytes let prev_data: [u8; RV32_REGISTER_NUM_LIMBS] = match local_opcode { - STOREW | STOREH | STOREB => memory_read(memory, e.as_canonical_u32(), ptr_val), + STOREW | STOREH | STOREB => memory_read(state.memory, e.as_canonical_u32(), ptr_val), LOADW | LOADB | LOADH | LOADBU | LOADHU => { - memory_read(memory, RV32_REGISTER_AS, a.as_canonical_u32()) + memory_read(state.memory, RV32_REGISTER_AS, a.as_canonical_u32()) } }; ((prev_data, read_data), shift_amount) } - fn write( + fn write( &self, - memory: &mut GuestMemory, + state: &mut VmStateMut, instruction: &Instruction, data: &Self::WriteData, - ) { + ) where + Ctx: E1E2ExecutionCtx, + { // TODO(ayush): remove duplication with read let &Instruction { opcode, @@ -645,7 +657,7 @@ where ); let rs1_bytes: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, RV32_REGISTER_AS, b.as_canonical_u32()); + memory_read(state.memory, RV32_REGISTER_AS, b.as_canonical_u32()); let rs1_val = u32::from_le_bytes(rs1_bytes); let imm = c.as_canonical_u32(); @@ -669,10 +681,10 @@ where match local_opcode { STOREW | STOREH | STOREB => { let ptr = mem_ptr_limbs[0] + mem_ptr_limbs[1] * (1 << (RV32_CELL_BITS * 2)); - memory_write(memory, e.as_canonical_u32(), ptr & 0xfffffffc, data); + memory_write_from_state(state, e.as_canonical_u32(), ptr & 0xfffffffc, data); } LOADW | LOADB | LOADH | LOADBU | LOADHU => { - memory_write(memory, RV32_REGISTER_AS, a.as_canonical_u32(), data); + memory_write_from_state(state, RV32_REGISTER_AS, a.as_canonical_u32(), data); } } } diff --git a/extensions/rv32im/circuit/src/adapters/mod.rs b/extensions/rv32im/circuit/src/adapters/mod.rs index ba458930df..484c646a52 100644 --- a/extensions/rv32im/circuit/src/adapters/mod.rs +++ b/extensions/rv32im/circuit/src/adapters/mod.rs @@ -1,10 +1,13 @@ use std::ops::Mul; -use openvm_circuit::system::memory::{ - offline_checker::{MemoryBaseAuxCols, MemoryReadAuxCols, MemoryWriteAuxCols}, - online::{GuestMemory, TracingMemory}, - tree::public_values::PUBLIC_VALUES_AS, - MemoryController, RecordId, +use openvm_circuit::{ + arch::{execution_mode::E1E2ExecutionCtx, VmStateMut}, + system::memory::{ + offline_checker::{MemoryBaseAuxCols, MemoryReadAuxCols, MemoryWriteAuxCols}, + online::{GuestMemory, TracingMemory}, + tree::public_values::PUBLIC_VALUES_AS, + MemoryController, RecordId, + }, }; use openvm_instructions::riscv::{RV32_MEMORY_AS, RV32_REGISTER_AS}; use openvm_stark_backend::p3_field::{FieldAlgebra, PrimeField32}; @@ -87,6 +90,34 @@ pub fn memory_write( unsafe { memory.write::(address_space, ptr, data) } } +#[inline(always)] +pub fn memory_read_from_state( + state: &mut VmStateMut, + address_space: u32, + ptr: u32, +) -> [u8; N] +where + Ctx: E1E2ExecutionCtx, +{ + state.ctx.on_memory_operation(address_space, ptr, N); + + memory_read(state.memory, address_space, ptr) +} + +#[inline(always)] +pub fn memory_write_from_state( + state: &mut VmStateMut, + address_space: u32, + ptr: u32, + data: &[u8; N], +) where + Ctx: E1E2ExecutionCtx, +{ + state.ctx.on_memory_operation(address_space, ptr, N); + + memory_write(state.memory, address_space, ptr, data) +} + /// Atomic read operation which increments the timestamp by 1. /// Returns `(t_prev, [ptr:4]_{address_space})` where `t_prev` is the timestamp of the last memory /// access. @@ -218,12 +249,24 @@ pub fn read_rv32_register( (record.0, val) } -// TODO(AG): if "register", why `address_space` is not hardcoded to be 1? #[inline(always)] pub fn new_read_rv32_register(memory: &GuestMemory, address_space: u32, ptr: u32) -> u32 { u32::from_le_bytes(memory_read(memory, address_space, ptr)) } +// TODO(AG): if "register", why `address_space` is not hardcoded to be 1? +#[inline(always)] +pub fn new_read_rv32_register_from_state( + state: &mut VmStateMut, + address_space: u32, + ptr: u32, +) -> u32 +where + Ctx: E1E2ExecutionCtx, +{ + u32::from_le_bytes(memory_read_from_state(state, address_space, ptr)) +} + /// Peeks at the value of a register without updating the memory state or incrementing the /// timestamp. pub fn unsafe_read_rv32_register(memory: &MemoryController, pointer: F) -> u32 { diff --git a/extensions/rv32im/circuit/src/adapters/mul.rs b/extensions/rv32im/circuit/src/adapters/mul.rs index 875b21eda1..de5460e402 100644 --- a/extensions/rv32im/circuit/src/adapters/mul.rs +++ b/extensions/rv32im/circuit/src/adapters/mul.rs @@ -2,8 +2,9 @@ use std::borrow::{Borrow, BorrowMut}; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, BasicAdapterInterface, - ExecutionBridge, ExecutionState, MinimalInstruction, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + BasicAdapterInterface, ExecutionBridge, ExecutionState, MinimalInstruction, VmAdapterAir, + VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, @@ -22,7 +23,7 @@ use openvm_stark_backend::{ }; use super::{tracing_write, RV32_REGISTER_NUM_LIMBS}; -use crate::adapters::{memory_read, memory_write, tracing_read}; +use crate::adapters::{memory_read_from_state, memory_write_from_state, tracing_read}; #[repr(C)] #[derive(AlignedBorrow)] @@ -227,25 +228,39 @@ where type WriteData = [[u8; RV32_REGISTER_NUM_LIMBS]; 1]; #[inline(always)] - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { let Instruction { b, c, d, .. } = instruction; debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS); let rs1: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, RV32_REGISTER_AS, b.as_canonical_u32()); + memory_read_from_state(state, RV32_REGISTER_AS, b.as_canonical_u32()); let rs2: [u8; RV32_REGISTER_NUM_LIMBS] = - memory_read(memory, RV32_REGISTER_AS, c.as_canonical_u32()); + memory_read_from_state(state, RV32_REGISTER_AS, c.as_canonical_u32()); [rs1, rs2] } #[inline(always)] - fn write(&self, memory: &mut GuestMemory, instruction: &Instruction, rd: &Self::WriteData) { + fn write( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + rd: &Self::WriteData, + ) where + Ctx: E1E2ExecutionCtx, + { let Instruction { a, d, .. } = *instruction; debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS); - memory_write(memory, RV32_REGISTER_AS, a.as_canonical_u32(), &rd[0]); + memory_write_from_state(state, RV32_REGISTER_AS, a.as_canonical_u32(), &rd[0]); } } diff --git a/extensions/rv32im/circuit/src/adapters/rdwrite.rs b/extensions/rv32im/circuit/src/adapters/rdwrite.rs index 59ebaddeb6..d577d32a0b 100644 --- a/extensions/rv32im/circuit/src/adapters/rdwrite.rs +++ b/extensions/rv32im/circuit/src/adapters/rdwrite.rs @@ -2,8 +2,9 @@ use std::borrow::{Borrow, BorrowMut}; use openvm_circuit::{ arch::{ - AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, BasicAdapterInterface, - ExecutionBridge, ExecutionState, ImmInstruction, VmAdapterAir, + execution_mode::E1E2ExecutionCtx, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, + BasicAdapterInterface, ExecutionBridge, ExecutionState, ImmInstruction, VmAdapterAir, + VmStateMut, }, system::memory::{ offline_checker::{MemoryBridge, MemoryWriteAuxCols}, @@ -21,10 +22,9 @@ use openvm_stark_backend::{ p3_air::{AirBuilder, BaseAir}, p3_field::{Field, FieldAlgebra, PrimeField32}, }; -use serde::{Deserialize, Serialize}; use super::RV32_REGISTER_NUM_LIMBS; -use crate::adapters::{memory_write, tracing_write}; +use crate::adapters::{memory_write_from_state, tracing_write}; #[repr(C)] #[derive(Debug, Clone, AlignedBorrow)] @@ -265,15 +265,30 @@ where type WriteData = [u8; RV32_REGISTER_NUM_LIMBS]; #[inline(always)] - fn read(&self, _memory: &mut GuestMemory, _instruction: &Instruction) -> Self::ReadData {} + fn read( + &self, + _state: &mut VmStateMut, + _instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { + } #[inline(always)] - fn write(&self, memory: &mut GuestMemory, instruction: &Instruction, rd: &Self::WriteData) { + fn write( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + rd: &Self::WriteData, + ) where + Ctx: E1E2ExecutionCtx, + { let Instruction { a, d, .. } = instruction; debug_assert_eq!(d.as_canonical_u32(), RV32_REGISTER_AS); - memory_write(memory, RV32_REGISTER_AS, a.as_canonical_u32(), rd); + memory_write_from_state(state, RV32_REGISTER_AS, a.as_canonical_u32(), rd); } } @@ -375,18 +390,32 @@ where type WriteData = [u8; RV32_REGISTER_NUM_LIMBS]; #[inline(always)] - fn read(&self, memory: &mut GuestMemory, instruction: &Instruction) -> Self::ReadData { - >::read(&self.inner, memory, instruction) + fn read( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + ) -> Self::ReadData + where + Ctx: E1E2ExecutionCtx, + { + >::read(&self.inner, state, instruction) } #[inline(always)] - fn write(&self, memory: &mut GuestMemory, instruction: &Instruction, rd: &Self::WriteData) { + fn write( + &self, + state: &mut VmStateMut, + instruction: &Instruction, + rd: &Self::WriteData, + ) where + Ctx: E1E2ExecutionCtx, + { let Instruction { f: enabled, .. } = instruction; if *enabled != F::ZERO { >::write( &self.inner, - memory, + state, instruction, rd, ) diff --git a/extensions/rv32im/circuit/src/auipc/core.rs b/extensions/rv32im/circuit/src/auipc/core.rs index 1e746ccbe8..e8cd98ac4a 100644 --- a/extensions/rv32im/circuit/src/auipc/core.rs +++ b/extensions/rv32im/circuit/src/auipc/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, ImmInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -29,7 +30,6 @@ use openvm_stark_backend::{ p3_field::{Field, FieldAlgebra, PrimeField32}, rap::BaseAirWithPublicValues, }; -use serde::{Deserialize, Serialize}; use crate::adapters::{Rv32RdWriteAdapterCols, RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS}; @@ -239,7 +239,7 @@ where let local_opcode = Rv32AuipcOpcode::from_usize(opcode.local_opcode_idx(Rv32AuipcOpcode::CLASS_OFFSET)); - let mut row_slice = &mut trace[*trace_offset..*trace_offset + width]; + let row_slice = &mut trace[*trace_offset..*trace_offset + width]; let (adapter_row, core_row) = unsafe { row_slice.split_at_mut_unchecked(A::WIDTH) }; A::start(*state.pc, state.memory, adapter_row); @@ -312,9 +312,12 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, c: imm, .. } = instruction; let local_opcode = @@ -323,12 +326,24 @@ where let imm = imm.as_canonical_u32(); let rd = run_auipc(local_opcode, *state.pc, imm); - self.adapter.write(state.memory, instruction, &rd); + self.adapter.write(state, instruction, &rd); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // returns rd_data diff --git a/extensions/rv32im/circuit/src/base_alu/core.rs b/extensions/rv32im/circuit/src/base_alu/core.rs index a653a69da3..7e87739569 100644 --- a/extensions/rv32im/circuit/src/base_alu/core.rs +++ b/extensions/rv32im/circuit/src/base_alu/core.rs @@ -6,6 +6,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, MinimalInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -285,21 +286,36 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, .. } = instruction; let local_opcode = BaseAluOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let [rs1, rs2] = self.adapter.read(state.memory, instruction).into(); + let [rs1, rs2] = self.adapter.read(state, instruction).into(); let rd = run_alu::(local_opcode, &rs1, &rs2); - self.adapter.write(state.memory, instruction, &[rd].into()); + self.adapter.write(state, instruction, &[rd].into()); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } #[inline(always)] diff --git a/extensions/rv32im/circuit/src/branch_eq/core.rs b/extensions/rv32im/circuit/src/branch_eq/core.rs index 901de4943a..b95bb0f79b 100644 --- a/extensions/rv32im/circuit/src/branch_eq/core.rs +++ b/extensions/rv32im/circuit/src/branch_eq/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, ImmInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -13,12 +14,9 @@ use openvm_circuit::{ MemoryAuxColsFactory, }, }; -use openvm_circuit_primitives::{ - bitwise_op_lookup::{BitwiseOperationLookupChip, SharedBitwiseOperationLookupChip}, - utils::not, -}; +use openvm_circuit_primitives::utils::not; use openvm_circuit_primitives_derive::AlignedBorrow; -use openvm_instructions::{instruction::Instruction, riscv::RV32_CELL_BITS, LocalOpcode}; +use openvm_instructions::{instruction::Instruction, LocalOpcode}; use openvm_rv32im_transpiler::BranchEqualOpcode; use openvm_stark_backend::{ interaction::InteractionBuilder, @@ -232,14 +230,17 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let &Instruction { opcode, c: imm, .. } = instruction; let branch_eq_opcode = BranchEqualOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let [rs1, rs2] = self.adapter.read(state.memory, instruction).into(); + let [rs1, rs2] = self.adapter.read(state, instruction).into(); // TODO(ayush): probably don't need the other values let (cmp_result, _, _) = run_eq::(branch_eq_opcode, &rs1, &rs2); @@ -254,6 +255,18 @@ where Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // Returns (cmp_result, diff_idx, x[diff_idx] - y[diff_idx]) diff --git a/extensions/rv32im/circuit/src/branch_eq/tests.rs b/extensions/rv32im/circuit/src/branch_eq/tests.rs index 33d4566315..e5da1f901f 100644 --- a/extensions/rv32im/circuit/src/branch_eq/tests.rs +++ b/extensions/rv32im/circuit/src/branch_eq/tests.rs @@ -40,7 +40,7 @@ const MAX_INS_CAPACITY: usize = 128; const ABS_MAX_IMM: i32 = 1 << (RV_B_TYPE_IMM_BITS - 1); fn create_test_chip(tester: &mut VmChipTestBuilder) -> Rv32BranchEqualChip { - let chip = Rv32BranchEqualChip::::new( + Rv32BranchEqualChip::::new( VmAirWrapper::new( Rv32BranchAdapterAir::new(tester.execution_bridge(), tester.memory_bridge()), BranchEqualCoreAir::new(BranchEqualOpcode::CLASS_OFFSET, DEFAULT_PC_STEP), @@ -52,9 +52,7 @@ fn create_test_chip(tester: &mut VmChipTestBuilder) -> Rv32BranchEqualChip ), MAX_INS_CAPACITY, tester.memory_helper(), - ); - - chip + ) } #[allow(clippy::too_many_arguments)] diff --git a/extensions/rv32im/circuit/src/branch_lt/core.rs b/extensions/rv32im/circuit/src/branch_lt/core.rs index b08ff35ae3..6240c064f5 100644 --- a/extensions/rv32im/circuit/src/branch_lt/core.rs +++ b/extensions/rv32im/circuit/src/branch_lt/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, ImmInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -360,14 +361,17 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let &Instruction { opcode, c: imm, .. } = instruction; let blt_opcode = BranchLessThanOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let [rs1, rs2] = self.adapter.read(state.memory, instruction).into(); + let [rs1, rs2] = self.adapter.read(state, instruction).into(); // TODO(ayush): probably don't need the other values let (cmp_result, _, _, _) = run_cmp::(blt_opcode, &rs1, &rs2); @@ -380,6 +384,18 @@ where Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // Returns (cmp_result, diff_idx, x_sign, y_sign) diff --git a/extensions/rv32im/circuit/src/divrem/core.rs b/extensions/rv32im/circuit/src/divrem/core.rs index c3141249ac..01585ab2af 100644 --- a/extensions/rv32im/circuit/src/divrem/core.rs +++ b/extensions/rv32im/circuit/src/divrem/core.rs @@ -7,6 +7,7 @@ use num_bigint::BigUint; use num_integer::Integer; use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, MinimalInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -463,7 +464,7 @@ where ); } - let c_sum_f = F::from_canonical_u32(c.iter().fold(0, |acc, c| acc + c)); + let c_sum_f = F::from_canonical_u32(c.iter().sum()); let c_sum_inv_f = c_sum_f.try_inverse().unwrap_or(F::ZERO); let r_sum_f = r @@ -544,15 +545,18 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, .. } = *instruction; // Determine opcode and operation type let divrem_opcode = DivRemOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let [rs1, rs2] = self.adapter.read(state.memory, instruction).into(); + let [rs1, rs2] = self.adapter.read(state, instruction).into(); let rs1 = rs1.map(u32::from); let rs2 = rs2.map(u32::from); @@ -569,12 +573,24 @@ where r.map(|x| x as u8) }; - self.adapter.write(state.memory, instruction, &[rd].into()); + self.adapter.write(state, instruction, &[rd].into()); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // Returns (quotient, remainder, x_sign, y_sign, q_sign, case) where case = 0 for normal, 1 diff --git a/extensions/rv32im/circuit/src/hintstore/mod.rs b/extensions/rv32im/circuit/src/hintstore/mod.rs index 41b0501100..e770abc4fe 100644 --- a/extensions/rv32im/circuit/src/hintstore/mod.rs +++ b/extensions/rv32im/circuit/src/hintstore/mod.rs @@ -5,22 +5,19 @@ use std::{ use openvm_circuit::{ arch::{ - ExecutionBridge, ExecutionBus, ExecutionError, ExecutionState, InsExecutorE1, - InstructionExecutor, NewVmChipWrapper, Result, StepExecutorE1, Streams, TraceStep, - VmStateMut, + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, + ExecutionBridge, ExecutionError, ExecutionState, NewVmChipWrapper, Result, StepExecutorE1, + Streams, TraceStep, VmStateMut, }, - system::{ - memory::{ - offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, - online::{GuestMemory, TracingMemory}, - MemoryAddress, MemoryAuxColsFactory, MemoryController, RecordId, - }, - program::ProgramBus, + system::memory::{ + offline_checker::{MemoryBridge, MemoryReadAuxCols, MemoryWriteAuxCols}, + online::{GuestMemory, TracingMemory}, + MemoryAddress, MemoryAuxColsFactory, RecordId, }, }; use openvm_circuit_primitives::{ bitwise_op_lookup::{BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip}, - utils::{next_power_of_two_or_zero, not}, + utils::not, }; use openvm_circuit_primitives_derive::AlignedBorrow; use openvm_instructions::{ @@ -34,21 +31,15 @@ use openvm_rv32im_transpiler::{ Rv32HintStoreOpcode::{HINT_BUFFER, HINT_STOREW}, }; use openvm_stark_backend::{ - config::{StarkGenericConfig, Val}, interaction::InteractionBuilder, p3_air::{Air, AirBuilder, BaseAir}, p3_field::{Field, FieldAlgebra, PrimeField32}, - p3_matrix::{dense::RowMajorMatrix, Matrix}, - prover::types::AirProofInput, - rap::{AnyRap, BaseAirWithPublicValues, PartitionedBaseAir}, - Chip, ChipUsageGetter, + p3_matrix::Matrix, + rap::{BaseAirWithPublicValues, PartitionedBaseAir}, }; -use rand::distributions::weighted; use serde::{Deserialize, Serialize}; -use crate::adapters::{ - decompose, memory_read, memory_write, tmp_convert_to_u8s, tracing_read, tracing_write, -}; +use crate::adapters::{decompose, memory_read, memory_write, tracing_read, tracing_write}; #[cfg(test)] mod tests; @@ -345,7 +336,7 @@ where let local_opcode = Rv32HintStoreOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let mut row: &mut Rv32HintStoreCols = + let row: &mut Rv32HintStoreCols = trace[*trace_offset..*trace_offset + width].borrow_mut(); row.from_state.pc = F::from_canonical_u32(*state.pc); @@ -464,9 +455,12 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let &Instruction { opcode, a: num_words_ptr, @@ -523,6 +517,38 @@ where Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + // TODO(ayush): remove duplication + let &Instruction { + opcode, + a: num_words_ptr, + .. + } = instruction; + + let local_opcode = Rv32HintStoreOpcode::from_usize(opcode.local_opcode_idx(self.offset)); + + let num_words = if local_opcode == HINT_STOREW { + 1 + } else { + let num_words_limbs = memory_read( + state.memory, + RV32_REGISTER_AS, + num_words_ptr.as_canonical_u32(), + ); + u32::from_le_bytes(num_words_limbs) + }; + + state.ctx.trace_heights[chip_index] += num_words as usize; + self.execute_e1(state, instruction)?; + + Ok(()) + } } pub type Rv32HintStoreChip = NewVmChipWrapper>; diff --git a/extensions/rv32im/circuit/src/jal_lui/core.rs b/extensions/rv32im/circuit/src/jal_lui/core.rs index e90c0a8432..e210ad4eb3 100644 --- a/extensions/rv32im/circuit/src/jal_lui/core.rs +++ b/extensions/rv32im/circuit/src/jal_lui/core.rs @@ -2,6 +2,7 @@ use std::borrow::{Borrow, BorrowMut}; use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, ImmInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -26,7 +27,6 @@ use openvm_stark_backend::{ p3_field::{Field, FieldAlgebra, PrimeField32}, rap::BaseAirWithPublicValues, }; -use serde::{Deserialize, Serialize}; use crate::adapters::{RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS, RV_J_TYPE_IMM_BITS}; @@ -194,7 +194,7 @@ where let local_opcode = Rv32JalLuiOpcode::from_usize(opcode.local_opcode_idx(Rv32JalLuiOpcode::CLASS_OFFSET)); - let mut row_slice = &mut trace[*trace_offset..*trace_offset + width]; + let row_slice = &mut trace[*trace_offset..*trace_offset + width]; let (adapter_row, core_row) = unsafe { row_slice.split_at_mut_unchecked(A::WIDTH) }; A::start(*state.pc, state.memory, adapter_row); @@ -257,9 +257,12 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, c: imm, .. } = instruction; let local_opcode = @@ -280,12 +283,24 @@ where }; let (to_pc, rd) = run_jal_lui(local_opcode, *state.pc, signed_imm); - self.adapter.write(state.memory, instruction, &rd); + self.adapter.write(state, instruction, &rd); *state.pc = to_pc; Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // returns (to_pc, rd_data) diff --git a/extensions/rv32im/circuit/src/jalr/core.rs b/extensions/rv32im/circuit/src/jalr/core.rs index b0746c5ae8..2f016d826c 100644 --- a/extensions/rv32im/circuit/src/jalr/core.rs +++ b/extensions/rv32im/circuit/src/jalr/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, Result, SignedImmInstruction, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -30,7 +31,6 @@ use openvm_stark_backend::{ p3_field::{Field, FieldAlgebra, PrimeField32}, rap::BaseAirWithPublicValues, }; -use serde::{Deserialize, Serialize}; use crate::adapters::{compose, Rv32JalrAdapterCols, RV32_CELL_BITS, RV32_REGISTER_NUM_LIMBS}; @@ -229,7 +229,7 @@ where let local_opcode = Rv32JalrOpcode::from_usize(opcode.local_opcode_idx(Rv32JalrOpcode::CLASS_OFFSET)); - let mut row_slice = &mut trace[*trace_offset..*trace_offset + width]; + let row_slice = &mut trace[*trace_offset..*trace_offset + width]; let (adapter_row, core_row) = unsafe { row_slice.split_at_mut_unchecked(A::WIDTH) }; A::start(*state.pc, state.memory, adapter_row); @@ -334,15 +334,18 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, c, g, .. } = instruction; let local_opcode = Rv32JalrOpcode::from_usize(opcode.local_opcode_idx(Rv32JalrOpcode::CLASS_OFFSET)); - let rs1 = self.adapter.read(state.memory, instruction); + let rs1 = self.adapter.read(state, instruction); let rs1 = u32::from_le_bytes(rs1); let imm = c.as_canonical_u32(); @@ -353,12 +356,24 @@ where let (to_pc, rd) = run_jalr(local_opcode, *state.pc, imm_extended, rs1); let rd = rd.map(|x| x as u8); - self.adapter.write(state.memory, instruction, &rd); + self.adapter.write(state, instruction, &rd); *state.pc = to_pc; Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // returns (to_pc, rd_data) diff --git a/extensions/rv32im/circuit/src/less_than/core.rs b/extensions/rv32im/circuit/src/less_than/core.rs index 6baeab4ddd..1ddd266ab6 100644 --- a/extensions/rv32im/circuit/src/less_than/core.rs +++ b/extensions/rv32im/circuit/src/less_than/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, MinimalInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -337,14 +338,17 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, .. } = instruction; let less_than_opcode = LessThanOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let [rs1, rs2] = self.adapter.read(state.memory, instruction).into(); + let [rs1, rs2] = self.adapter.read(state, instruction).into(); // Run the comparison let (cmp_result, _, _, _) = @@ -352,12 +356,24 @@ where let mut rd = [0u8; NUM_LIMBS]; rd[0] = cmp_result as u8; - self.adapter.write(state.memory, instruction, &[rd].into()); + self.adapter.write(state, instruction, &[rd].into()); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // Returns (cmp_result, diff_idx, x_sign, y_sign) diff --git a/extensions/rv32im/circuit/src/load_sign_extend/core.rs b/extensions/rv32im/circuit/src/load_sign_extend/core.rs index d2782005c9..992229b893 100644 --- a/extensions/rv32im/circuit/src/load_sign_extend/core.rs +++ b/extensions/rv32im/circuit/src/load_sign_extend/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -235,7 +236,7 @@ where opcode.local_opcode_idx(Rv32LoadStoreOpcode::CLASS_OFFSET), ); - let mut row_slice = &mut trace[*trace_offset..*trace_offset + width]; + let row_slice = &mut trace[*trace_offset..*trace_offset + width]; let (adapter_row, core_row) = unsafe { row_slice.split_at_mut_unchecked(A::WIDTH) }; A::start(*state.pc, state.memory, adapter_row); @@ -316,16 +317,19 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, .. } = instruction; let local_opcode = Rv32LoadStoreOpcode::from_usize( opcode.local_opcode_idx(Rv32LoadStoreOpcode::CLASS_OFFSET), ); - let ((_, read_data), shift_amount) = self.adapter.read(state.memory, instruction); + let ((_, read_data), shift_amount) = self.adapter.read(state, instruction); let read_data = read_data.map(F::from_canonical_u8); // TODO(ayush): clean this up for e1 @@ -337,12 +341,24 @@ where ); let write_data = write_data.map(|x| x.as_canonical_u32() as u8); - self.adapter.write(state.memory, instruction, &write_data); + self.adapter.write(state, instruction, &write_data); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // TODO(ayush): remove _prev_data diff --git a/extensions/rv32im/circuit/src/load_sign_extend/tests.rs b/extensions/rv32im/circuit/src/load_sign_extend/tests.rs index 32474eb494..b3f4805a00 100644 --- a/extensions/rv32im/circuit/src/load_sign_extend/tests.rs +++ b/extensions/rv32im/circuit/src/load_sign_extend/tests.rs @@ -41,7 +41,7 @@ fn into_limbs(num: u32) -> [u32; fn create_test_chip(tester: &mut VmChipTestBuilder) -> Rv32LoadSignExtendChip { let range_checker_chip = tester.memory_controller().range_checker.clone(); - let chip = Rv32LoadSignExtendChip::::new( + Rv32LoadSignExtendChip::::new( VmAirWrapper::new( Rv32LoadStoreAdapterAir::new( tester.memory_bridge(), @@ -57,9 +57,7 @@ fn create_test_chip(tester: &mut VmChipTestBuilder) -> Rv32LoadSignExtendChip ), MAX_INS_CAPACITY, tester.memory_helper(), - ); - - chip + ) } #[allow(clippy::too_many_arguments)] diff --git a/extensions/rv32im/circuit/src/loadstore/core.rs b/extensions/rv32im/circuit/src/loadstore/core.rs index 9baa0c65ec..dc9be8aac5 100644 --- a/extensions/rv32im/circuit/src/loadstore/core.rs +++ b/extensions/rv32im/circuit/src/loadstore/core.rs @@ -2,6 +2,7 @@ use std::borrow::{Borrow, BorrowMut}; use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -305,7 +306,7 @@ where let local_opcode = Rv32LoadStoreOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let mut row_slice = &mut trace[*trace_offset..*trace_offset + width]; + let row_slice = &mut trace[*trace_offset..*trace_offset + width]; let (adapter_row, core_row) = unsafe { row_slice.split_at_mut_unchecked(A::WIDTH) }; A::start(*state.pc, state.memory, adapter_row); @@ -380,15 +381,18 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, .. } = instruction; // Get the local opcode for this instruction let local_opcode = Rv32LoadStoreOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let ((prev_data, read_data), shift_amount) = self.adapter.read(state.memory, instruction); + let ((prev_data, read_data), shift_amount) = self.adapter.read(state, instruction); let prev_data = prev_data.map(F::from_canonical_u8); let read_data = read_data.map(F::from_canonical_u8); @@ -396,12 +400,24 @@ where let write_data = run_write_data(local_opcode, read_data, prev_data, shift_amount); let write_data = write_data.map(|x| x.as_canonical_u32() as u8); - self.adapter.write(state.memory, instruction, &write_data); + self.adapter.write(state, instruction, &write_data); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } #[inline(always)] diff --git a/extensions/rv32im/circuit/src/mul/core.rs b/extensions/rv32im/circuit/src/mul/core.rs index b1df4b8e64..32ce87af1b 100644 --- a/extensions/rv32im/circuit/src/mul/core.rs +++ b/extensions/rv32im/circuit/src/mul/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, MinimalInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -236,9 +237,12 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, .. } = instruction; // Verify the opcode is MUL @@ -248,16 +252,28 @@ where MulOpcode::MUL ); - let [rs1, rs2] = self.adapter.read(state.memory, instruction).into(); + let [rs1, rs2] = self.adapter.read(state, instruction).into(); let (rd, _) = run_mul::(&rs1, &rs2); - self.adapter.write(state.memory, instruction, &[rd].into()); + self.adapter.write(state, instruction, &[rd].into()); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // returns mul, carry diff --git a/extensions/rv32im/circuit/src/mulh/core.rs b/extensions/rv32im/circuit/src/mulh/core.rs index 1a202cb306..361a912b02 100644 --- a/extensions/rv32im/circuit/src/mulh/core.rs +++ b/extensions/rv32im/circuit/src/mulh/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, MinimalInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -326,26 +327,41 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, .. } = instruction; let mulh_opcode = MulHOpcode::from_usize(opcode.local_opcode_idx(MulHOpcode::CLASS_OFFSET)); - let [rs1, rs2] = self.adapter.read(state.memory, instruction).into(); + let [rs1, rs2] = self.adapter.read(state, instruction).into(); let rs1 = rs1.map(u32::from); let rs2 = rs2.map(u32::from); let (rd, _, _, _, _) = run_mulh::(mulh_opcode, &rs1, &rs2); let rd = rd.map(|x| x as u8); - self.adapter.write(state.memory, instruction, &[rd].into()); + self.adapter.write(state, instruction, &[rd].into()); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // returns mulh[[s]u], mul, carry, x_ext, y_ext diff --git a/extensions/rv32im/circuit/src/shift/core.rs b/extensions/rv32im/circuit/src/shift/core.rs index 872917852c..e8f903bd92 100644 --- a/extensions/rv32im/circuit/src/shift/core.rs +++ b/extensions/rv32im/circuit/src/shift/core.rs @@ -5,6 +5,7 @@ use std::{ use openvm_circuit::{ arch::{ + execution_mode::{metered::MeteredCtx, E1E2ExecutionCtx}, AdapterAirContext, AdapterExecutorE1, AdapterTraceStep, MinimalInstruction, Result, StepExecutorE1, TraceStep, VmAdapterInterface, VmCoreAir, VmStateMut, }, @@ -399,23 +400,38 @@ where { fn execute_e1( &mut self, - state: VmStateMut, + state: &mut VmStateMut, instruction: &Instruction, - ) -> Result<()> { + ) -> Result<()> + where + Ctx: E1E2ExecutionCtx, + { let Instruction { opcode, .. } = instruction; let shift_opcode = ShiftOpcode::from_usize(opcode.local_opcode_idx(self.offset)); - let [rs1, rs2] = self.adapter.read(state.memory, instruction).into(); + let [rs1, rs2] = self.adapter.read(state, instruction).into(); let (rd, _, _) = run_shift::(shift_opcode, &rs1, &rs2); - self.adapter.write(state.memory, instruction, &[rd].into()); + self.adapter.write(state, instruction, &[rd].into()); *state.pc = state.pc.wrapping_add(DEFAULT_PC_STEP); Ok(()) } + + fn execute_metered( + &mut self, + state: &mut VmStateMut, + instruction: &Instruction, + chip_index: usize, + ) -> Result<()> { + state.ctx.trace_heights[chip_index] += 1; + self.execute_e1(state, instruction)?; + + Ok(()) + } } // Returns (result, limb_shift, bit_shift)