From 9f864a29f022f17519dc8b878b0b8ef311eeffd0 Mon Sep 17 00:00:00 2001 From: Tamir Hemo Date: Tue, 5 Dec 2023 13:56:29 -0800 Subject: [PATCH 1/4] initial rought --- .gitignore | 9 ++ Cargo.lock | 217 +++++++++++++++++++++++++++++++ Cargo.toml | 14 ++ LICENSE-APACHE.md | 201 ++++++++++++++++++++++++++++ LICENSE-MIT.md | 21 +++ assembly/Cargo.toml | 8 ++ assembly/src/lib.rs | 14 ++ core/Cargo.toml | 11 ++ core/src/air/mod.rs | 1 + core/src/alu/mod.rs | 1 + core/src/cpu/air.rs | 8 ++ core/src/cpu/mod.rs | 15 +++ core/src/cpu/witness.rs | 1 + core/src/lib.rs | 8 ++ core/src/program/mod.rs | 0 core/src/runtime/instance/mod.rs | 15 +++ core/src/runtime/mod.rs | 1 + core/src/runtime/store.rs | 1 + core/src/segment/mod.rs | 6 + 19 files changed, 552 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE-APACHE.md create mode 100644 LICENSE-MIT.md create mode 100644 assembly/Cargo.toml create mode 100644 assembly/src/lib.rs create mode 100644 core/Cargo.toml create mode 100644 core/src/air/mod.rs create mode 100644 core/src/alu/mod.rs create mode 100644 core/src/cpu/air.rs create mode 100644 core/src/cpu/mod.rs create mode 100644 core/src/cpu/witness.rs create mode 100644 core/src/lib.rs create mode 100644 core/src/program/mod.rs create mode 100644 core/src/runtime/instance/mod.rs create mode 100644 core/src/runtime/mod.rs create mode 100644 core/src/runtime/store.rs create mode 100644 core/src/segment/mod.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..70cea0001d --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Cargo build +/target + +# Profile-guided optimization +/tmp +pgo-data.profdata + +# MacOS nuisances +.DS_Store diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..bdaac134f1 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,217 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "assembly" +version = "0.1.0" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core" +version = "0.1.0" +dependencies = [ + "anyhow", + "p3-air", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "p3-air" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3#b21d54f13fd7949a2661c9478b91c01bc3abccbe" +dependencies = [ + "p3-field", + "p3-matrix", +] + +[[package]] +name = "p3-field" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3#b21d54f13fd7949a2661c9478b91c01bc3abccbe" +dependencies = [ + "itertools", + "p3-util", + "rand", +] + +[[package]] +name = "p3-matrix" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3#b21d54f13fd7949a2661c9478b91c01bc3abccbe" +dependencies = [ + "p3-field", + "p3-maybe-rayon", + "rand", +] + +[[package]] +name = "p3-maybe-rayon" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3#b21d54f13fd7949a2661c9478b91c01bc3abccbe" +dependencies = [ + "rayon", +] + +[[package]] +name = "p3-util" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3#b21d54f13fd7949a2661c9478b91c01bc3abccbe" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..41d10894bf --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +members = ["core", "assembly"] +resolver = "2" + +[profile.release] +opt-level = 3 + +[profile.bench] +opt-level = 3 + + +[workspace.dependencies] +p3-air = { git = "https://github.com/Plonky3/Plonky3" } +p3-commit = { git = "https://github.com/Plonky3/Plonky3" } diff --git a/LICENSE-APACHE.md b/LICENSE-APACHE.md new file mode 100644 index 0000000000..da2551fa53 --- /dev/null +++ b/LICENSE-APACHE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2023 Succinct Labs + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT.md b/LICENSE-MIT.md new file mode 100644 index 0000000000..50ab5408bc --- /dev/null +++ b/LICENSE-MIT.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 Succinct Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/assembly/Cargo.toml b/assembly/Cargo.toml new file mode 100644 index 0000000000..9494169bc8 --- /dev/null +++ b/assembly/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "assembly" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/assembly/src/lib.rs b/assembly/src/lib.rs new file mode 100644 index 0000000000..7d12d9af81 --- /dev/null +++ b/assembly/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/core/Cargo.toml b/core/Cargo.toml new file mode 100644 index 0000000000..7e221f5992 --- /dev/null +++ b/core/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "core" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + + +[dependencies] +anyhow = "1.0.75" +p3-air = { workspace = true } diff --git a/core/src/air/mod.rs b/core/src/air/mod.rs new file mode 100644 index 0000000000..56a37c4706 --- /dev/null +++ b/core/src/air/mod.rs @@ -0,0 +1 @@ +pub use p3_air::*; diff --git a/core/src/alu/mod.rs b/core/src/alu/mod.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/core/src/alu/mod.rs @@ -0,0 +1 @@ + diff --git a/core/src/cpu/air.rs b/core/src/cpu/air.rs new file mode 100644 index 0000000000..85d8dcbed0 --- /dev/null +++ b/core/src/cpu/air.rs @@ -0,0 +1,8 @@ +use crate::Word; + +pub struct CPUTable { + pub pc: F, + pub fp: F, + pub opcode: F, + pub operands: [Word; 3], +} diff --git a/core/src/cpu/mod.rs b/core/src/cpu/mod.rs new file mode 100644 index 0000000000..7f311dcdd3 --- /dev/null +++ b/core/src/cpu/mod.rs @@ -0,0 +1,15 @@ +pub mod air; +pub mod witness; + +/// The `Word` type of our architecture. +pub struct Word(u32); +pub struct Pointer(u32); +pub struct Opcode(u8); + +pub struct CPU { + pub pc: Pointer, + pub fp: Pointer, + pub opcode: Opcode, + pub operands: [Word; 3], + pub immediate: Word, +} diff --git a/core/src/cpu/witness.rs b/core/src/cpu/witness.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/core/src/cpu/witness.rs @@ -0,0 +1 @@ + diff --git a/core/src/lib.rs b/core/src/lib.rs new file mode 100644 index 0000000000..ceb7e1908f --- /dev/null +++ b/core/src/lib.rs @@ -0,0 +1,8 @@ +pub mod air; +pub mod alu; +pub mod cpu; +pub mod program; +pub mod runtime; +pub mod segment; + +pub struct Word([F; 4]); diff --git a/core/src/program/mod.rs b/core/src/program/mod.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/src/runtime/instance/mod.rs b/core/src/runtime/instance/mod.rs new file mode 100644 index 0000000000..09c9b14d8b --- /dev/null +++ b/core/src/runtime/instance/mod.rs @@ -0,0 +1,15 @@ +use anyhow::Result; + +use crate::segment::Segment; + +/// A runtime instance. +/// +/// A runtime instance is a collection of modules that have been instantiated together with a +/// shared store and a shared table. +pub trait Instance { + type Store; + + type Segments: IntoIterator; + + fn run(&self, store: &mut Self::Store) -> Result; +} diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs new file mode 100644 index 0000000000..67020667c7 --- /dev/null +++ b/core/src/runtime/mod.rs @@ -0,0 +1 @@ +mod instance; diff --git a/core/src/runtime/store.rs b/core/src/runtime/store.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/core/src/runtime/store.rs @@ -0,0 +1 @@ + diff --git a/core/src/segment/mod.rs b/core/src/segment/mod.rs new file mode 100644 index 0000000000..52e58951da --- /dev/null +++ b/core/src/segment/mod.rs @@ -0,0 +1,6 @@ +/// An execution trace to be proved in a single ZK proof. +/// +/// A segment consists of a program, initial values for memory, and the execution trace +/// of the program which is run to a specific number of cycles. Segmemts contain data that allows +/// them to be connected to other segments, and to be verified in a batch. +pub struct Segment; From e7ad5cf99eed54b000b81133933a1f2f7da26ccc Mon Sep 17 00:00:00 2001 From: Tamir Hemo Date: Tue, 5 Dec 2023 16:18:12 -0800 Subject: [PATCH 2/4] wip --- Cargo.lock | 24 +++++--- Cargo.toml | 5 +- core/Cargo.toml | 6 +- core/src/alu/mod.rs | 21 +++++++ core/src/cpu/mod.rs | 19 +++--- core/src/program/basic.rs | 17 ++++++ core/src/program/mod.rs | 22 +++++++ core/src/runtime/instance/mod.rs | 20 +++++-- core/src/runtime/instance/simple.rs | 90 +++++++++++++++++++++++++++++ core/src/runtime/mod.rs | 1 + core/src/runtime/store.rs | 1 - core/src/runtime/store/function.rs | 20 +++++++ core/src/runtime/store/mod.rs | 5 ++ core/src/segment/mod.rs | 4 +- valida/Cargo.toml | 9 +++ valida/src/lib.rs | 18 ++++++ 16 files changed, 254 insertions(+), 28 deletions(-) create mode 100644 core/src/program/basic.rs create mode 100644 core/src/runtime/instance/simple.rs delete mode 100644 core/src/runtime/store.rs create mode 100644 core/src/runtime/store/function.rs create mode 100644 core/src/runtime/store/mod.rs create mode 100644 valida/Cargo.toml create mode 100644 valida/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index bdaac134f1..ac55a6813e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,14 +24,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "core" -version = "0.1.0" -dependencies = [ - "anyhow", - "p3-air", -] - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -65,6 +57,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "curta-core" +version = "0.1.0" +dependencies = [ + "anyhow", + "p3-air", + "valida-isa", +] + [[package]] name = "either" version = "1.9.0" @@ -210,6 +211,13 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "valida-isa" +version = "0.1.0" +dependencies = [ + "curta-core", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 41d10894bf..6551cbacf0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["core", "assembly"] +members = ["core", "assembly", "valida"] resolver = "2" [profile.release] @@ -12,3 +12,6 @@ opt-level = 3 [workspace.dependencies] p3-air = { git = "https://github.com/Plonky3/Plonky3" } p3-commit = { git = "https://github.com/Plonky3/Plonky3" } + +curta-core = { path = "core" } +valida-isa = { path = "valida" } diff --git a/core/Cargo.toml b/core/Cargo.toml index 7e221f5992..ba2bb8ef89 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,11 +1,13 @@ [package] -name = "core" +name = "curta-core" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] anyhow = "1.0.75" p3-air = { workspace = true } + +[dev-dependencies] +valida-isa = { workspace = true } diff --git a/core/src/alu/mod.rs b/core/src/alu/mod.rs index 8b13789179..67da212208 100644 --- a/core/src/alu/mod.rs +++ b/core/src/alu/mod.rs @@ -1 +1,22 @@ +use crate::program::ISA; +pub enum ALUOperation { + Add, + Sub, + Mul, + Div, + Mod, + And, + Or, + Xor, + Not, + Shl, + Shr, + Leq, +} + +pub struct ALU { + op: ALUOperation, + operands: [IS::Word; 3], + values: [IS::Word; 3], +} diff --git a/core/src/cpu/mod.rs b/core/src/cpu/mod.rs index 7f311dcdd3..190ca5cdd5 100644 --- a/core/src/cpu/mod.rs +++ b/core/src/cpu/mod.rs @@ -1,15 +1,14 @@ +use crate::program::ISA; + pub mod air; pub mod witness; -/// The `Word` type of our architecture. -pub struct Word(u32); -pub struct Pointer(u32); -pub struct Opcode(u8); +/// The `Opcode` type of our architecture. -pub struct CPU { - pub pc: Pointer, - pub fp: Pointer, - pub opcode: Opcode, - pub operands: [Word; 3], - pub immediate: Word, +pub struct Cpu { + pub pc: IS::Word, + pub fp: IS::Word, + pub opcode: IS::Opcode, + pub operands: [IS::Word; 3], + pub immediate: IS::ImmValue, } diff --git a/core/src/program/basic.rs b/core/src/program/basic.rs new file mode 100644 index 0000000000..0b182ed48a --- /dev/null +++ b/core/src/program/basic.rs @@ -0,0 +1,17 @@ +use super::ISA; + +pub struct Basic32; + +pub enum BasicInstruction { + LW(W, W), + SW(W, W), + Const(W, W), + Add(W, W, W), +} + +impl ISA for Basic32 { + type Opcode = u8; + type Word = u32; + type Instruction = BasicInstruction; + type ImmValue = u32; +} diff --git a/core/src/program/mod.rs b/core/src/program/mod.rs index e69de29bb2..a1727e2b7e 100644 --- a/core/src/program/mod.rs +++ b/core/src/program/mod.rs @@ -0,0 +1,22 @@ +pub mod basic; + +/// An instruction set architecture. +/// +/// This trait defines the basic types needed to encode an instruction. +pub trait ISA { + /// The opcode type of our architecture. + /// + /// Opcodes are used to encode instructions. + type Opcode; + + /// The word type of our architecture. + /// + /// Words are used to encode addresses and data in memory. + type Word: Copy + Default; + + type Instruction; + /// The immediate value type of our architecture. + /// + /// Immediate values are used to encode constants in instructions. + type ImmValue; +} diff --git a/core/src/runtime/instance/mod.rs b/core/src/runtime/instance/mod.rs index 09c9b14d8b..ff283c5c80 100644 --- a/core/src/runtime/instance/mod.rs +++ b/core/src/runtime/instance/mod.rs @@ -1,15 +1,25 @@ use anyhow::Result; -use crate::segment::Segment; +use crate::{program::ISA, segment::Segment}; + +pub mod simple; /// A runtime instance. /// /// A runtime instance is a collection of modules that have been instantiated together with a /// shared store and a shared table. -pub trait Instance { - type Store; +pub trait Instance { + type Segment: Segment; + type Segments: IntoIterator; + + fn max_segment_len(&self) -> usize; - type Segments: IntoIterator; + fn execute( + &self, + instruction: &IS::Instruction, + store: &mut S, + segment: &mut Self::Segment, + ) -> Result<()>; - fn run(&self, store: &mut Self::Store) -> Result; + fn run(&self, store: &mut S) -> Result; } diff --git a/core/src/runtime/instance/simple.rs b/core/src/runtime/instance/simple.rs new file mode 100644 index 0000000000..87b5ac9b93 --- /dev/null +++ b/core/src/runtime/instance/simple.rs @@ -0,0 +1,90 @@ +use crate::{ + alu::ALU, + cpu::Cpu, + program::{ + basic::{Basic32, BasicInstruction}, + ISA, + }, + runtime::store::FunctionStore, + segment::Segment, +}; + +use anyhow::Result; + +use super::Instance; + +pub struct CoreInstance { + pub program: Vec, + pub max_segment_len: usize, + pub fp: IS::Word, + pub pc: IS::Word, +} + +pub struct CoreSegment { + cpu_trace: Vec>, + alu_trace: Vec>, +} + +impl CoreSegment { + pub fn new() -> Self { + Self { + cpu_trace: vec![], + alu_trace: vec![], + } + } +} + +impl Segment for CoreSegment { + fn init() -> Self { + Self::new() + } +} + +impl CoreInstance { + pub fn new(program: Vec, max_segment_len: usize) -> Self { + Self { + program, + max_segment_len, + pc: IS::Word::default(), + fp: IS::Word::default(), + } + } + + fn execute( + instruction: &IS::Instruction, + store: &mut FunctionStore, + segment: &mut CoreSegment, + ) { + } +} + +impl Instance, Basic32> for CoreInstance { + type Segment = CoreSegment; + type Segments = Vec; + + fn max_segment_len(&self) -> usize { + self.max_segment_len + } + + fn execute( + &self, + Instruction: &BasicInstruction, + store: &mut FunctionStore, + segment: &mut Self::Segment, + ) -> Result<()> { + Ok(()) + } + + fn run(&self, store: &mut FunctionStore) -> Result { + let mut segments = vec![]; + + loop { + let mut segment = Self::Segment::init(); + let mut instruction_counter = 0; + + while instruction_counter < self.max_segment_len {} + segments.push(segment); + } + Ok(vec![]) + } +} diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs index 67020667c7..f6f6e16f61 100644 --- a/core/src/runtime/mod.rs +++ b/core/src/runtime/mod.rs @@ -1 +1,2 @@ mod instance; +mod store; diff --git a/core/src/runtime/store.rs b/core/src/runtime/store.rs deleted file mode 100644 index 8b13789179..0000000000 --- a/core/src/runtime/store.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/core/src/runtime/store/function.rs b/core/src/runtime/store/function.rs new file mode 100644 index 0000000000..65dc251328 --- /dev/null +++ b/core/src/runtime/store/function.rs @@ -0,0 +1,20 @@ +use super::Store; + +/// A simple store representing a function with no internal state and no co-processors. +pub struct FunctionStore { + pub memory: Vec, + pub inputs: Vec, + pub outputs: Vec, +} + +impl Store for FunctionStore {} + +impl FunctionStore { + pub fn new(inputs: Vec) -> Self { + Self { + memory: vec![], + inputs, + outputs: vec![], + } + } +} diff --git a/core/src/runtime/store/mod.rs b/core/src/runtime/store/mod.rs new file mode 100644 index 0000000000..d2a97f394c --- /dev/null +++ b/core/src/runtime/store/mod.rs @@ -0,0 +1,5 @@ +mod function; + +pub use function::FunctionStore; + +pub trait Store {} diff --git a/core/src/segment/mod.rs b/core/src/segment/mod.rs index 52e58951da..eb09b1bcc3 100644 --- a/core/src/segment/mod.rs +++ b/core/src/segment/mod.rs @@ -3,4 +3,6 @@ /// A segment consists of a program, initial values for memory, and the execution trace /// of the program which is run to a specific number of cycles. Segmemts contain data that allows /// them to be connected to other segments, and to be verified in a batch. -pub struct Segment; +pub trait Segment { + fn init() -> Self; +} diff --git a/valida/Cargo.toml b/valida/Cargo.toml new file mode 100644 index 0000000000..c87041d0fa --- /dev/null +++ b/valida/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "valida-isa" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +curta-core = { workspace = true } diff --git a/valida/src/lib.rs b/valida/src/lib.rs new file mode 100644 index 0000000000..7eda931fd4 --- /dev/null +++ b/valida/src/lib.rs @@ -0,0 +1,18 @@ +use curta_core::program::ISA; + +pub struct ValidaISA; + +impl ISA for ValidaISA { + type Opcode = u8; + type Word = u32; + type Instruction = Instruction; + type ImmValue = u32; +} + +pub enum Instruction { + Add(u32, u32, u32), + Addi(u32, u32, u32), + Const(u32, u32), + LW(u32, u32), + SW(u32, u32), +} From 70ff875376614cdb46481d19707d1e52ca669f9b Mon Sep 17 00:00:00 2001 From: Tamir Hemo Date: Wed, 6 Dec 2023 13:37:55 -0800 Subject: [PATCH 3/4] runtime v.0.0.1 --- core/Cargo.toml | 2 + core/src/alu/mod.rs | 16 ++-- core/src/cpu/air.rs | 6 +- core/src/cpu/mod.rs | 31 +++++-- core/src/lib.rs | 4 +- core/src/program/base.rs | 83 +++++++++++++++++ core/src/program/basic.rs | 17 ---- core/src/program/mod.rs | 23 ++--- core/src/runtime/base.rs | 138 ++++++++++++++++++++++++++++ core/src/runtime/instance/mod.rs | 25 ----- core/src/runtime/instance/simple.rs | 90 ------------------ core/src/runtime/mod.rs | 51 +++++++++- core/src/runtime/store/event.rs | 26 ++++++ core/src/runtime/store/function.rs | 39 ++++++-- core/src/runtime/store/mod.rs | 22 ++++- core/src/runtime/writer.rs | 13 +++ core/src/segment/mod.rs | 8 -- 17 files changed, 411 insertions(+), 183 deletions(-) create mode 100644 core/src/program/base.rs delete mode 100644 core/src/program/basic.rs create mode 100644 core/src/runtime/base.rs delete mode 100644 core/src/runtime/instance/mod.rs delete mode 100644 core/src/runtime/instance/simple.rs create mode 100644 core/src/runtime/store/event.rs create mode 100644 core/src/runtime/writer.rs delete mode 100644 core/src/segment/mod.rs diff --git a/core/Cargo.toml b/core/Cargo.toml index ba2bb8ef89..a834d1468c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [dependencies] anyhow = "1.0.75" +bincode = "1.3.3" +serde = { version = "1.0", features = ["derive"] } p3-air = { workspace = true } [dev-dependencies] diff --git a/core/src/alu/mod.rs b/core/src/alu/mod.rs index 67da212208..133725df2e 100644 --- a/core/src/alu/mod.rs +++ b/core/src/alu/mod.rs @@ -1,6 +1,7 @@ -use crate::program::ISA; +use serde::{Deserialize, Serialize}; -pub enum ALUOperation { +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum AluOperation { Add, Sub, Mul, @@ -15,8 +16,11 @@ pub enum ALUOperation { Leq, } -pub struct ALU { - op: ALUOperation, - operands: [IS::Word; 3], - values: [IS::Word; 3], +/// The state of the Alu at a particular point in the program execution. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Alu { + pub op: AluOperation, + pub v_a: u32, + pub v_b: u32, + pub v_c: u32, } diff --git a/core/src/cpu/air.rs b/core/src/cpu/air.rs index 85d8dcbed0..b2a5a27333 100644 --- a/core/src/cpu/air.rs +++ b/core/src/cpu/air.rs @@ -1,8 +1,12 @@ use crate::Word; +/// The AIR table for the CPU. pub struct CPUTable { pub pc: F, pub fp: F, pub opcode: F, - pub operands: [Word; 3], + pub op_a: Word, + pub op_b: Word, + pub op_c: Word, + pub imm: Word, } diff --git a/core/src/cpu/mod.rs b/core/src/cpu/mod.rs index 190ca5cdd5..1736017c32 100644 --- a/core/src/cpu/mod.rs +++ b/core/src/cpu/mod.rs @@ -1,14 +1,27 @@ -use crate::program::ISA; +use serde::{Deserialize, Serialize}; pub mod air; pub mod witness; -/// The `Opcode` type of our architecture. - -pub struct Cpu { - pub pc: IS::Word, - pub fp: IS::Word, - pub opcode: IS::Opcode, - pub operands: [IS::Word; 3], - pub immediate: IS::ImmValue, +/// The state of the CPU at a particular point in the program execution. +/// +/// The CPU state is a snapshot of the CPU at a particular point in the program execution. It is +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Cpu { + /// The program timestamp. + pub clk: u32, + /// The program counter. + pub pc: u32, + /// The frame pointer. + pub fp: u32, + // The opcode of the current instruction. + pub opcode: u8, + /// The first argument of the current instruction. + pub arg1: u32, + /// The second argument of the current instruction. + pub arg2: u32, + /// The third argument of the current instruction. + pub arg3: u32, + /// The immediate vAlue of the current instruction (if any). + pub imm: u32, } diff --git a/core/src/lib.rs b/core/src/lib.rs index ceb7e1908f..dd6ad9e01b 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -3,6 +3,6 @@ pub mod alu; pub mod cpu; pub mod program; pub mod runtime; -pub mod segment; -pub struct Word([F; 4]); +pub const WORD_SIZE: usize = 4; +pub struct Word([F; WORD_SIZE]); diff --git a/core/src/program/base.rs b/core/src/program/base.rs new file mode 100644 index 0000000000..df6cc4f1da --- /dev/null +++ b/core/src/program/base.rs @@ -0,0 +1,83 @@ +use super::ISA; + +/// The base instruction set architecture. +#[derive(Clone, Debug, Copy)] +pub struct BaseISA; + +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)] +pub enum BaseInstruction { + /// StoreWord(a, b). + /// + /// Loads the word at address fp-b into address fp-a. + SW(u32, u32), + /// ConstantWord(a, b). + /// + /// Stores the constant word into address fp-a. + CW(u32, u32), + /// Add(a, b, c) + /// + /// Adds the values at address fp-b and fp-c and stores the result in fp-a. + ADD(u32, u32, u32), + /// SUB(a, b, c) + /// + /// Subtracts the values at address fp-b and fp-c and stores the result in fp-a. + SUB(u32, u32, u32), + /// AND(a, b, c) + /// + /// Bitwise ANDs the values at address fp-b and fp-c and stores the result in fp-a. + AND(u32, u32, u32), + /// OR(a, b, c) + /// + /// Bitwise ORs the values at address fp-b and fp-c and stores the result in fp-a. + OR(u32, u32, u32), + /// XOR(a, b, c) + /// + /// Bitwise XORs the values at address fp-b and fp-c and stores the result in fp-a. + XOR(u32, u32, u32), + /// ADDI(a, b, d) + /// + /// Adds the value at address fp-b and the constant d and stores the result in fp-a. + ADDI(u32, u32, u32), + /// SUBI(a, b, d) + /// + /// Subtracts the value at address fp-b and the constant d and stores the result in fp-a. + SUBI(u32, u32, u32), + /// ANDI(a, b, d) + /// + /// Bitwise ANDs the value at address fp-b and the constant d and stores the result in fp-a. + ANDI(u32, u32, u32), + /// ORI(a, b, d) + /// + /// Bitwise ORs the value at address fp-b and the constant d and stores the result in fp-a. + ORI(u32, u32, u32), + /// XORI(a, b, d) + /// + /// Bitwise XORs the value at address fp-b and the constant d and stores the result in fp-a. + XORI(u32, u32, u32), + /// ECALL(a, b, c, d) + /// + /// Make an external call to the supporting execution environment. + ECALL(u32, u32, u32, u32), +} + +impl ISA for BaseISA { + type Instruction = BaseInstruction; + + fn decode(instruction: &Self::Instruction) -> (u8, u32, u32, u32, u32) { + match instruction { + BaseInstruction::SW(a, b) => (0, *a, *b, 0, 0), + BaseInstruction::CW(a, b) => (1, *a, *b, 0, 0), + BaseInstruction::ADD(a, b, c) => (2, *a, *b, *c, 0), + BaseInstruction::SUB(a, b, c) => (3, *a, *b, *c, 0), + BaseInstruction::AND(a, b, c) => (4, *a, *b, *c, 0), + BaseInstruction::OR(a, b, c) => (5, *a, *b, *c, 0), + BaseInstruction::XOR(a, b, c) => (6, *a, *b, *c, 0), + BaseInstruction::ADDI(a, b, d) => (7, *a, *b, 0, *d), + BaseInstruction::SUBI(a, b, d) => (8, *a, *b, 0, *d), + BaseInstruction::ANDI(a, b, d) => (9, *a, *b, 0, *d), + BaseInstruction::ORI(a, b, d) => (10, *a, *b, 0, *d), + BaseInstruction::XORI(a, b, d) => (11, *a, *b, 0, *d), + BaseInstruction::ECALL(a, b, c, d) => (12, *a, *b, *c, *d), + } + } +} diff --git a/core/src/program/basic.rs b/core/src/program/basic.rs deleted file mode 100644 index 0b182ed48a..0000000000 --- a/core/src/program/basic.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::ISA; - -pub struct Basic32; - -pub enum BasicInstruction { - LW(W, W), - SW(W, W), - Const(W, W), - Add(W, W, W), -} - -impl ISA for Basic32 { - type Opcode = u8; - type Word = u32; - type Instruction = BasicInstruction; - type ImmValue = u32; -} diff --git a/core/src/program/mod.rs b/core/src/program/mod.rs index a1727e2b7e..233493c53e 100644 --- a/core/src/program/mod.rs +++ b/core/src/program/mod.rs @@ -1,22 +1,15 @@ -pub mod basic; +pub mod base; -/// An instruction set architecture. +/// An instruction set architecture with 32-bit addresses. /// /// This trait defines the basic types needed to encode an instruction. pub trait ISA { - /// The opcode type of our architecture. - /// - /// Opcodes are used to encode instructions. - type Opcode; - - /// The word type of our architecture. - /// - /// Words are used to encode addresses and data in memory. - type Word: Copy + Default; - + /// The instruction type of our architecture. type Instruction; - /// The immediate value type of our architecture. + + /// Decode an instruction to its opcode and arguments. /// - /// Immediate values are used to encode constants in instructions. - type ImmValue; + /// The instruction is deconded as `(opcode, op_a, op_b, op_c, imm)`. This enforces a standard + /// format for instructions that can be used by the runtime. + fn decode(instruction: &Self::Instruction) -> (u8, u32, u32, u32, u32); } diff --git a/core/src/runtime/base.rs b/core/src/runtime/base.rs new file mode 100644 index 0000000000..e015185850 --- /dev/null +++ b/core/src/runtime/base.rs @@ -0,0 +1,138 @@ +use super::Runtime; +use crate::alu::{Alu, AluOperation}; +use crate::runtime::store::Event; +use crate::{ + cpu::Cpu, + program::{ + base::{BaseISA, BaseInstruction}, + ISA, + }, + runtime::store::Store, +}; +use anyhow::Result; + +#[derive(Debug, Clone)] +pub struct BaseRuntime { + program: Vec, +} + +impl Runtime for BaseRuntime { + fn get_next_instruction(&self, store: &mut S) -> Option<::Instruction> { + let pc = *store.pc() as usize; + self.program.get(pc).copied() + } + + fn execute( + &self, + instruction: &::Instruction, + store: &mut S, + ) -> Result<::Event> { + let event = match instruction { + BaseInstruction::SW(a, b) => { + // Load the value from address fp-b into address fp-a. + let fp = *store.fp(); + let addr_b = fp as usize + *b as usize; + let b_bytes: [_; 4] = store.memory()[addr_b..addr_b + 4].try_into().unwrap(); + let addr_a = fp as usize + *a as usize; + store.memory()[addr_a..addr_a + 4].copy_from_slice(&b_bytes); + + // Update the store state. + *store.pc() += 1; + *store.clk() += 1; + + // Record the event. + let (opcode, arg1, arg2, arg3, imm) = BaseISA::decode(instruction); + let cpu = Cpu { + clk: *store.clk(), + pc: *store.pc(), + fp: *store.fp(), + opcode, + arg1, + arg2, + arg3, + imm, + }; + S::Event::core(cpu) + } + BaseInstruction::CW(a, b) => { + // Store the constant word into address fp-a. + let fp = *store.fp(); + let addr_a = fp as usize + *a as usize; + store.memory()[addr_a..addr_a + 4].copy_from_slice(&b.to_le_bytes()); + + // Update the store state. + *store.pc() += 1; + *store.clk() += 1; + + // Record the event. + let (opcode, arg1, arg2, arg3, imm) = BaseISA::decode(instruction); + let cpu = Cpu { + clk: *store.clk(), + pc: *store.pc(), + fp: *store.fp(), + opcode, + arg1, + arg2, + arg3, + imm, + }; + S::Event::core(cpu) + } + BaseInstruction::XOR(a, b, c) => { + // Bitwise XORs the values at address fp-b and fp-c and stores the result in fp-a. + let fp = *store.fp(); + let addr_b = fp as usize + *b as usize; + let addr_c = fp as usize + *c as usize; + let v_b = + u32::from_le_bytes(store.memory()[addr_b..addr_b + 4].try_into().unwrap()); + let v_c = + u32::from_le_bytes(store.memory()[addr_c..addr_c + 4].try_into().unwrap()); + let v_a = v_b ^ v_c; + let addr_a = fp as usize + *a as usize; + store.memory()[addr_a..addr_a + 4].copy_from_slice(&v_a.to_le_bytes()); + + // Update the store state. + *store.pc() += 1; + *store.clk() += 1; + + // Record the event. + let (opcode, arg1, arg2, arg3, imm) = BaseISA::decode(instruction); + let cpu = Cpu { + clk: *store.clk(), + pc: *store.pc(), + fp: *store.fp(), + opcode, + arg1, + arg2, + arg3, + imm, + }; + let alu = Alu { + op: AluOperation::Xor, + v_a, + v_b, + v_c, + }; + S::Event::alu(cpu, alu) + } + _ => unimplemented!("Instrcution not implemented"), + }; + Ok(event) + } +} + +#[cfg(test)] +mod tests { + use crate::program::base::BaseInstruction; + + #[test] + fn test_basic_rt() { + let program = vec![ + BaseInstruction::CW(0, 0), + BaseInstruction::CW(1, 1), + BaseInstruction::CW(2, 2), + BaseInstruction::XOR(3, 1, 2), + BaseInstruction::SW(0, 3), + ]; + } +} diff --git a/core/src/runtime/instance/mod.rs b/core/src/runtime/instance/mod.rs deleted file mode 100644 index ff283c5c80..0000000000 --- a/core/src/runtime/instance/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -use anyhow::Result; - -use crate::{program::ISA, segment::Segment}; - -pub mod simple; - -/// A runtime instance. -/// -/// A runtime instance is a collection of modules that have been instantiated together with a -/// shared store and a shared table. -pub trait Instance { - type Segment: Segment; - type Segments: IntoIterator; - - fn max_segment_len(&self) -> usize; - - fn execute( - &self, - instruction: &IS::Instruction, - store: &mut S, - segment: &mut Self::Segment, - ) -> Result<()>; - - fn run(&self, store: &mut S) -> Result; -} diff --git a/core/src/runtime/instance/simple.rs b/core/src/runtime/instance/simple.rs deleted file mode 100644 index 87b5ac9b93..0000000000 --- a/core/src/runtime/instance/simple.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::{ - alu::ALU, - cpu::Cpu, - program::{ - basic::{Basic32, BasicInstruction}, - ISA, - }, - runtime::store::FunctionStore, - segment::Segment, -}; - -use anyhow::Result; - -use super::Instance; - -pub struct CoreInstance { - pub program: Vec, - pub max_segment_len: usize, - pub fp: IS::Word, - pub pc: IS::Word, -} - -pub struct CoreSegment { - cpu_trace: Vec>, - alu_trace: Vec>, -} - -impl CoreSegment { - pub fn new() -> Self { - Self { - cpu_trace: vec![], - alu_trace: vec![], - } - } -} - -impl Segment for CoreSegment { - fn init() -> Self { - Self::new() - } -} - -impl CoreInstance { - pub fn new(program: Vec, max_segment_len: usize) -> Self { - Self { - program, - max_segment_len, - pc: IS::Word::default(), - fp: IS::Word::default(), - } - } - - fn execute( - instruction: &IS::Instruction, - store: &mut FunctionStore, - segment: &mut CoreSegment, - ) { - } -} - -impl Instance, Basic32> for CoreInstance { - type Segment = CoreSegment; - type Segments = Vec; - - fn max_segment_len(&self) -> usize { - self.max_segment_len - } - - fn execute( - &self, - Instruction: &BasicInstruction, - store: &mut FunctionStore, - segment: &mut Self::Segment, - ) -> Result<()> { - Ok(()) - } - - fn run(&self, store: &mut FunctionStore) -> Result { - let mut segments = vec![]; - - loop { - let mut segment = Self::Segment::init(); - let mut instruction_counter = 0; - - while instruction_counter < self.max_segment_len {} - segments.push(segment); - } - Ok(vec![]) - } -} diff --git a/core/src/runtime/mod.rs b/core/src/runtime/mod.rs index f6f6e16f61..c823525539 100644 --- a/core/src/runtime/mod.rs +++ b/core/src/runtime/mod.rs @@ -1,2 +1,51 @@ -mod instance; +//! Runtime +//! +//! The runtime module is responsible for managing the execution of the program and the production +//! of the program execution trace. As the virtual machine arithmetization is bounded, the runtime +//! runs the program for a particular number of cycles at a time, and then returns the execution +//! trace of each cycle segment. + mod store; +mod writer; + +use anyhow::Result; + +use crate::program::ISA; + +pub use store::FunctionStore; +pub use store::Store; + +use self::writer::PollResult; +use self::writer::TraceWrite; + +pub mod base; + +/// A runtime instance. +/// +/// A runtime instance is a collection of modules that have been instantiated together with a store +/// external host functions, and any other instance necessary to run the program. +pub trait Runtime: Send + Sync { + /// Execute an instruction and return the new state to be recorded. + fn execute(&self, instruction: &IS::Instruction, store: &mut S) -> Result; + + /// Get the next instruction to be executed. + fn get_next_instruction(&self, store: &mut S) -> Option; + + /// Run the instance. + /// + /// The runtime will run the program by executing the instruction in sequence and will stream + /// the execution trace to the writer. The runtime will stop when the program has finished or + /// when the writer returns a `halt` signal. + fn run(&self, store: &mut S, writer: &mut impl TraceWrite) -> Result<()> { + while let Some(instruction) = self.get_next_instruction(store) { + let state = self.execute(&instruction, store).unwrap(); + let bytes = bincode::serialize(&state)?; + writer.write_all(&bytes)?; + match writer.poll()? { + PollResult::Halt => break, + PollResult::Continue => (), + } + } + Ok(()) + } +} diff --git a/core/src/runtime/store/event.rs b/core/src/runtime/store/event.rs new file mode 100644 index 0000000000..743338e4fc --- /dev/null +++ b/core/src/runtime/store/event.rs @@ -0,0 +1,26 @@ +use serde::Serialize; + +use crate::{alu::Alu, cpu::Cpu}; + +/// An event to be recorded in the execution trace. +pub trait Event: Serialize { + fn core(cpu: Cpu) -> Self; + fn alu(cpu: Cpu, alu: Alu) -> Self; +} + +/// A minimal implementation of an event. +#[derive(Clone, Debug, Serialize)] +pub enum BaseEvent { + Core(Cpu), + Alu(Cpu, Alu), +} + +impl Event for BaseEvent { + fn core(cpu: Cpu) -> Self { + Self::Core(cpu) + } + + fn alu(cpu: Cpu, alu: Alu) -> Self { + Self::Alu(cpu, alu) + } +} diff --git a/core/src/runtime/store/function.rs b/core/src/runtime/store/function.rs index 65dc251328..161d5a7129 100644 --- a/core/src/runtime/store/function.rs +++ b/core/src/runtime/store/function.rs @@ -1,17 +1,40 @@ -use super::Store; +use super::{event::BaseEvent, Store}; /// A simple store representing a function with no internal state and no co-processors. -pub struct FunctionStore { - pub memory: Vec, - pub inputs: Vec, - pub outputs: Vec, +pub struct FunctionStore { + pub clk: u32, + pub fp: u32, + pub pc: u32, + pub memory: Vec, + pub inputs: Vec, + pub outputs: Vec, } -impl Store for FunctionStore {} +impl Store for FunctionStore { + type Event = BaseEvent; + fn memory(&mut self) -> &mut [u8] { + &mut self.memory + } + + fn clk(&mut self) -> &mut u32 { + &mut self.clk + } + + fn fp(&mut self) -> &mut u32 { + &mut self.fp + } + + fn pc(&mut self) -> &mut u32 { + &mut self.pc + } +} -impl FunctionStore { - pub fn new(inputs: Vec) -> Self { +impl FunctionStore { + pub fn new(inputs: Vec) -> Self { Self { + clk: 0, + fp: 0, + pc: 0, memory: vec![], inputs, outputs: vec![], diff --git a/core/src/runtime/store/mod.rs b/core/src/runtime/store/mod.rs index d2a97f394c..ba94a8188e 100644 --- a/core/src/runtime/store/mod.rs +++ b/core/src/runtime/store/mod.rs @@ -1,5 +1,25 @@ +mod event; mod function; +pub use event::Event; pub use function::FunctionStore; -pub trait Store {} +/// A store represents all global state that can be accessed by a program. +/// +/// A minimal store must include a memory. A more complete store may also include some other forms +/// of internal state such as inputs, outputs, registers, etc. +pub trait Store { + /// The snapshot of the state that is recorded in the execution trace. + type Event: Event; + /// Get a mutable reference to the memory of the store. + fn memory(&mut self) -> &mut [u8]; + + /// Get a mutable reference to the program counter. + fn pc(&mut self) -> &mut u32; + + /// Get a mutable reference to the frame pointer. + fn fp(&mut self) -> &mut u32; + + /// Get a mutable reference to the clock. + fn clk(&mut self) -> &mut u32; +} diff --git a/core/src/runtime/writer.rs b/core/src/runtime/writer.rs new file mode 100644 index 0000000000..bfb95b1f03 --- /dev/null +++ b/core/src/runtime/writer.rs @@ -0,0 +1,13 @@ +use anyhow::Result; +use std::io::Write; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum PollResult { + Halt, + Continue, +} + +pub trait TraceWrite: Write { + /// Poll the writer to see if we should continue execution. + fn poll(&mut self) -> Result; +} diff --git a/core/src/segment/mod.rs b/core/src/segment/mod.rs deleted file mode 100644 index eb09b1bcc3..0000000000 --- a/core/src/segment/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// An execution trace to be proved in a single ZK proof. -/// -/// A segment consists of a program, initial values for memory, and the execution trace -/// of the program which is run to a specific number of cycles. Segmemts contain data that allows -/// them to be connected to other segments, and to be verified in a batch. -pub trait Segment { - fn init() -> Self; -} From 8104b1038f52741845fd6859c56c063f3d65e6c6 Mon Sep 17 00:00:00 2001 From: Tamir Hemo Date: Wed, 6 Dec 2023 17:31:52 -0800 Subject: [PATCH 4/4] recent --- core/src/program/base.rs | 24 ++++++++++++------------ core/src/runtime/store/base.rs | 27 +++++++++++++++++++++++++++ core/src/runtime/write.rs | 13 +++++++++++++ 3 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 core/src/runtime/store/base.rs create mode 100644 core/src/runtime/write.rs diff --git a/core/src/program/base.rs b/core/src/program/base.rs index df6cc4f1da..35697c8849 100644 --- a/core/src/program/base.rs +++ b/core/src/program/base.rs @@ -8,51 +8,51 @@ pub struct BaseISA; pub enum BaseInstruction { /// StoreWord(a, b). /// - /// Loads the word at address fp-b into address fp-a. + /// Loads the word at address fp+b into address fp+a. SW(u32, u32), /// ConstantWord(a, b). /// - /// Stores the constant word into address fp-a. + /// Stores the constant word into address fp+a. CW(u32, u32), /// Add(a, b, c) /// - /// Adds the values at address fp-b and fp-c and stores the result in fp-a. + /// Adds the values at address fp+b and fp+c and stores the result in fp+a. ADD(u32, u32, u32), /// SUB(a, b, c) /// - /// Subtracts the values at address fp-b and fp-c and stores the result in fp-a. + /// Subtracts the values at address fp+b and fp+c and stores the result in fp+a. SUB(u32, u32, u32), /// AND(a, b, c) /// - /// Bitwise ANDs the values at address fp-b and fp-c and stores the result in fp-a. + /// Bitwise ANDs the values at address fp+b and fp+c and stores the result in fp+a. AND(u32, u32, u32), /// OR(a, b, c) /// - /// Bitwise ORs the values at address fp-b and fp-c and stores the result in fp-a. + /// Bitwise ORs the values at address fp+b and fp+c and stores the result in fp+a. OR(u32, u32, u32), /// XOR(a, b, c) /// - /// Bitwise XORs the values at address fp-b and fp-c and stores the result in fp-a. + /// Bitwise XORs the values at address fp+b and fp+c and stores the result in fp+a. XOR(u32, u32, u32), /// ADDI(a, b, d) /// - /// Adds the value at address fp-b and the constant d and stores the result in fp-a. + /// Adds the value at address fp+b and the constant d and stores the result in fp+a. ADDI(u32, u32, u32), /// SUBI(a, b, d) /// - /// Subtracts the value at address fp-b and the constant d and stores the result in fp-a. + /// Subtracts the value at address fp+b and the constant d and stores the result in fp+a. SUBI(u32, u32, u32), /// ANDI(a, b, d) /// - /// Bitwise ANDs the value at address fp-b and the constant d and stores the result in fp-a. + /// Bitwise ANDs the value at address fp+b and the constant d and stores the result in fp+a. ANDI(u32, u32, u32), /// ORI(a, b, d) /// - /// Bitwise ORs the value at address fp-b and the constant d and stores the result in fp-a. + /// Bitwise ORs the value at address fp+b and the constant d and stores the result in fp+a. ORI(u32, u32, u32), /// XORI(a, b, d) /// - /// Bitwise XORs the value at address fp-b and the constant d and stores the result in fp-a. + /// Bitwise XORs the value at address fp+b and the constant d and stores the result in fp+a. XORI(u32, u32, u32), /// ECALL(a, b, c, d) /// diff --git a/core/src/runtime/store/base.rs b/core/src/runtime/store/base.rs new file mode 100644 index 0000000000..dbbf535a58 --- /dev/null +++ b/core/src/runtime/store/base.rs @@ -0,0 +1,27 @@ +use super::Store; + +/// A simple store representing a function with no internal state and no co-processors. +pub struct BaseStore { + pub clk: u32, + pub fp: u32, + pub pc: u32, + pub memory: Vec, +} + +impl Store for BaseStore { + fn memory(&mut self) -> &mut [u8] { + &mut self.memory + } + + fn clk(&mut self) -> &mut u32 { + &mut self.clk + } + + fn fp(&mut self) -> &mut u32 { + &mut self.fp + } + + fn pc(&mut self) -> &mut u32 { + &mut self.pc + } +} diff --git a/core/src/runtime/write.rs b/core/src/runtime/write.rs new file mode 100644 index 0000000000..bfb95b1f03 --- /dev/null +++ b/core/src/runtime/write.rs @@ -0,0 +1,13 @@ +use anyhow::Result; +use std::io::Write; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum PollResult { + Halt, + Continue, +} + +pub trait TraceWrite: Write { + /// Poll the writer to see if we should continue execution. + fn poll(&mut self) -> Result; +}