From 29d5fcbe1d80342a236af7a44bd5a876b91a59ba Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 17 Sep 2024 17:04:30 +0300 Subject: [PATCH] adding sp1, zkwasm, valida, nexus and risc0 guest program --- nexus/mem_alloc_vec_test/.cargo/config.toml | 5 + nexus/mem_alloc_vec_test/Cargo.toml | 14 ++ nexus/mem_alloc_vec_test/rust-toolchain.toml | 3 + nexus/mem_alloc_vec_test/src/main.rs | 54 ++++++++ .../simple_arithmetic_test/.cargo/config.toml | 5 + nexus/simple_arithmetic_test/Cargo.toml | 14 ++ .../rust-toolchain.toml | 3 + nexus/simple_arithmetic_test/src/main.rs | 24 ++++ .../bench_programs/mem_bench.rs | 31 +++++ .../bench_programs/perf_bench.rs | 31 +++++ .../guest_programs/mem_alloc_vec_test.rs | 65 +++++++++ .../guest_programs/simple_arithmetic_test.rs | 30 +++++ shared/memory_allocations/Cargo.toml | 8 ++ shared/memory_allocations/src/lib.rs | 117 ++++++++++++++++ sp1/mem_alloc_vec_test/.env.example | 5 + sp1/mem_alloc_vec_test/.gitignore | 19 +++ sp1/mem_alloc_vec_test/.vscode/settings.json | 37 +++++ sp1/mem_alloc_vec_test/Cargo.toml | 10 ++ sp1/mem_alloc_vec_test/LICENSE-MIT | 21 +++ sp1/mem_alloc_vec_test/README.md | 92 +++++++++++++ .../elf/riscv32im-succinct-zkvm-elf | Bin 0 -> 130776 bytes sp1/mem_alloc_vec_test/lib/Cargo.toml | 7 + sp1/mem_alloc_vec_test/lib/src/lib.rs | 52 ++++++++ sp1/mem_alloc_vec_test/program/Cargo.toml | 9 ++ sp1/mem_alloc_vec_test/program/src/main.rs | 29 ++++ sp1/mem_alloc_vec_test/rust-toolchain | 3 + sp1/mem_alloc_vec_test/script/Cargo.toml | 26 ++++ sp1/mem_alloc_vec_test/script/build.rs | 5 + sp1/mem_alloc_vec_test/script/src/bin/evm.rs | 126 ++++++++++++++++++ sp1/mem_alloc_vec_test/script/src/bin/main.rs | 91 +++++++++++++ sp1/simple_arithmetic_test/.env.example | 5 + sp1/simple_arithmetic_test/.gitignore | 19 +++ .../.vscode/settings.json | 37 +++++ sp1/simple_arithmetic_test/Cargo.toml | 10 ++ sp1/simple_arithmetic_test/LICENSE-MIT | 21 +++ sp1/simple_arithmetic_test/README.md | 92 +++++++++++++ .../elf/riscv32im-succinct-zkvm-elf | Bin 0 -> 130776 bytes sp1/simple_arithmetic_test/lib/Cargo.toml | 7 + sp1/simple_arithmetic_test/lib/src/lib.rs | 19 +++ sp1/simple_arithmetic_test/program/Cargo.toml | 9 ++ .../program/src/main.rs | 29 ++++ sp1/simple_arithmetic_test/rust-toolchain | 3 + sp1/simple_arithmetic_test/script/Cargo.toml | 26 ++++ sp1/simple_arithmetic_test/script/build.rs | 5 + .../script/src/bin/evm.rs | 126 ++++++++++++++++++ .../script/src/bin/main.rs | 91 +++++++++++++ valida/scripts_and_tools/build-rust.sh | 6 + valida/scripts_and_tools/valida_prove.sh | 3 + valida/scripts_and_tools/valida_setup.sh | 15 +++ valida/scripts_and_tools/valida_verify.sh | 3 + valida/tests/empty_test.rs | 14 ++ valida/tests/simple_arithmetic_test.rs | 23 ++++ zkwasm/scripts_and_tools/zkwasm_build.sh | 8 ++ zkwasm/scripts_and_tools/zkwasm_prove.sh | 5 + zkwasm/scripts_and_tools/zkwasm_setup.sh | 6 + .../scripts_and_tools/zkwasm_setup_circuit.sh | 5 + zkwasm/scripts_and_tools/zkwasm_verify.sh | 3 + zkwasm/tests/empty_test/Cargo.toml | 13 ++ zkwasm/tests/empty_test/src/lib.rs | 7 + zkwasm/tests/mem_alloc_vec_test/Cargo.toml | 14 ++ zkwasm/tests/mem_alloc_vec_test/src/lib.rs | 14 ++ .../tests/simple_arithmetic_test/Cargo.toml | 13 ++ .../tests/simple_arithmetic_test/src/lib.rs | 11 ++ 63 files changed, 1598 insertions(+) create mode 100644 nexus/mem_alloc_vec_test/.cargo/config.toml create mode 100644 nexus/mem_alloc_vec_test/Cargo.toml create mode 100644 nexus/mem_alloc_vec_test/rust-toolchain.toml create mode 100644 nexus/mem_alloc_vec_test/src/main.rs create mode 100644 nexus/simple_arithmetic_test/.cargo/config.toml create mode 100644 nexus/simple_arithmetic_test/Cargo.toml create mode 100644 nexus/simple_arithmetic_test/rust-toolchain.toml create mode 100644 nexus/simple_arithmetic_test/src/main.rs create mode 100644 risc0/benchmark_tests/bench_programs/mem_bench.rs create mode 100644 risc0/benchmark_tests/bench_programs/perf_bench.rs create mode 100644 risc0/benchmark_tests/guest_programs/mem_alloc_vec_test.rs create mode 100644 risc0/benchmark_tests/guest_programs/simple_arithmetic_test.rs create mode 100644 shared/memory_allocations/Cargo.toml create mode 100644 shared/memory_allocations/src/lib.rs create mode 100644 sp1/mem_alloc_vec_test/.env.example create mode 100644 sp1/mem_alloc_vec_test/.gitignore create mode 100644 sp1/mem_alloc_vec_test/.vscode/settings.json create mode 100644 sp1/mem_alloc_vec_test/Cargo.toml create mode 100644 sp1/mem_alloc_vec_test/LICENSE-MIT create mode 100644 sp1/mem_alloc_vec_test/README.md create mode 100755 sp1/mem_alloc_vec_test/elf/riscv32im-succinct-zkvm-elf create mode 100644 sp1/mem_alloc_vec_test/lib/Cargo.toml create mode 100644 sp1/mem_alloc_vec_test/lib/src/lib.rs create mode 100644 sp1/mem_alloc_vec_test/program/Cargo.toml create mode 100644 sp1/mem_alloc_vec_test/program/src/main.rs create mode 100644 sp1/mem_alloc_vec_test/rust-toolchain create mode 100644 sp1/mem_alloc_vec_test/script/Cargo.toml create mode 100644 sp1/mem_alloc_vec_test/script/build.rs create mode 100644 sp1/mem_alloc_vec_test/script/src/bin/evm.rs create mode 100644 sp1/mem_alloc_vec_test/script/src/bin/main.rs create mode 100644 sp1/simple_arithmetic_test/.env.example create mode 100644 sp1/simple_arithmetic_test/.gitignore create mode 100644 sp1/simple_arithmetic_test/.vscode/settings.json create mode 100644 sp1/simple_arithmetic_test/Cargo.toml create mode 100644 sp1/simple_arithmetic_test/LICENSE-MIT create mode 100644 sp1/simple_arithmetic_test/README.md create mode 100755 sp1/simple_arithmetic_test/elf/riscv32im-succinct-zkvm-elf create mode 100644 sp1/simple_arithmetic_test/lib/Cargo.toml create mode 100644 sp1/simple_arithmetic_test/lib/src/lib.rs create mode 100644 sp1/simple_arithmetic_test/program/Cargo.toml create mode 100644 sp1/simple_arithmetic_test/program/src/main.rs create mode 100644 sp1/simple_arithmetic_test/rust-toolchain create mode 100644 sp1/simple_arithmetic_test/script/Cargo.toml create mode 100644 sp1/simple_arithmetic_test/script/build.rs create mode 100644 sp1/simple_arithmetic_test/script/src/bin/evm.rs create mode 100644 sp1/simple_arithmetic_test/script/src/bin/main.rs create mode 100755 valida/scripts_and_tools/build-rust.sh create mode 100755 valida/scripts_and_tools/valida_prove.sh create mode 100755 valida/scripts_and_tools/valida_setup.sh create mode 100755 valida/scripts_and_tools/valida_verify.sh create mode 100644 valida/tests/empty_test.rs create mode 100644 valida/tests/simple_arithmetic_test.rs create mode 100755 zkwasm/scripts_and_tools/zkwasm_build.sh create mode 100755 zkwasm/scripts_and_tools/zkwasm_prove.sh create mode 100755 zkwasm/scripts_and_tools/zkwasm_setup.sh create mode 100755 zkwasm/scripts_and_tools/zkwasm_setup_circuit.sh create mode 100755 zkwasm/scripts_and_tools/zkwasm_verify.sh create mode 100644 zkwasm/tests/empty_test/Cargo.toml create mode 100644 zkwasm/tests/empty_test/src/lib.rs create mode 100644 zkwasm/tests/mem_alloc_vec_test/Cargo.toml create mode 100644 zkwasm/tests/mem_alloc_vec_test/src/lib.rs create mode 100644 zkwasm/tests/simple_arithmetic_test/Cargo.toml create mode 100644 zkwasm/tests/simple_arithmetic_test/src/lib.rs diff --git a/nexus/mem_alloc_vec_test/.cargo/config.toml b/nexus/mem_alloc_vec_test/.cargo/config.toml new file mode 100644 index 0000000..80e2c50 --- /dev/null +++ b/nexus/mem_alloc_vec_test/.cargo/config.toml @@ -0,0 +1,5 @@ +[target.riscv32i-unknown-none-elf] +rustflags = [ + "-C", "link-arg=-Tlink.x", +] +runner="nexus-run" diff --git a/nexus/mem_alloc_vec_test/Cargo.toml b/nexus/mem_alloc_vec_test/Cargo.toml new file mode 100644 index 0000000..9e2e6f8 --- /dev/null +++ b/nexus/mem_alloc_vec_test/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "mem_alloc_vec_test" +version = "0.1.0" +edition = "2021" + +[dependencies] +nexus-rt = { git = "https://github.com/nexus-xyz/nexus-zkvm.git", version = "0.2.3" } + +# Generated by cargo-nexus, do not remove! +# +# This profile is used for generating proofs, as Nexus VM support for compiler optimizations is still under development. +[features] +cycles = [] # Enable cycle counting for run command + diff --git a/nexus/mem_alloc_vec_test/rust-toolchain.toml b/nexus/mem_alloc_vec_test/rust-toolchain.toml new file mode 100644 index 0000000..2121065 --- /dev/null +++ b/nexus/mem_alloc_vec_test/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.77.0" +targets = ["riscv32i-unknown-none-elf"] diff --git a/nexus/mem_alloc_vec_test/src/main.rs b/nexus/mem_alloc_vec_test/src/main.rs new file mode 100644 index 0000000..e5f94e6 --- /dev/null +++ b/nexus/mem_alloc_vec_test/src/main.rs @@ -0,0 +1,54 @@ +#![cfg_attr(target_arch = "riscv32", no_std, no_main)] + +extern crate alloc; + +use alloc::vec::Vec; + +pub const CAP_LIM: usize = 10000; +pub const TO_INSERT_ITEM: usize = 145; + +macro_rules! write_tests_vec { + ($t:ty, $fn_name_1:ident, $fn_name_2:ident, $fn_name_3:ident, $fn_name_4:ident) => { + pub fn $fn_name_1() -> $t { + <$t>::with_capacity(CAP_LIM) + } + + pub fn $fn_name_2(vecc: &mut $t) { + for _ in 1..CAP_LIM { + vecc.push(TO_INSERT_ITEM); + } + } + + pub fn $fn_name_3(vecc: &mut $t) { + for _ in 0..(CAP_LIM + 1) { + vecc.push(TO_INSERT_ITEM); + } + } + + pub fn $fn_name_4(vecc: &mut $t) { + for _ in 1..CAP_LIM { + vecc.pop(); + } + } + }; +} + +write_tests_vec!(Vec, alloc_vec, push_vec, dyn_alloc_vec, pop_vec); + +pub fn vec_alloc(n: u32) -> u32 { + + let mut vvec = alloc_vec(); + + push_vec(&mut vvec); + + pop_vec(&mut vvec); + + 0 +} + +#[nexus_rt::main] +fn main() { + let n = 7; + let result = vec_alloc(n); + assert_eq!(result, 13); +} \ No newline at end of file diff --git a/nexus/simple_arithmetic_test/.cargo/config.toml b/nexus/simple_arithmetic_test/.cargo/config.toml new file mode 100644 index 0000000..80e2c50 --- /dev/null +++ b/nexus/simple_arithmetic_test/.cargo/config.toml @@ -0,0 +1,5 @@ +[target.riscv32i-unknown-none-elf] +rustflags = [ + "-C", "link-arg=-Tlink.x", +] +runner="nexus-run" diff --git a/nexus/simple_arithmetic_test/Cargo.toml b/nexus/simple_arithmetic_test/Cargo.toml new file mode 100644 index 0000000..18c5659 --- /dev/null +++ b/nexus/simple_arithmetic_test/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "simple_arithmetic_test" +version = "0.1.0" +edition = "2021" + +[dependencies] +nexus-rt = { git = "https://github.com/nexus-xyz/nexus-zkvm.git", version = "0.2.3" } + +# Generated by cargo-nexus, do not remove! +# +# This profile is used for generating proofs, as Nexus VM support for compiler optimizations is still under development. +[features] +cycles = [] # Enable cycle counting for run command + diff --git a/nexus/simple_arithmetic_test/rust-toolchain.toml b/nexus/simple_arithmetic_test/rust-toolchain.toml new file mode 100644 index 0000000..2121065 --- /dev/null +++ b/nexus/simple_arithmetic_test/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.77.0" +targets = ["riscv32i-unknown-none-elf"] diff --git a/nexus/simple_arithmetic_test/src/main.rs b/nexus/simple_arithmetic_test/src/main.rs new file mode 100644 index 0000000..83e9764 --- /dev/null +++ b/nexus/simple_arithmetic_test/src/main.rs @@ -0,0 +1,24 @@ +#![cfg_attr(target_arch = "riscv32", no_std, no_main)] + +fn fib(n: u32) -> u32 { + match n { + 0 => 0, + 1 => 1, + _ => fib(n - 1) + fib(n - 2), + } +} + +pub fn hept(n: u32) -> u32 { + + for i in 0..100 { + let hept = (5*i*i - 3*i)/2; + } + 0 +} + +#[nexus_rt::main] +fn main() { + let n = 7; + let result = hept(n); + assert_eq!(result, 13); +} \ No newline at end of file diff --git a/risc0/benchmark_tests/bench_programs/mem_bench.rs b/risc0/benchmark_tests/bench_programs/mem_bench.rs new file mode 100644 index 0000000..fe0931a --- /dev/null +++ b/risc0/benchmark_tests/bench_programs/mem_bench.rs @@ -0,0 +1,31 @@ +// Copyright 2024 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use risc0_zkvm::serde::to_vec; + +use crate::Job; + +pub fn new_jobs() -> Vec { + let mut jobs = Vec::new(); + for iterations in [1] { + jobs.push(Job::new( + format!("mem_alloc_vec_test-{iterations}"), + risc0_benchmark_methods::MEM_ALLOC_VEC_TEST_ELF, + risc0_benchmark_methods::MEM_ALLOC_VEC_TEST_ID.into(), + to_vec(&iterations).unwrap(), + iterations as usize, + )); + } + jobs +} \ No newline at end of file diff --git a/risc0/benchmark_tests/bench_programs/perf_bench.rs b/risc0/benchmark_tests/bench_programs/perf_bench.rs new file mode 100644 index 0000000..f6bc0d2 --- /dev/null +++ b/risc0/benchmark_tests/bench_programs/perf_bench.rs @@ -0,0 +1,31 @@ +// Copyright 2024 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use risc0_zkvm::serde::to_vec; + +use crate::Job; + +pub fn new_jobs() -> Vec { + let mut jobs = Vec::new(); + for iterations in [100] { + jobs.push(Job::new( + format!("simlpe_arithmetic_test-{iterations}"), + risc0_benchmark_methods::SIMPLE_ARITHMETIC_TEST_ELF, + risc0_benchmark_methods::SIMPLE_ARITHMETIC_TEST_ID.into(), + to_vec(&iterations).unwrap(), + iterations as usize, + )); + } + jobs +} \ No newline at end of file diff --git a/risc0/benchmark_tests/guest_programs/mem_alloc_vec_test.rs b/risc0/benchmark_tests/guest_programs/mem_alloc_vec_test.rs new file mode 100644 index 0000000..15d715d --- /dev/null +++ b/risc0/benchmark_tests/guest_programs/mem_alloc_vec_test.rs @@ -0,0 +1,65 @@ +// Copyright 2024 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::vec::Vec; + +pub const CAP_LIM: usize = 10000; +pub const TO_INSERT_ITEM: usize = 145; + +macro_rules! write_tests_vec { + ($t:ty, $fn_name_1:ident, $fn_name_2:ident, $fn_name_3:ident, $fn_name_4:ident) => { + pub fn $fn_name_1() -> $t { + <$t>::with_capacity(CAP_LIM) + } + + pub fn $fn_name_2(vecc: &mut $t) { + for _ in 1..CAP_LIM { + vecc.push(TO_INSERT_ITEM); + } + } + + pub fn $fn_name_3(vecc: &mut $t) { + for _ in 0..(CAP_LIM + 1) { + vecc.push(TO_INSERT_ITEM); + } + } + + pub fn $fn_name_4(vecc: &mut $t) { + for _ in 1..CAP_LIM { + vecc.pop(); + } + } + }; +} + +write_tests_vec!(Vec, alloc_vec, push_vec, dyn_alloc_vec, pop_vec); + +use nalgebra::Matrix2; +use risc0_zkvm::guest::env; + +fn main() { + let iterations: u32 = env::read(); + let answer = vec_alloc(iterations); + env::commit(&answer); +} + +fn vec_alloc(n: u32) -> u64 { + let mut vvec = alloc_vec(); + + push_vec(&mut vvec); + + pop_vec(&mut vvec); + + 0 +} diff --git a/risc0/benchmark_tests/guest_programs/simple_arithmetic_test.rs b/risc0/benchmark_tests/guest_programs/simple_arithmetic_test.rs new file mode 100644 index 0000000..63ca1f9 --- /dev/null +++ b/risc0/benchmark_tests/guest_programs/simple_arithmetic_test.rs @@ -0,0 +1,30 @@ +// Copyright 2024 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use nalgebra::Matrix2; +use risc0_zkvm::guest::env; + +fn main() { + let iterations: u32 = env::read(); + let answer = hept(iterations); + env::commit(&answer); +} + +fn hept(n: u32) -> u64 { + for i in 0..100 { + let hept = (5*i*i - 3*i)/2; + } + + 0 +} diff --git a/shared/memory_allocations/Cargo.toml b/shared/memory_allocations/Cargo.toml new file mode 100644 index 0000000..f813837 --- /dev/null +++ b/shared/memory_allocations/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "memory_allocations" +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/shared/memory_allocations/src/lib.rs b/shared/memory_allocations/src/lib.rs new file mode 100644 index 0000000..c215d52 --- /dev/null +++ b/shared/memory_allocations/src/lib.rs @@ -0,0 +1,117 @@ +use std::collections::{BTreeMap, BinaryHeap, HashMap, HashSet}; + +pub const CAP_LIM: usize = 10000; +pub const TO_INSERT_ITEM: usize = 145; + +pub fn alloc_btree_map() -> BTreeMap { + BTreeMap::new() +} + +pub fn insert_btree_map(mmap: &mut BTreeMap) { + for i in 1..CAP_LIM { + mmap.insert(TO_INSERT_ITEM + i, TO_INSERT_ITEM); + } +} + +pub fn remove_btree_map(mmap: &mut BTreeMap) { + for i in 1..CAP_LIM { + mmap.remove(&(TO_INSERT_ITEM + i)); + } +} + +macro_rules! write_tests_maps { + ($t:ty, $fn_name_1:ident, $fn_name_2:ident, $fn_name_3:ident, $fn_name_4:ident) => { + pub fn $fn_name_1() -> $t { + <$t>::with_capacity(CAP_LIM) + } + + pub fn $fn_name_2(mmap: &mut $t) { + for i in 1..CAP_LIM { + mmap.insert(TO_INSERT_ITEM + i, TO_INSERT_ITEM); + } + } + + pub fn $fn_name_3(mmap: &mut $t) { + for i in 0..(CAP_LIM + 1) { + mmap.insert(TO_INSERT_ITEM + i, TO_INSERT_ITEM); + } + } + + pub fn $fn_name_4(mmap: &mut $t) { + for i in 1..CAP_LIM { + mmap.remove(&(TO_INSERT_ITEM + i)); + } + } + }; +} + +macro_rules! write_tests_sets { + ($t:ty, $fn_name_1:ident, $fn_name_2:ident, $fn_name_3:ident, $fn_name_4:ident) => { + pub fn $fn_name_1() -> $t { + <$t>::with_capacity(CAP_LIM) + } + + pub fn $fn_name_2(mmap: &mut $t) { + for i in 1..CAP_LIM { + mmap.insert(TO_INSERT_ITEM + i); + } + } + + pub fn $fn_name_3(mmap: &mut $t) { + for i in 0..(CAP_LIM + 1) { + mmap.insert(TO_INSERT_ITEM + i); + } + } + + pub fn $fn_name_4(mmap: &mut $t) { + for i in 1..CAP_LIM { + mmap.remove(&(TO_INSERT_ITEM + i)); + } + } + }; +} + +macro_rules! write_tests_vec { + ($t:ty, $fn_name_1:ident, $fn_name_2:ident, $fn_name_3:ident, $fn_name_4:ident) => { + pub fn $fn_name_1() -> $t { + <$t>::with_capacity(CAP_LIM) + } + + pub fn $fn_name_2(vecc: &mut $t) { + for _ in 1..CAP_LIM { + vecc.push(TO_INSERT_ITEM); + } + } + + pub fn $fn_name_3(vecc: &mut $t) { + for _ in 0..(CAP_LIM + 1) { + vecc.push(TO_INSERT_ITEM); + } + } + + pub fn $fn_name_4(vecc: &mut $t) { + for _ in 1..CAP_LIM { + vecc.pop(); + } + } + }; +} + +write_tests_maps!(HashMap, alloc_hash_map, insert_hash_map, dyn_alloc_hash_map, remove_hash_map); +write_tests_sets!(HashSet, alloc_hash_set, insert_hash_set, dyn_alloc_hash_set, remove_hash_set); +write_tests_vec!(Vec, alloc_vec, push_vec, dyn_alloc_vec, pop_vec); +write_tests_vec!(BinaryHeap, alloc_b_heap, push_b_heap, dyn_alloc_b_heap, pop_b_heap); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test2() { + let mut mmap = alloc_hash_map(); + + insert_hash_map(&mut mmap); + + remove_hash_map(&mut mmap); + } +} diff --git a/sp1/mem_alloc_vec_test/.env.example b/sp1/mem_alloc_vec_test/.env.example new file mode 100644 index 0000000..48913a1 --- /dev/null +++ b/sp1/mem_alloc_vec_test/.env.example @@ -0,0 +1,5 @@ +# 'mock' for generating mock proofs locally, 'local' for generating proofs locally, 'network' for generating proofs using the proving network. +SP1_PROVER=local +# If using the proving network, set to your whitelisted private key. For more information, see: +# https://docs.succinct.xyz/prover-network/setup.html#key-setup +SP1_PRIVATE_KEY= \ No newline at end of file diff --git a/sp1/mem_alloc_vec_test/.gitignore b/sp1/mem_alloc_vec_test/.gitignore new file mode 100644 index 0000000..174aa94 --- /dev/null +++ b/sp1/mem_alloc_vec_test/.gitignore @@ -0,0 +1,19 @@ +# Cargo build +**/target + +# Cargo config +.cargo + +# Profile-guided optimization +/tmp +pgo-data.profdata + +# MacOS nuisances +.DS_Store + +# Proofs +**/proof-with-pis.json +**/proof-with-io.json + +# Env +.env \ No newline at end of file diff --git a/sp1/mem_alloc_vec_test/.vscode/settings.json b/sp1/mem_alloc_vec_test/.vscode/settings.json new file mode 100644 index 0000000..ca6a515 --- /dev/null +++ b/sp1/mem_alloc_vec_test/.vscode/settings.json @@ -0,0 +1,37 @@ +{ + "rust-analyzer.linkedProjects": [ + "program/Cargo.toml", + "script/Cargo.toml" + ], + "rust-analyzer.check.overrideCommand": [ + "cargo", + "clippy", + "--workspace", + "--message-format=json", + "--all-features", + "--all-targets", + "--", + "-A", + "incomplete-features" + ], + "rust-analyzer.runnables.extraEnv": { + "RUST_LOG": "debug", + "RUSTFLAGS": "-Ctarget-cpu=native" + }, + "rust-analyzer.runnables.extraArgs": [ + "--release", + "+nightly" + ], + "rust-analyzer.diagnostics.disabled": [ + "unresolved-proc-macro" + ], + "editor.rulers": [ + 100 + ], + "editor.inlineSuggest.enabled": true, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true, + "editor.hover.enabled": true + }, +} \ No newline at end of file diff --git a/sp1/mem_alloc_vec_test/Cargo.toml b/sp1/mem_alloc_vec_test/Cargo.toml new file mode 100644 index 0000000..3915b20 --- /dev/null +++ b/sp1/mem_alloc_vec_test/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] +members = [ + "lib", + "program", + "script", +] +resolver = "2" + +[workspace.dependencies] +alloy-sol-types = "0.7.7" \ No newline at end of file diff --git a/sp1/mem_alloc_vec_test/LICENSE-MIT b/sp1/mem_alloc_vec_test/LICENSE-MIT new file mode 100644 index 0000000..626685c --- /dev/null +++ b/sp1/mem_alloc_vec_test/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2024 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/sp1/mem_alloc_vec_test/README.md b/sp1/mem_alloc_vec_test/README.md new file mode 100644 index 0000000..295787d --- /dev/null +++ b/sp1/mem_alloc_vec_test/README.md @@ -0,0 +1,92 @@ +# SP1 Project Template + +This is a template for creating an end-to-end [SP1](https://github.com/succinctlabs/sp1) project +that can generate a proof of any RISC-V program. + +## Requirements + +- [Rust](https://rustup.rs/) +- [SP1](https://docs.succinct.xyz/getting-started/install.html) + +## Running the Project + +There are four main ways to run this project: build a program, execute a program, generate a core proof, and +generate an EVM-compatible proof. + +### Build the Program + +To build the program, run the following command: + +```sh +cd program +cargo prove build +``` + +### Execute the Program + +To run the program without generating a proof: + +```sh +cd script +cargo run --release -- --execute +``` + +This will execute the program and display the output. + +### Generate a Core Proof + +To generate a core proof for your program: + +```sh +cd script +cargo run --release -- --prove +``` + +### Generate an EVM-Compatible Proof + +> [!WARNING] +> You will need at least 128GB RAM to generate a PLONK or Groth16 proof. + +To generate a proof that is small enough to be verified on-chain and verifiable by the EVM: + +```sh +cd script +cargo run --release --bin evm -- --system plonk +``` + +this will generate a PLONK proof. If you want to generate a Groth16 proof, run the following command: + +```sh +cargo run --release --bin evm -- --system groth16 +``` + +These commands will also generate fixtures that can be used to test the verification of SP1 zkVM proofs +inside Solidity. + +### Retrieve the Verification Key + +To retrieve your `programVKey` for your on-chain contract, run the following command: + +```sh +cargo prove vkey --elf elf/riscv32im-succinct-zkvm-elf +``` + +## Using the Prover Network + +We highly recommend using the Succinct prover network for any non-trivial programs or benchmarking purposes. For more information, see the [setup guide](https://docs.succinct.xyz/prover-network/setup.html). + +To get started, copy the example environment file: + +```sh +cp .env.example .env +``` + +Then, set the `SP1_PROVER` environment variable to `network` and set the `SP1_PRIVATE_KEY` +environment variable to your whitelisted private key. + +For example, to generate an EVM-compatible proof using the prover network, run the following +command: + +```sh +SP1_PROVER=network SP1_PRIVATE_KEY=... cargo run --release --bin evm +``` diff --git a/sp1/mem_alloc_vec_test/elf/riscv32im-succinct-zkvm-elf b/sp1/mem_alloc_vec_test/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000000000000000000000000000000000..8aa13f878b59b86fb986e52da8f661ec831e2849 GIT binary patch literal 130776 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

u#^}kYU;ez9;rN4;iNHXPiskwRDj7_gcs| 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 I4f}Tg4~{a!v;Y7A literal 0 HcmV?d00001 diff --git a/sp1/mem_alloc_vec_test/lib/Cargo.toml b/sp1/mem_alloc_vec_test/lib/Cargo.toml new file mode 100644 index 0000000..23dc268 --- /dev/null +++ b/sp1/mem_alloc_vec_test/lib/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "mem_alloc_vec_test-lib" +version = "0.1.0" +edition = "2021" + +[dependencies] +alloy-sol-types = { workspace = true } diff --git a/sp1/mem_alloc_vec_test/lib/src/lib.rs b/sp1/mem_alloc_vec_test/lib/src/lib.rs new file mode 100644 index 0000000..8dfa1be --- /dev/null +++ b/sp1/mem_alloc_vec_test/lib/src/lib.rs @@ -0,0 +1,52 @@ +use alloy_sol_types::sol; + +sol! { + /// The public values encoded as a struct that can be easily deserialized inside Solidity. + struct PublicValuesStruct { + uint32 n; + uint32 a; + uint32 b; + } +} + +pub const CAP_LIM: usize = 10000; +pub const TO_INSERT_ITEM: usize = 145; + +macro_rules! write_tests_vec { + ($t:ty, $fn_name_1:ident, $fn_name_2:ident, $fn_name_3:ident, $fn_name_4:ident) => { + pub fn $fn_name_1() -> $t { + <$t>::with_capacity(CAP_LIM) + } + + pub fn $fn_name_2(vecc: &mut $t) { + for _ in 1..CAP_LIM { + vecc.push(TO_INSERT_ITEM); + } + } + + pub fn $fn_name_3(vecc: &mut $t) { + for _ in 0..(CAP_LIM + 1) { + vecc.push(TO_INSERT_ITEM); + } + } + + pub fn $fn_name_4(vecc: &mut $t) { + for _ in 1..CAP_LIM { + vecc.pop(); + } + } + }; +} + +write_tests_vec!(Vec, alloc_vec, push_vec, dyn_alloc_vec, pop_vec); + +pub fn vec_alloc(n: u32) -> (u32, u32) { + + let mut vecc = alloc_vec(); + + push_vec(&mut vecc); + + pop_vec(&mut vecc); + + (0, 0) +} \ No newline at end of file diff --git a/sp1/mem_alloc_vec_test/program/Cargo.toml b/sp1/mem_alloc_vec_test/program/Cargo.toml new file mode 100644 index 0000000..f92f254 --- /dev/null +++ b/sp1/mem_alloc_vec_test/program/Cargo.toml @@ -0,0 +1,9 @@ +[package] +version = "0.1.0" +name = "mem_alloc_vec_test-program" +edition = "2021" + +[dependencies] +alloy-sol-types = { workspace = true } +sp1-zkvm = "1.2.0" +mem_alloc_vec_test-lib = { path = "../lib" } diff --git a/sp1/mem_alloc_vec_test/program/src/main.rs b/sp1/mem_alloc_vec_test/program/src/main.rs new file mode 100644 index 0000000..cb31543 --- /dev/null +++ b/sp1/mem_alloc_vec_test/program/src/main.rs @@ -0,0 +1,29 @@ +//! A simple program that takes a number `n` as input, and writes the `n-1`th and `n`th fibonacci +//! number as an output. + +// These two lines are necessary for the program to properly compile. +// +// Under the hood, we wrap your main function with some extra code so that it behaves properly +// inside the zkVM. +#![no_main] +sp1_zkvm::entrypoint!(main); + +use alloy_sol_types::SolType; +use mem_alloc_vec_test_lib::{vec_alloc, PublicValuesStruct}; + +pub fn main() { + // Read an input to the program. + // + // Behind the scenes, this compiles down to a custom system call which handles reading inputs + // from the prover. + let n = sp1_zkvm::io::read::(); + + let (a, b) = vec_alloc(n); + + // Encode the public values of the program. + let bytes = PublicValuesStruct::abi_encode(&PublicValuesStruct { n, a, b }); + + // Commit to the public values of the program. The final proof will have a commitment to all the + // bytes that were committed to. + sp1_zkvm::io::commit_slice(&bytes); +} diff --git a/sp1/mem_alloc_vec_test/rust-toolchain b/sp1/mem_alloc_vec_test/rust-toolchain new file mode 100644 index 0000000..3415d6b --- /dev/null +++ b/sp1/mem_alloc_vec_test/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.79.0" +components = ["llvm-tools", "rustc-dev"] \ No newline at end of file diff --git a/sp1/mem_alloc_vec_test/script/Cargo.toml b/sp1/mem_alloc_vec_test/script/Cargo.toml new file mode 100644 index 0000000..cb769c6 --- /dev/null +++ b/sp1/mem_alloc_vec_test/script/Cargo.toml @@ -0,0 +1,26 @@ +[package] +version = "0.1.0" +name = "mem_alloc_vec_test-script" +edition = "2021" +default-run = "mem_alloc_vec_test" + +[[bin]] +name = "mem_alloc_vec_test" +path = "src/bin/main.rs" + +[[bin]] +name = "evm" +path = "src/bin/evm.rs" + +[dependencies] +sp1-sdk = "1.2.0" +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } +serde = { version = "1.0", default-features = false, features = ["derive"] } +clap = { version = "4.0", features = ["derive", "env"] } +tracing = "0.1.40" +hex = "0.4.3" +alloy-sol-types = { workspace = true } +mem_alloc_vec_test-lib = { path = "../lib" } + +[build-dependencies] +sp1-helper = "1.2.0" diff --git a/sp1/mem_alloc_vec_test/script/build.rs b/sp1/mem_alloc_vec_test/script/build.rs new file mode 100644 index 0000000..bc5f025 --- /dev/null +++ b/sp1/mem_alloc_vec_test/script/build.rs @@ -0,0 +1,5 @@ +use sp1_helper::build_program_with_args; + +fn main() { + build_program_with_args("../program", Default::default()) +} diff --git a/sp1/mem_alloc_vec_test/script/src/bin/evm.rs b/sp1/mem_alloc_vec_test/script/src/bin/evm.rs new file mode 100644 index 0000000..d39357c --- /dev/null +++ b/sp1/mem_alloc_vec_test/script/src/bin/evm.rs @@ -0,0 +1,126 @@ +//! An end-to-end example of using the SP1 SDK to generate a proof of a program that can have an +//! EVM-Compatible proof generated which can be verified on-chain. +//! +//! You can run this script using the following command: +//! ```shell +//! RUST_LOG=info cargo run --release --bin evm -- --system plonk +//! ``` +//! or +//! ```shell +//! RUST_LOG=info cargo run --release --bin evm -- --system groth16 +//! ``` + +use alloy_sol_types::SolType; +use clap::{Parser, ValueEnum}; +use mem_alloc_vec_test_lib::PublicValuesStruct; +use serde::{Deserialize, Serialize}; +use sp1_sdk::{HashableKey, ProverClient, SP1ProofWithPublicValues, SP1Stdin, SP1VerifyingKey}; +use std::path::PathBuf; + +/// The ELF (executable and linkable format) file for the Succinct RISC-V zkVM. +pub const MEM_ALLOC_VEC_TEST_ELF: &[u8] = include_bytes!("../../../elf/riscv32im-succinct-zkvm-elf"); + +/// The arguments for the EVM command. +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct EVMArgs { + #[clap(long, default_value = "20")] + n: u32, + #[clap(long, value_enum, default_value = "plonk")] + system: ProofSystem, +} + +/// Enum representing the available proof systems +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)] +enum ProofSystem { + Plonk, + Groth16, +} + +/// A fixture that can be used to test the verification of SP1 zkVM proofs inside Solidity. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct SP1SimpleArithmeticTestProofFixture { + a: u32, + b: u32, + n: u32, + vkey: String, + public_values: String, + proof: String, +} + +fn main() { + // Setup the logger. + sp1_sdk::utils::setup_logger(); + + // Parse the command line arguments. + let args = EVMArgs::parse(); + + // Setup the prover client. + let client = ProverClient::new(); + + // Setup the program. + let (pk, vk) = client.setup(MEM_ALLOC_VEC_TEST_ELF); + + // Setup the inputs. + let mut stdin = SP1Stdin::new(); + stdin.write(&args.n); + + println!("n: {}", args.n); + println!("Proof System: {:?}", args.system); + + // Generate the proof based on the selected proof system. + let proof = match args.system { + ProofSystem::Plonk => client.prove(&pk, stdin).plonk().run(), + ProofSystem::Groth16 => client.prove(&pk, stdin).groth16().run(), + } + .expect("failed to generate proof"); + + create_proof_fixture(&proof, &vk, args.system); +} + +/// Create a fixture for the given proof. +fn create_proof_fixture( + proof: &SP1ProofWithPublicValues, + vk: &SP1VerifyingKey, + system: ProofSystem, +) { + // Deserialize the public values. + let bytes = proof.public_values.as_slice(); + let PublicValuesStruct { n, a, b } = PublicValuesStruct::abi_decode(bytes, false).unwrap(); + + // Create the testing fixture so we can test things end-to-end. + let fixture = SP1MemAllocVecTestProofFixture { + a, + b, + n, + vkey: vk.bytes32().to_string(), + public_values: format!("0x{}", hex::encode(bytes)), + proof: format!("0x{}", hex::encode(proof.bytes())), + }; + + // The verification key is used to verify that the proof corresponds to the execution of the + // program on the given input. + // + // Note that the verification key stays the same regardless of the input. + println!("Verification Key: {}", fixture.vkey); + + // The public values are the values which are publicly committed to by the zkVM. + // + // If you need to expose the inputs or outputs of your program, you should commit them in + // the public values. + println!("Public Values: {}", fixture.public_values); + + // The proof proves to the verifier that the program was executed with some inputs that led to + // the give public values. + println!("Proof Bytes: {}", fixture.proof); + + // Save the fixture to a file. + let fixture_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../contracts/src/fixtures"); + std::fs::create_dir_all(&fixture_path).expect("failed to create fixture path"); + std::fs::write( + fixture_path.join(format!("{:?}-fixture.json", system).to_lowercase()), + serde_json::to_string_pretty(&fixture).unwrap(), + ) + .expect("failed to write fixture"); +} diff --git a/sp1/mem_alloc_vec_test/script/src/bin/main.rs b/sp1/mem_alloc_vec_test/script/src/bin/main.rs new file mode 100644 index 0000000..51defd9 --- /dev/null +++ b/sp1/mem_alloc_vec_test/script/src/bin/main.rs @@ -0,0 +1,91 @@ +//! An end-to-end example of using the SP1 SDK to generate a proof of a program that can be executed +//! or have a core proof generated. +//! +//! You can run this script using the following command: +//! ```shell +//! RUST_LOG=info cargo run --release -- --execute +//! ``` +//! or +//! ```shell +//! RUST_LOG=info cargo run --release -- --prove +//! ``` + +use alloy_sol_types::SolType; +use clap::Parser; +use simple_arithmetic_test_lib::PublicValuesStruct; +use sp1_sdk::{ProverClient, SP1Stdin}; + +/// The ELF (executable and linkable format) file for the Succinct RISC-V zkVM. +pub const MEM_ALLOC_VEC_TEST_ELF: &[u8] = include_bytes!("../../../elf/riscv32im-succinct-zkvm-elf"); + +/// The arguments for the command. +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Args { + #[clap(long)] + execute: bool, + + #[clap(long)] + prove: bool, + + #[clap(long, default_value = "20")] + n: u32, +} + +fn main() { + // Setup the logger. + sp1_sdk::utils::setup_logger(); + + // Parse the command line arguments. + let args = Args::parse(); + + if args.execute == args.prove { + eprintln!("Error: You must specify either --execute or --prove"); + std::process::exit(1); + } + + // Setup the prover client. + let client = ProverClient::new(); + + // Setup the inputs. + let mut stdin = SP1Stdin::new(); + stdin.write(&args.n); + + println!("n: {}", args.n); + + if args.execute { + // Execute the program + let (output, report) = client.execute(MEM_ALLOC_VEC_TEST_ELF, stdin).run().unwrap(); + println!("Program executed successfully."); + + // Read the output. + let decoded = PublicValuesStruct::abi_decode(output.as_slice(), true).unwrap(); + let PublicValuesStruct { n, a, b } = decoded; + println!("n: {}", n); + println!("a: {}", a); + println!("b: {}", b); + + let (expected_a, expected_b) = fibonacci_lib::fibonacci(n); + assert_eq!(a, expected_a); + assert_eq!(b, expected_b); + println!("Values are correct!"); + + // Record the number of cycles executed. + println!("Number of cycles: {}", report.total_instruction_count()); + } else { + // Setup the program for proving. + let (pk, vk) = client.setup(FIBONACCI_ELF); + + // Generate the proof + let proof = client + .prove(&pk, stdin) + .run() + .expect("failed to generate proof"); + + println!("Successfully generated proof!"); + + // Verify the proof. + client.verify(&proof, &vk).expect("failed to verify proof"); + println!("Successfully verified proof!"); + } +} diff --git a/sp1/simple_arithmetic_test/.env.example b/sp1/simple_arithmetic_test/.env.example new file mode 100644 index 0000000..48913a1 --- /dev/null +++ b/sp1/simple_arithmetic_test/.env.example @@ -0,0 +1,5 @@ +# 'mock' for generating mock proofs locally, 'local' for generating proofs locally, 'network' for generating proofs using the proving network. +SP1_PROVER=local +# If using the proving network, set to your whitelisted private key. For more information, see: +# https://docs.succinct.xyz/prover-network/setup.html#key-setup +SP1_PRIVATE_KEY= \ No newline at end of file diff --git a/sp1/simple_arithmetic_test/.gitignore b/sp1/simple_arithmetic_test/.gitignore new file mode 100644 index 0000000..174aa94 --- /dev/null +++ b/sp1/simple_arithmetic_test/.gitignore @@ -0,0 +1,19 @@ +# Cargo build +**/target + +# Cargo config +.cargo + +# Profile-guided optimization +/tmp +pgo-data.profdata + +# MacOS nuisances +.DS_Store + +# Proofs +**/proof-with-pis.json +**/proof-with-io.json + +# Env +.env \ No newline at end of file diff --git a/sp1/simple_arithmetic_test/.vscode/settings.json b/sp1/simple_arithmetic_test/.vscode/settings.json new file mode 100644 index 0000000..ca6a515 --- /dev/null +++ b/sp1/simple_arithmetic_test/.vscode/settings.json @@ -0,0 +1,37 @@ +{ + "rust-analyzer.linkedProjects": [ + "program/Cargo.toml", + "script/Cargo.toml" + ], + "rust-analyzer.check.overrideCommand": [ + "cargo", + "clippy", + "--workspace", + "--message-format=json", + "--all-features", + "--all-targets", + "--", + "-A", + "incomplete-features" + ], + "rust-analyzer.runnables.extraEnv": { + "RUST_LOG": "debug", + "RUSTFLAGS": "-Ctarget-cpu=native" + }, + "rust-analyzer.runnables.extraArgs": [ + "--release", + "+nightly" + ], + "rust-analyzer.diagnostics.disabled": [ + "unresolved-proc-macro" + ], + "editor.rulers": [ + 100 + ], + "editor.inlineSuggest.enabled": true, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true, + "editor.hover.enabled": true + }, +} \ No newline at end of file diff --git a/sp1/simple_arithmetic_test/Cargo.toml b/sp1/simple_arithmetic_test/Cargo.toml new file mode 100644 index 0000000..3915b20 --- /dev/null +++ b/sp1/simple_arithmetic_test/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] +members = [ + "lib", + "program", + "script", +] +resolver = "2" + +[workspace.dependencies] +alloy-sol-types = "0.7.7" \ No newline at end of file diff --git a/sp1/simple_arithmetic_test/LICENSE-MIT b/sp1/simple_arithmetic_test/LICENSE-MIT new file mode 100644 index 0000000..626685c --- /dev/null +++ b/sp1/simple_arithmetic_test/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2024 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/sp1/simple_arithmetic_test/README.md b/sp1/simple_arithmetic_test/README.md new file mode 100644 index 0000000..295787d --- /dev/null +++ b/sp1/simple_arithmetic_test/README.md @@ -0,0 +1,92 @@ +# SP1 Project Template + +This is a template for creating an end-to-end [SP1](https://github.com/succinctlabs/sp1) project +that can generate a proof of any RISC-V program. + +## Requirements + +- [Rust](https://rustup.rs/) +- [SP1](https://docs.succinct.xyz/getting-started/install.html) + +## Running the Project + +There are four main ways to run this project: build a program, execute a program, generate a core proof, and +generate an EVM-compatible proof. + +### Build the Program + +To build the program, run the following command: + +```sh +cd program +cargo prove build +``` + +### Execute the Program + +To run the program without generating a proof: + +```sh +cd script +cargo run --release -- --execute +``` + +This will execute the program and display the output. + +### Generate a Core Proof + +To generate a core proof for your program: + +```sh +cd script +cargo run --release -- --prove +``` + +### Generate an EVM-Compatible Proof + +> [!WARNING] +> You will need at least 128GB RAM to generate a PLONK or Groth16 proof. + +To generate a proof that is small enough to be verified on-chain and verifiable by the EVM: + +```sh +cd script +cargo run --release --bin evm -- --system plonk +``` + +this will generate a PLONK proof. If you want to generate a Groth16 proof, run the following command: + +```sh +cargo run --release --bin evm -- --system groth16 +``` + +These commands will also generate fixtures that can be used to test the verification of SP1 zkVM proofs +inside Solidity. + +### Retrieve the Verification Key + +To retrieve your `programVKey` for your on-chain contract, run the following command: + +```sh +cargo prove vkey --elf elf/riscv32im-succinct-zkvm-elf +``` + +## Using the Prover Network + +We highly recommend using the Succinct prover network for any non-trivial programs or benchmarking purposes. For more information, see the [setup guide](https://docs.succinct.xyz/prover-network/setup.html). + +To get started, copy the example environment file: + +```sh +cp .env.example .env +``` + +Then, set the `SP1_PROVER` environment variable to `network` and set the `SP1_PRIVATE_KEY` +environment variable to your whitelisted private key. + +For example, to generate an EVM-compatible proof using the prover network, run the following +command: + +```sh +SP1_PROVER=network SP1_PRIVATE_KEY=... cargo run --release --bin evm +``` diff --git a/sp1/simple_arithmetic_test/elf/riscv32im-succinct-zkvm-elf b/sp1/simple_arithmetic_test/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000000000000000000000000000000000..8aa13f878b59b86fb986e52da8f661ec831e2849 GIT binary patch literal 130776 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

u#^}kYU;ez9;rN4;iNHXPiskwRDj7_gcs| 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 I4f}Tg4~{a!v;Y7A literal 0 HcmV?d00001 diff --git a/sp1/simple_arithmetic_test/lib/Cargo.toml b/sp1/simple_arithmetic_test/lib/Cargo.toml new file mode 100644 index 0000000..fe5a39e --- /dev/null +++ b/sp1/simple_arithmetic_test/lib/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "simple_arithmetic_test-lib" +version = "0.1.0" +edition = "2021" + +[dependencies] +alloy-sol-types = { workspace = true } diff --git a/sp1/simple_arithmetic_test/lib/src/lib.rs b/sp1/simple_arithmetic_test/lib/src/lib.rs new file mode 100644 index 0000000..03d36ad --- /dev/null +++ b/sp1/simple_arithmetic_test/lib/src/lib.rs @@ -0,0 +1,19 @@ +use alloy_sol_types::sol; + +sol! { + /// The public values encoded as a struct that can be easily deserialized inside Solidity. + struct PublicValuesStruct { + uint32 n; + uint32 a; + uint32 b; + } +} + +pub fn hept(n: u32) -> (u32, u32) { + + for i in 0..100 { + let hept = (5*i*i - 3*i)/2; + } + + (0, 0) +} \ No newline at end of file diff --git a/sp1/simple_arithmetic_test/program/Cargo.toml b/sp1/simple_arithmetic_test/program/Cargo.toml new file mode 100644 index 0000000..3ffda43 --- /dev/null +++ b/sp1/simple_arithmetic_test/program/Cargo.toml @@ -0,0 +1,9 @@ +[package] +version = "0.1.0" +name = "simple_arithmetic_test-program" +edition = "2021" + +[dependencies] +alloy-sol-types = { workspace = true } +sp1-zkvm = "1.2.0" +simple_arithmetic_test-lib = { path = "../lib" } diff --git a/sp1/simple_arithmetic_test/program/src/main.rs b/sp1/simple_arithmetic_test/program/src/main.rs new file mode 100644 index 0000000..1a624b3 --- /dev/null +++ b/sp1/simple_arithmetic_test/program/src/main.rs @@ -0,0 +1,29 @@ +//! A simple program that takes a number `n` as input, and writes the `n-1`th and `n`th fibonacci +//! number as an output. + +// These two lines are necessary for the program to properly compile. +// +// Under the hood, we wrap your main function with some extra code so that it behaves properly +// inside the zkVM. +#![no_main] +sp1_zkvm::entrypoint!(main); + +use alloy_sol_types::SolType; +use simple_arithmetic_test_lib::{hept, PublicValuesStruct}; + +pub fn main() { + // Read an input to the program. + // + // Behind the scenes, this compiles down to a custom system call which handles reading inputs + // from the prover. + let n = sp1_zkvm::io::read::(); + + let (a, b) = hept(n); + + // Encode the public values of the program. + let bytes = PublicValuesStruct::abi_encode(&PublicValuesStruct { n, a, b }); + + // Commit to the public values of the program. The final proof will have a commitment to all the + // bytes that were committed to. + sp1_zkvm::io::commit_slice(&bytes); +} diff --git a/sp1/simple_arithmetic_test/rust-toolchain b/sp1/simple_arithmetic_test/rust-toolchain new file mode 100644 index 0000000..3415d6b --- /dev/null +++ b/sp1/simple_arithmetic_test/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.79.0" +components = ["llvm-tools", "rustc-dev"] \ No newline at end of file diff --git a/sp1/simple_arithmetic_test/script/Cargo.toml b/sp1/simple_arithmetic_test/script/Cargo.toml new file mode 100644 index 0000000..4de789f --- /dev/null +++ b/sp1/simple_arithmetic_test/script/Cargo.toml @@ -0,0 +1,26 @@ +[package] +version = "0.1.0" +name = "simple_arithmetic_test-script" +edition = "2021" +default-run = "simple_arithmetic_test" + +[[bin]] +name = "simple_arithmetic_test" +path = "src/bin/main.rs" + +[[bin]] +name = "evm" +path = "src/bin/evm.rs" + +[dependencies] +sp1-sdk = "1.2.0" +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } +serde = { version = "1.0", default-features = false, features = ["derive"] } +clap = { version = "4.0", features = ["derive", "env"] } +tracing = "0.1.40" +hex = "0.4.3" +alloy-sol-types = { workspace = true } +simple_arithmetic_test-lib = { path = "../lib" } + +[build-dependencies] +sp1-helper = "1.2.0" diff --git a/sp1/simple_arithmetic_test/script/build.rs b/sp1/simple_arithmetic_test/script/build.rs new file mode 100644 index 0000000..bc5f025 --- /dev/null +++ b/sp1/simple_arithmetic_test/script/build.rs @@ -0,0 +1,5 @@ +use sp1_helper::build_program_with_args; + +fn main() { + build_program_with_args("../program", Default::default()) +} diff --git a/sp1/simple_arithmetic_test/script/src/bin/evm.rs b/sp1/simple_arithmetic_test/script/src/bin/evm.rs new file mode 100644 index 0000000..88ff465 --- /dev/null +++ b/sp1/simple_arithmetic_test/script/src/bin/evm.rs @@ -0,0 +1,126 @@ +//! An end-to-end example of using the SP1 SDK to generate a proof of a program that can have an +//! EVM-Compatible proof generated which can be verified on-chain. +//! +//! You can run this script using the following command: +//! ```shell +//! RUST_LOG=info cargo run --release --bin evm -- --system plonk +//! ``` +//! or +//! ```shell +//! RUST_LOG=info cargo run --release --bin evm -- --system groth16 +//! ``` + +use alloy_sol_types::SolType; +use clap::{Parser, ValueEnum}; +use simple_arithmetic_test_lib::PublicValuesStruct; +use serde::{Deserialize, Serialize}; +use sp1_sdk::{HashableKey, ProverClient, SP1ProofWithPublicValues, SP1Stdin, SP1VerifyingKey}; +use std::path::PathBuf; + +/// The ELF (executable and linkable format) file for the Succinct RISC-V zkVM. +pub const SIMPLE_ARITHMETIC_TEST_ELF: &[u8] = include_bytes!("../../../elf/riscv32im-succinct-zkvm-elf"); + +/// The arguments for the EVM command. +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct EVMArgs { + #[clap(long, default_value = "20")] + n: u32, + #[clap(long, value_enum, default_value = "plonk")] + system: ProofSystem, +} + +/// Enum representing the available proof systems +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)] +enum ProofSystem { + Plonk, + Groth16, +} + +/// A fixture that can be used to test the verification of SP1 zkVM proofs inside Solidity. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct SP1SimpleArithmeticTestProofFixture { + a: u32, + b: u32, + n: u32, + vkey: String, + public_values: String, + proof: String, +} + +fn main() { + // Setup the logger. + sp1_sdk::utils::setup_logger(); + + // Parse the command line arguments. + let args = EVMArgs::parse(); + + // Setup the prover client. + let client = ProverClient::new(); + + // Setup the program. + let (pk, vk) = client.setup(SIMPLE_ARITHMETIC_TEST_ELF); + + // Setup the inputs. + let mut stdin = SP1Stdin::new(); + stdin.write(&args.n); + + println!("n: {}", args.n); + println!("Proof System: {:?}", args.system); + + // Generate the proof based on the selected proof system. + let proof = match args.system { + ProofSystem::Plonk => client.prove(&pk, stdin).plonk().run(), + ProofSystem::Groth16 => client.prove(&pk, stdin).groth16().run(), + } + .expect("failed to generate proof"); + + create_proof_fixture(&proof, &vk, args.system); +} + +/// Create a fixture for the given proof. +fn create_proof_fixture( + proof: &SP1ProofWithPublicValues, + vk: &SP1VerifyingKey, + system: ProofSystem, +) { + // Deserialize the public values. + let bytes = proof.public_values.as_slice(); + let PublicValuesStruct { n, a, b } = PublicValuesStruct::abi_decode(bytes, false).unwrap(); + + // Create the testing fixture so we can test things end-to-end. + let fixture = SP1SimpleArithmeticTestProofFixture { + a, + b, + n, + vkey: vk.bytes32().to_string(), + public_values: format!("0x{}", hex::encode(bytes)), + proof: format!("0x{}", hex::encode(proof.bytes())), + }; + + // The verification key is used to verify that the proof corresponds to the execution of the + // program on the given input. + // + // Note that the verification key stays the same regardless of the input. + println!("Verification Key: {}", fixture.vkey); + + // The public values are the values which are publicly committed to by the zkVM. + // + // If you need to expose the inputs or outputs of your program, you should commit them in + // the public values. + println!("Public Values: {}", fixture.public_values); + + // The proof proves to the verifier that the program was executed with some inputs that led to + // the give public values. + println!("Proof Bytes: {}", fixture.proof); + + // Save the fixture to a file. + let fixture_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../contracts/src/fixtures"); + std::fs::create_dir_all(&fixture_path).expect("failed to create fixture path"); + std::fs::write( + fixture_path.join(format!("{:?}-fixture.json", system).to_lowercase()), + serde_json::to_string_pretty(&fixture).unwrap(), + ) + .expect("failed to write fixture"); +} diff --git a/sp1/simple_arithmetic_test/script/src/bin/main.rs b/sp1/simple_arithmetic_test/script/src/bin/main.rs new file mode 100644 index 0000000..4e9eff4 --- /dev/null +++ b/sp1/simple_arithmetic_test/script/src/bin/main.rs @@ -0,0 +1,91 @@ +//! An end-to-end example of using the SP1 SDK to generate a proof of a program that can be executed +//! or have a core proof generated. +//! +//! You can run this script using the following command: +//! ```shell +//! RUST_LOG=info cargo run --release -- --execute +//! ``` +//! or +//! ```shell +//! RUST_LOG=info cargo run --release -- --prove +//! ``` + +use alloy_sol_types::SolType; +use clap::Parser; +use simple_arithmetic_test_lib::PublicValuesStruct; +use sp1_sdk::{ProverClient, SP1Stdin}; + +/// The ELF (executable and linkable format) file for the Succinct RISC-V zkVM. +pub const SIMPLE_ARITHMETIC_TEST_ELF: &[u8] = include_bytes!("../../../elf/riscv32im-succinct-zkvm-elf"); + +/// The arguments for the command. +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct Args { + #[clap(long)] + execute: bool, + + #[clap(long)] + prove: bool, + + #[clap(long, default_value = "20")] + n: u32, +} + +fn main() { + // Setup the logger. + sp1_sdk::utils::setup_logger(); + + // Parse the command line arguments. + let args = Args::parse(); + + if args.execute == args.prove { + eprintln!("Error: You must specify either --execute or --prove"); + std::process::exit(1); + } + + // Setup the prover client. + let client = ProverClient::new(); + + // Setup the inputs. + let mut stdin = SP1Stdin::new(); + stdin.write(&args.n); + + println!("n: {}", args.n); + + if args.execute { + // Execute the program + let (output, report) = client.execute(SIMPLE_ARITHMETIC_TEST_ELF, stdin).run().unwrap(); + println!("Program executed successfully."); + + // Read the output. + let decoded = PublicValuesStruct::abi_decode(output.as_slice(), true).unwrap(); + let PublicValuesStruct { n, a, b } = decoded; + println!("n: {}", n); + println!("a: {}", a); + println!("b: {}", b); + + let (expected_a, expected_b) = fibonacci_lib::fibonacci(n); + assert_eq!(a, expected_a); + assert_eq!(b, expected_b); + println!("Values are correct!"); + + // Record the number of cycles executed. + println!("Number of cycles: {}", report.total_instruction_count()); + } else { + // Setup the program for proving. + let (pk, vk) = client.setup(FIBONACCI_ELF); + + // Generate the proof + let proof = client + .prove(&pk, stdin) + .run() + .expect("failed to generate proof"); + + println!("Successfully generated proof!"); + + // Verify the proof. + client.verify(&proof, &vk).expect("failed to verify proof"); + println!("Successfully verified proof!"); + } +} diff --git a/valida/scripts_and_tools/build-rust.sh b/valida/scripts_and_tools/build-rust.sh new file mode 100755 index 0000000..e82ccb3 --- /dev/null +++ b/valida/scripts_and_tools/build-rust.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +TEST_NAME=$1 + +rustc --emit=llvm-ir -Cpanic="abort" -C opt-level=3 -C target-cpu=generic ../tests/$TEST_NAME.rs +./llc -march=delendum -filetype=obj $TEST_NAME.ll +./ld.lld --script=./valida.ld $TEST_NAME.o -L . -lstdio -o $TEST_NAME diff --git a/valida/scripts_and_tools/valida_prove.sh b/valida/scripts_and_tools/valida_prove.sh new file mode 100755 index 0000000..60e4025 --- /dev/null +++ b/valida/scripts_and_tools/valida_prove.sh @@ -0,0 +1,3 @@ +TEST_NAME=$1 + +./valida prove ./$TEST_NAME ./$TEST_NAME.proof \ No newline at end of file diff --git a/valida/scripts_and_tools/valida_setup.sh b/valida/scripts_and_tools/valida_setup.sh new file mode 100755 index 0000000..abb11e2 --- /dev/null +++ b/valida/scripts_and_tools/valida_setup.sh @@ -0,0 +1,15 @@ +set -eo + +wget https://github.com/lita-xyz/llvm-valida-releases/releases/latest/download/llvm-valida-v0.3.0-alpha-linux-x86_64.tar.gz +tar xzvf llvm-valida-v0.3.0-alpha-linux-x86_64.tar.gz +cd llvm-valida-release +mv clang .. +mv DelendumEntryPoint.o .. +mv ld.lld .. +mv llc .. +mv valida .. +mv valida.ld .. +mv libstdio.a .. +cd .. +rm -rf llvm-valida-release +rm -rf llvm-valida-v0.3.0-alpha-linux-x86_64.tar.gz \ No newline at end of file diff --git a/valida/scripts_and_tools/valida_verify.sh b/valida/scripts_and_tools/valida_verify.sh new file mode 100755 index 0000000..b00aee0 --- /dev/null +++ b/valida/scripts_and_tools/valida_verify.sh @@ -0,0 +1,3 @@ +TEST_NAME=$1 + +./valida verify ./$TEST_NAME ./$TEST_NAME.proof \ No newline at end of file diff --git a/valida/tests/empty_test.rs b/valida/tests/empty_test.rs new file mode 100644 index 0000000..0ae196c --- /dev/null +++ b/valida/tests/empty_test.rs @@ -0,0 +1,14 @@ +#![no_std] +#![feature(start)] + +use core::panic::PanicInfo; + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} \ No newline at end of file diff --git a/valida/tests/simple_arithmetic_test.rs b/valida/tests/simple_arithmetic_test.rs new file mode 100644 index 0000000..63585d9 --- /dev/null +++ b/valida/tests/simple_arithmetic_test.rs @@ -0,0 +1,23 @@ +#![no_std] +#![feature(start)] + +use core::panic::PanicInfo; + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + let i = 11; + let hept = (5*i*i + 3*i)/2; + if hept == 286 { + return 1; + } + else { + return 0; + } +} + + diff --git a/zkwasm/scripts_and_tools/zkwasm_build.sh b/zkwasm/scripts_and_tools/zkwasm_build.sh new file mode 100755 index 0000000..a08d16e --- /dev/null +++ b/zkwasm/scripts_and_tools/zkwasm_build.sh @@ -0,0 +1,8 @@ +WASM_PATH=$1 + +pushd $WASM_PATH +wasm-pack build --release --out-name test.wasm --out-dir pkg +wasm-opt -Oz -o output.wasm pkg/test.wasm + +rm -rf pkg output params +popd \ No newline at end of file diff --git a/zkwasm/scripts_and_tools/zkwasm_prove.sh b/zkwasm/scripts_and_tools/zkwasm_prove.sh new file mode 100755 index 0000000..b80d253 --- /dev/null +++ b/zkwasm/scripts_and_tools/zkwasm_prove.sh @@ -0,0 +1,5 @@ +WASM_PATH=$1 + +cd zkWasm +./target/release/zkwasm-cli --params ./params testwasm prove --output ./output --wasm $WASM_PATH +cd .. \ No newline at end of file diff --git a/zkwasm/scripts_and_tools/zkwasm_setup.sh b/zkwasm/scripts_and_tools/zkwasm_setup.sh new file mode 100755 index 0000000..1976373 --- /dev/null +++ b/zkwasm/scripts_and_tools/zkwasm_setup.sh @@ -0,0 +1,6 @@ +set -eo + +git clone --recurse-submodules https://github.com/DelphinusLab/zkWasm.git +cd zkWasm +cargo build --release +cd .. \ No newline at end of file diff --git a/zkwasm/scripts_and_tools/zkwasm_setup_circuit.sh b/zkwasm/scripts_and_tools/zkwasm_setup_circuit.sh new file mode 100755 index 0000000..2591bc5 --- /dev/null +++ b/zkwasm/scripts_and_tools/zkwasm_setup_circuit.sh @@ -0,0 +1,5 @@ +WASM_PATH=$1 + +cd zkWasm +cargo run --release -- --params params testwasm setup --host standard -k 18 --wasm $WASM_PATH +cd .. \ No newline at end of file diff --git a/zkwasm/scripts_and_tools/zkwasm_verify.sh b/zkwasm/scripts_and_tools/zkwasm_verify.sh new file mode 100755 index 0000000..fa83a4c --- /dev/null +++ b/zkwasm/scripts_and_tools/zkwasm_verify.sh @@ -0,0 +1,3 @@ +cd zkWasm +./target/release/zkwasm-cli --params ./params testwasm verify --output ./output +cd .. \ No newline at end of file diff --git a/zkwasm/tests/empty_test/Cargo.toml b/zkwasm/tests/empty_test/Cargo.toml new file mode 100644 index 0000000..b2527bc --- /dev/null +++ b/zkwasm/tests/empty_test/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "simple_arithmetic_test" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +zkwasm-rust-sdk = { git = "https://github.com/DelphinusLab/zkWasm-rust.git" } +wasm-bindgen = "0.2.83" \ No newline at end of file diff --git a/zkwasm/tests/empty_test/src/lib.rs b/zkwasm/tests/empty_test/src/lib.rs new file mode 100644 index 0000000..bdefa2e --- /dev/null +++ b/zkwasm/tests/empty_test/src/lib.rs @@ -0,0 +1,7 @@ +#![no_main] + +use zkwasm_rust_sdk::wasm_dbg; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn zkmain() {} diff --git a/zkwasm/tests/mem_alloc_vec_test/Cargo.toml b/zkwasm/tests/mem_alloc_vec_test/Cargo.toml new file mode 100644 index 0000000..1698596 --- /dev/null +++ b/zkwasm/tests/mem_alloc_vec_test/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "mem_alloc_vec_test" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +zkwasm-rust-sdk = { git = "https://github.com/DelphinusLab/zkWasm-rust.git" } +wasm-bindgen = "0.2.83" +memory_allocations = { path = "../../../shared/memory_allocations"} \ No newline at end of file diff --git a/zkwasm/tests/mem_alloc_vec_test/src/lib.rs b/zkwasm/tests/mem_alloc_vec_test/src/lib.rs new file mode 100644 index 0000000..de0793d --- /dev/null +++ b/zkwasm/tests/mem_alloc_vec_test/src/lib.rs @@ -0,0 +1,14 @@ +#![no_main] + +use zkwasm_rust_sdk::wasm_dbg; +use wasm_bindgen::prelude::*; +use memory_allocations::{alloc_vec, push_vec, pop_vec}; + +#[wasm_bindgen] +pub fn zkmain() { + let mut vvec = alloc_vec(); + + push_vec(&mut vvec); + + pop_vec(&mut vvec); +} diff --git a/zkwasm/tests/simple_arithmetic_test/Cargo.toml b/zkwasm/tests/simple_arithmetic_test/Cargo.toml new file mode 100644 index 0000000..b2527bc --- /dev/null +++ b/zkwasm/tests/simple_arithmetic_test/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "simple_arithmetic_test" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +zkwasm-rust-sdk = { git = "https://github.com/DelphinusLab/zkWasm-rust.git" } +wasm-bindgen = "0.2.83" \ No newline at end of file diff --git a/zkwasm/tests/simple_arithmetic_test/src/lib.rs b/zkwasm/tests/simple_arithmetic_test/src/lib.rs new file mode 100644 index 0000000..8e7b81c --- /dev/null +++ b/zkwasm/tests/simple_arithmetic_test/src/lib.rs @@ -0,0 +1,11 @@ +#![no_main] + +use zkwasm_rust_sdk::wasm_dbg; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn zkmain() { + for i in 0..100 { + let hept = (5*i*i - 3*i)/2; + } +}