mirror of
https://github.com/eth-act/ere.git
synced 2026-02-19 11:54:42 -05:00
20
.github/workflows/test-zkvm-miden.yml
vendored
Normal file
20
.github/workflows/test-zkvm-miden.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Test and clippy Miden
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: ./.github/workflows/test-zkvm.yml
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
with:
|
||||
zkvm: miden
|
||||
toolchain: 1.88.0
|
||||
test_ere_dockerized: false
|
||||
default_features: true
|
||||
test_options: ""
|
||||
746
Cargo.lock
generated
746
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
@@ -4,6 +4,7 @@ members = [
|
||||
"crates/test-utils",
|
||||
# zkVMs
|
||||
"crates/ere-jolt",
|
||||
"crates/ere-miden",
|
||||
"crates/ere-nexus",
|
||||
"crates/ere-openvm",
|
||||
"crates/ere-pico",
|
||||
@@ -57,6 +58,14 @@ jolt = { git = "https://github.com/a16z/jolt.git", rev = "55b9830a3944dde55d33a5
|
||||
jolt-core = { git = "https://github.com/a16z/jolt.git", rev = "55b9830a3944dde55d33a55c42522b81dd49f87a" }
|
||||
jolt-sdk = { git = "https://github.com/a16z/jolt.git", rev = "55b9830a3944dde55d33a55c42522b81dd49f87a" }
|
||||
|
||||
# Miden dependencies
|
||||
miden-assembly = { git = "https://github.com/0xPolygonMiden/miden-vm.git", tag = "v0.17.1" }
|
||||
miden-core = { git = "https://github.com/0xPolygonMiden/miden-vm.git", tag = "v0.17.1" }
|
||||
miden-processor = { git = "https://github.com/0xPolygonMiden/miden-vm.git", tag = "v0.17.1" }
|
||||
miden-prover = { git = "https://github.com/0xPolygonMiden/miden-vm.git", tag = "v0.17.1" }
|
||||
miden-stdlib = { git = "https://github.com/0xPolygonMiden/miden-vm.git", tag = "v0.17.1" }
|
||||
miden-verifier = { git = "https://github.com/0xPolygonMiden/miden-vm.git", tag = "v0.17.1" }
|
||||
|
||||
# Nexus dependencies
|
||||
nexus-sdk = { git = "https://github.com/nexus-xyz/nexus-zkvm.git", tag = "v0.3.4" }
|
||||
|
||||
@@ -90,6 +99,7 @@ test-utils = { path = "crates/test-utils" }
|
||||
ere-cli = { path = "crates/ere-cli", default-features = false }
|
||||
ere-dockerized = { path = "crates/ere-dockerized" }
|
||||
ere-jolt = { path = "crates/ere-jolt", default-features = false }
|
||||
ere-miden = { path = "crates/ere-miden", default-features = false }
|
||||
ere-nexus = { path = "crates/ere-nexus", default-features = false }
|
||||
ere-openvm = { path = "crates/ere-openvm", default-features = false }
|
||||
ere-pico = { path = "crates/ere-pico", default-features = false }
|
||||
|
||||
@@ -14,6 +14,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter"], optional = t
|
||||
|
||||
# Local dependencies
|
||||
ere-jolt = { workspace = true, optional = true }
|
||||
ere-miden = { workspace = true, optional = true }
|
||||
ere-nexus = { workspace = true, optional = true }
|
||||
ere-openvm = { workspace = true, optional = true }
|
||||
ere-pico = { workspace = true, optional = true }
|
||||
@@ -34,6 +35,7 @@ cli = ["dep:clap", "dep:tracing-subscriber"]
|
||||
|
||||
# zkVM
|
||||
jolt = ["dep:ere-jolt"]
|
||||
miden = ["dep:ere-miden"]
|
||||
nexus = ["dep:ere-nexus"]
|
||||
openvm = ["dep:ere-openvm"]
|
||||
pico = ["dep:ere-pico"]
|
||||
|
||||
@@ -10,6 +10,7 @@ const _: () = {
|
||||
if cfg!(feature = "cli") {
|
||||
assert!(
|
||||
(cfg!(feature = "jolt") as u8
|
||||
+ cfg!(feature = "miden") as u8
|
||||
+ cfg!(feature = "nexus") as u8
|
||||
+ cfg!(feature = "openvm") as u8
|
||||
+ cfg!(feature = "pico") as u8
|
||||
@@ -136,6 +137,9 @@ fn compile(guest_path: PathBuf, program_path: PathBuf) -> Result<(), Error> {
|
||||
#[cfg(feature = "jolt")]
|
||||
let program = ere_jolt::JOLT_TARGET.compile(&guest_path);
|
||||
|
||||
#[cfg(feature = "miden")]
|
||||
let program = ere_miden::MIDEN_TARGET.compile(&guest_path);
|
||||
|
||||
#[cfg(feature = "nexus")]
|
||||
let program = ere_nexus::NEXUS_TARGET.compile(&guest_path);
|
||||
|
||||
@@ -232,6 +236,9 @@ fn construct_zkvm(program_path: PathBuf, resource: ProverResourceType) -> Result
|
||||
#[cfg(feature = "jolt")]
|
||||
let zkvm = ere_jolt::EreJolt::new(program, resource);
|
||||
|
||||
#[cfg(feature = "miden")]
|
||||
let zkvm = ere_miden::EreMiden::new(program, resource);
|
||||
|
||||
#[cfg(feature = "nexus")]
|
||||
let zkvm = Ok::<_, Error>(ere_nexus::EreNexus::new(program, resource));
|
||||
|
||||
|
||||
29
crates/ere-miden/Cargo.toml
Normal file
29
crates/ere-miden/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "ere-miden"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bincode = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
zkvm-interface = { workspace = true }
|
||||
|
||||
# Miden
|
||||
miden-assembly = { workspace = true, features = ["std"] }
|
||||
miden-core = { workspace = true, features = ["std"] }
|
||||
miden-processor = { workspace = true, features = ["std"] }
|
||||
miden-prover = { workspace = true, features = ["std"] }
|
||||
miden-stdlib = { workspace = true, features = ["std"] }
|
||||
miden-verifier = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
test-utils = { workspace = true, features = ["host"] }
|
||||
|
||||
[build-dependencies]
|
||||
build-utils.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
5
crates/ere-miden/build.rs
Normal file
5
crates/ere-miden/build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
use build_utils::detect_and_generate_name_and_sdk_version;
|
||||
|
||||
fn main() {
|
||||
detect_and_generate_name_and_sdk_version("miden", "miden-core");
|
||||
}
|
||||
64
crates/ere-miden/src/compile.rs
Normal file
64
crates/ere-miden/src/compile.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use crate::{
|
||||
MIDEN_TARGET, MidenProgram,
|
||||
error::{CompileError, MidenError},
|
||||
};
|
||||
use miden_assembly::Assembler;
|
||||
use miden_core::utils::Serializable;
|
||||
use miden_stdlib::StdLibrary;
|
||||
use std::{fs, path::Path};
|
||||
use zkvm_interface::Compiler;
|
||||
|
||||
impl Compiler for MIDEN_TARGET {
|
||||
type Error = MidenError;
|
||||
type Program = MidenProgram;
|
||||
|
||||
fn compile(&self, guest_directory: &Path) -> Result<Self::Program, Self::Error> {
|
||||
let dir_name = guest_directory
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or(CompileError::InvalidProgramPath)?;
|
||||
|
||||
let entrypoint = format!("{dir_name}.masm");
|
||||
let main_path = guest_directory.join(&entrypoint);
|
||||
if !main_path.exists() {
|
||||
return Err(CompileError::MissingEntrypoint {
|
||||
program_dir: guest_directory.display().to_string(),
|
||||
entrypoint,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
// Compile using Miden assembler
|
||||
let mut assembler = Assembler::default().with_debug_mode(true);
|
||||
assembler
|
||||
.link_dynamic_library(StdLibrary::default())
|
||||
.map_err(|e| CompileError::LoadStdLibrary(e.to_string()))?;
|
||||
|
||||
let source = fs::read_to_string(&main_path).map_err(|e| CompileError::ReadSource {
|
||||
path: main_path.clone(),
|
||||
source: e,
|
||||
})?;
|
||||
|
||||
let program = assembler
|
||||
.assemble_program(&source)
|
||||
.map_err(|e| CompileError::AssemblyCompilation(e.to_string()))?;
|
||||
|
||||
Ok(MidenProgram {
|
||||
program_bytes: program.to_bytes(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use test_utils::host::testing_guest_directory;
|
||||
use zkvm_interface::Compiler;
|
||||
|
||||
#[test]
|
||||
fn test_compile() {
|
||||
let guest_directory = testing_guest_directory("miden", "fib");
|
||||
let program = MIDEN_TARGET.compile(&guest_directory).unwrap();
|
||||
assert!(!program.program_bytes.is_empty());
|
||||
}
|
||||
}
|
||||
77
crates/ere-miden/src/error.rs
Normal file
77
crates/ere-miden/src/error.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use miden_core::utils::DeserializationError;
|
||||
use miden_processor::ExecutionError;
|
||||
use miden_verifier::VerificationError;
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
use zkvm_interface::zkVMError;
|
||||
|
||||
impl From<MidenError> for zkVMError {
|
||||
fn from(value: MidenError) -> Self {
|
||||
zkVMError::Other(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MidenError {
|
||||
#[error(transparent)]
|
||||
Compile(#[from] CompileError),
|
||||
#[error(transparent)]
|
||||
Execute(#[from] ExecuteError),
|
||||
#[error(transparent)]
|
||||
Prove(#[from] ProveError),
|
||||
#[error(transparent)]
|
||||
Verify(#[from] VerifyError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompileError {
|
||||
#[error("Invalid program directory name")]
|
||||
InvalidProgramPath,
|
||||
#[error("Entrypoint '{entrypoint}' not found in {program_dir}")]
|
||||
MissingEntrypoint {
|
||||
program_dir: String,
|
||||
entrypoint: String,
|
||||
},
|
||||
#[error("Failed to read assembly source at {path}")]
|
||||
ReadSource {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("Miden assembly compilation failed: {0}")]
|
||||
AssemblyCompilation(String),
|
||||
#[error("Failed to load Miden standard library: {0}")]
|
||||
LoadStdLibrary(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ExecuteError {
|
||||
#[error("Miden execution failed")]
|
||||
Execution(#[from] ExecutionError),
|
||||
#[error("Invalid input format: {0}")]
|
||||
InvalidInput(String),
|
||||
#[error("Serialization failed")]
|
||||
Serialization(#[from] bincode::Error),
|
||||
#[error("Failed to deserialize Miden program")]
|
||||
ProgramDeserialization(#[from] DeserializationError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ProveError {
|
||||
#[error("Miden proving failed")]
|
||||
Proving(#[from] ExecutionError),
|
||||
#[error("Invalid input format: {0}")]
|
||||
InvalidInput(String),
|
||||
#[error("Serialization failed")]
|
||||
Serialization(#[from] bincode::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum VerifyError {
|
||||
#[error("Miden verification failed")]
|
||||
Verification(#[from] VerificationError),
|
||||
#[error("Proof or associated data deserialization failed")]
|
||||
MidenDeserialization(#[from] DeserializationError),
|
||||
#[error("Proof bundle deserialization failed")]
|
||||
BundleDeserialization(#[from] bincode::Error),
|
||||
}
|
||||
52
crates/ere-miden/src/io.rs
Normal file
52
crates/ere-miden/src/io.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use crate::error::{ExecuteError, MidenError};
|
||||
use miden_processor::{AdviceInputs, StackInputs, StackOutputs};
|
||||
use zkvm_interface::{Input, InputItem, PublicValues};
|
||||
|
||||
/// Returns Miden compatible inputs from `zkvm_interface::Input`.
|
||||
///
|
||||
/// All inputs are serialized and concatenated, then placed onto the advice tape.
|
||||
/// The stack is left empty.
|
||||
pub fn generate_miden_inputs(inputs: &Input) -> Result<(StackInputs, AdviceInputs), MidenError> {
|
||||
let mut all_bytes = Vec::new();
|
||||
|
||||
for item in inputs.iter() {
|
||||
match item {
|
||||
InputItem::Object(obj) => {
|
||||
bincode::serialize_into(&mut all_bytes, &**obj)
|
||||
.map_err(ExecuteError::Serialization)?;
|
||||
}
|
||||
InputItem::SerializedObject(bytes) | InputItem::Bytes(bytes) => {
|
||||
all_bytes.extend_from_slice(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the byte stream into u64 words for the Miden VM.
|
||||
let advice_words: Vec<u64> = {
|
||||
let mut words: Vec<u64> = all_bytes
|
||||
.chunks_exact(8)
|
||||
.map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap()))
|
||||
.collect();
|
||||
|
||||
let remainder = all_bytes.chunks_exact(8).remainder();
|
||||
if !remainder.is_empty() {
|
||||
let mut last_chunk = [0u8; 8];
|
||||
last_chunk[..remainder.len()].copy_from_slice(remainder);
|
||||
words.push(u64::from_le_bytes(last_chunk));
|
||||
}
|
||||
|
||||
words
|
||||
};
|
||||
|
||||
let advice_inputs = AdviceInputs::default()
|
||||
.with_stack_values(advice_words)
|
||||
.map_err(|e| ExecuteError::InvalidInput(e.to_string()))?;
|
||||
|
||||
Ok((StackInputs::default(), advice_inputs))
|
||||
}
|
||||
|
||||
// Convert Miden stack outputs to public values
|
||||
pub fn outputs_to_public_values(outputs: &StackOutputs) -> Result<PublicValues, bincode::Error> {
|
||||
let output_ints: Vec<u64> = outputs.iter().map(|f| f.as_int()).collect();
|
||||
bincode::serialize(&output_ints)
|
||||
}
|
||||
245
crates/ere-miden/src/lib.rs
Normal file
245
crates/ere-miden/src/lib.rs
Normal file
@@ -0,0 +1,245 @@
|
||||
pub mod compile;
|
||||
pub mod error;
|
||||
pub mod io;
|
||||
|
||||
use self::error::{ExecuteError, MidenError, VerifyError};
|
||||
use self::io::{generate_miden_inputs, outputs_to_public_values};
|
||||
use miden_core::{
|
||||
Program,
|
||||
utils::{Deserializable, Serializable},
|
||||
};
|
||||
use miden_processor::{
|
||||
DefaultHost, ExecutionOptions, ProgramInfo, StackInputs, StackOutputs, execute as miden_execute,
|
||||
};
|
||||
use miden_prover::{ExecutionProof, ProvingOptions, prove as miden_prove};
|
||||
use miden_stdlib::StdLibrary;
|
||||
use miden_verifier::verify as miden_verify;
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
use std::{env, io::Read, time::Instant};
|
||||
use zkvm_interface::{
|
||||
Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType, PublicValues,
|
||||
zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct MIDEN_TARGET;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct MidenProgram {
|
||||
pub program_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct MidenProofBundle {
|
||||
stack_inputs: Vec<u8>,
|
||||
stack_outputs: Vec<u8>,
|
||||
proof: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct EreMiden {
|
||||
program: Program,
|
||||
}
|
||||
|
||||
impl EreMiden {
|
||||
pub fn new(program: MidenProgram, _resource: ProverResourceType) -> Result<Self, MidenError> {
|
||||
let program = Program::read_from_bytes(&program.program_bytes)
|
||||
.map_err(ExecuteError::ProgramDeserialization)
|
||||
.map_err(MidenError::Execute)?;
|
||||
|
||||
Ok(Self { program })
|
||||
}
|
||||
|
||||
fn setup_host() -> Result<DefaultHost, MidenError> {
|
||||
let mut host = DefaultHost::default();
|
||||
|
||||
host.load_library(&StdLibrary::default())
|
||||
.map_err(ExecuteError::Execution)
|
||||
.map_err(MidenError::Execute)?;
|
||||
|
||||
Ok(host)
|
||||
}
|
||||
}
|
||||
|
||||
impl zkVM for EreMiden {
|
||||
fn execute(&self, inputs: &Input) -> Result<(PublicValues, ProgramExecutionReport), zkVMError> {
|
||||
let (stack_inputs, advice_inputs) = generate_miden_inputs(inputs)?;
|
||||
let mut host = Self::setup_host()?;
|
||||
|
||||
let start = Instant::now();
|
||||
let trace = miden_execute(
|
||||
&self.program,
|
||||
stack_inputs,
|
||||
advice_inputs,
|
||||
&mut host,
|
||||
ExecutionOptions::default(),
|
||||
)
|
||||
.map_err(|e| MidenError::Execute(e.into()))?;
|
||||
|
||||
let public_values = outputs_to_public_values(trace.stack_outputs())
|
||||
.map_err(|e| MidenError::Execute(e.into()))?;
|
||||
|
||||
let report = ProgramExecutionReport {
|
||||
total_num_cycles: trace.trace_len_summary().main_trace_len() as u64,
|
||||
execution_duration: start.elapsed(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok((public_values, report))
|
||||
}
|
||||
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
|
||||
let (stack_inputs, advice_inputs) = generate_miden_inputs(inputs)?;
|
||||
let mut host = Self::setup_host()?;
|
||||
|
||||
let start = Instant::now();
|
||||
let proving_options = ProvingOptions::with_96_bit_security(env::var("MIDEN_DEBUG").is_ok());
|
||||
|
||||
let (stack_outputs, proof) = miden_prove(
|
||||
&self.program,
|
||||
stack_inputs.clone(),
|
||||
advice_inputs,
|
||||
&mut host,
|
||||
proving_options,
|
||||
)
|
||||
.map_err(|e| MidenError::Prove(e.into()))?;
|
||||
|
||||
let public_values =
|
||||
outputs_to_public_values(&stack_outputs).map_err(|e| MidenError::Prove(e.into()))?;
|
||||
|
||||
let bundle = MidenProofBundle {
|
||||
stack_inputs: stack_inputs.to_bytes(),
|
||||
stack_outputs: stack_outputs.to_bytes(),
|
||||
proof: proof.to_bytes(),
|
||||
};
|
||||
|
||||
let proof_bytes = bincode::serialize(&bundle).map_err(|e| MidenError::Prove(e.into()))?;
|
||||
|
||||
Ok((
|
||||
public_values,
|
||||
proof_bytes,
|
||||
ProgramProvingReport::new(start.elapsed()),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
let bundle: MidenProofBundle = bincode::deserialize(proof)
|
||||
.map_err(|e| MidenError::Verify(VerifyError::BundleDeserialization(e)))?;
|
||||
|
||||
let program_info: ProgramInfo = self.program.clone().into();
|
||||
|
||||
let stack_inputs = StackInputs::read_from_bytes(&bundle.stack_inputs)
|
||||
.map_err(|e| MidenError::Verify(VerifyError::MidenDeserialization(e)))?;
|
||||
let stack_outputs = StackOutputs::read_from_bytes(&bundle.stack_outputs)
|
||||
.map_err(|e| MidenError::Verify(VerifyError::MidenDeserialization(e)))?;
|
||||
let execution_proof = ExecutionProof::from_bytes(&bundle.proof)
|
||||
.map_err(|e| MidenError::Verify(VerifyError::MidenDeserialization(e)))?;
|
||||
|
||||
miden_verify(
|
||||
program_info,
|
||||
stack_inputs,
|
||||
stack_outputs.clone(),
|
||||
execution_proof,
|
||||
)
|
||||
.map_err(|e| MidenError::Verify(e.into()))?;
|
||||
|
||||
Ok(outputs_to_public_values(&stack_outputs)
|
||||
.map_err(|e| MidenError::Verify(VerifyError::BundleDeserialization(e)))?)
|
||||
}
|
||||
|
||||
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, reader: R) -> Result<T, zkVMError> {
|
||||
bincode::deserialize_from(reader).map_err(|e| MidenError::Execute(e.into()).into())
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
NAME
|
||||
}
|
||||
|
||||
fn sdk_version(&self) -> &'static str {
|
||||
SDK_VERSION
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use test_utils::host::testing_guest_directory;
|
||||
use zkvm_interface::Compiler;
|
||||
|
||||
fn load_miden_program(guest_name: &str) -> MidenProgram {
|
||||
MIDEN_TARGET
|
||||
.compile(&testing_guest_directory("miden", guest_name))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prove_and_verify_add() {
|
||||
let program = load_miden_program("add");
|
||||
let zkvm = EreMiden::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
let const_a = 2518446814u64;
|
||||
let const_b = 1949327098u64;
|
||||
let expected_sum = const_a + const_b;
|
||||
|
||||
let mut inputs = Input::new();
|
||||
inputs.write(const_a);
|
||||
inputs.write(const_b);
|
||||
|
||||
// Prove
|
||||
let (prover_public_values, proof, _) = zkvm.prove(&inputs).unwrap();
|
||||
|
||||
// Verify
|
||||
let verifier_public_values = zkvm.verify(&proof).unwrap();
|
||||
assert_eq!(prover_public_values, verifier_public_values,);
|
||||
|
||||
// Assert output
|
||||
let output: Vec<u64> = zkvm
|
||||
.deserialize_from(verifier_public_values.as_slice())
|
||||
.unwrap();
|
||||
assert_eq!(output[0], expected_sum);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prove_and_verify_fib() {
|
||||
let program = load_miden_program("fib");
|
||||
let zkvm = EreMiden::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
let n_iterations = 50u64;
|
||||
let expected_fib = 12_586_269_025u64;
|
||||
|
||||
let mut inputs = Input::new();
|
||||
inputs.write(0u64);
|
||||
inputs.write(1u64);
|
||||
inputs.write(n_iterations);
|
||||
|
||||
// Prove
|
||||
let (prover_public_values, proof, _) = zkvm.prove(&inputs).unwrap();
|
||||
|
||||
// Verify
|
||||
let verifier_public_values = zkvm.verify(&proof).unwrap();
|
||||
assert_eq!(prover_public_values, verifier_public_values,);
|
||||
|
||||
// Assert output
|
||||
let output: Vec<u64> = zkvm
|
||||
.deserialize_from(verifier_public_values.as_slice())
|
||||
.unwrap();
|
||||
assert_eq!(output[0], expected_fib);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_inputs() {
|
||||
let program = load_miden_program("add");
|
||||
let zkvm = EreMiden::new(program, ProverResourceType::Cpu).unwrap();
|
||||
|
||||
let empty_inputs = Input::new();
|
||||
assert!(zkvm.execute(&empty_inputs).is_err());
|
||||
|
||||
let mut insufficient_inputs = Input::new();
|
||||
insufficient_inputs.write(5u64);
|
||||
assert!(zkvm.execute(&insufficient_inputs).is_err());
|
||||
}
|
||||
}
|
||||
19
docker/miden/Dockerfile
Normal file
19
docker/miden/Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
||||
ARG BASE_IMAGE_TAG=ere-base:latest
|
||||
|
||||
FROM ${BASE_IMAGE_TAG}
|
||||
|
||||
# Set default toolchain to MSRV of Miden
|
||||
RUN rustup default 1.88.0
|
||||
|
||||
# Miden Configuration
|
||||
ENV MIDEN_VERSION="v0.17.1" \
|
||||
MIDEN_TOOLCHAIN_VERSION="1.88.0"
|
||||
|
||||
# Miden CLI Installation
|
||||
# COPY --chmod=755 scripts/sdk_installers/install_miden_sdk.sh /tmp/
|
||||
# RUN /tmp/install_miden_sdk.sh && rm /tmp/install_miden_sdk.sh
|
||||
|
||||
# Verify
|
||||
# RUN miden-vm --version
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
12
tests/miden/add/add.masm
Normal file
12
tests/miden/add/add.masm
Normal file
@@ -0,0 +1,12 @@
|
||||
# Adds two numbers from advice stack
|
||||
# Input: advice_stack contains second_number, first_number
|
||||
use.std::sys
|
||||
|
||||
begin
|
||||
adv_push.1
|
||||
adv_push.1
|
||||
|
||||
add
|
||||
|
||||
exec.sys::truncate_stack
|
||||
end
|
||||
29
tests/miden/fib/fib.masm
Normal file
29
tests/miden/fib/fib.masm
Normal file
@@ -0,0 +1,29 @@
|
||||
# Fibonacci
|
||||
# Reads three u64 values from advice stack: fib_a, fib_b, n
|
||||
# Returns nth fibonacci number
|
||||
use.std::sys
|
||||
|
||||
begin
|
||||
# Read inputs from advice stack
|
||||
adv_push.1 # fib_a
|
||||
adv_push.1 # fib_b
|
||||
adv_push.1 # n
|
||||
|
||||
# Compute fibonacci
|
||||
dup neq.0
|
||||
while.true
|
||||
movdn.2
|
||||
dup.1
|
||||
add
|
||||
swap
|
||||
movup.2
|
||||
sub.1
|
||||
dup neq.0
|
||||
end
|
||||
|
||||
# Drop counter and one of the fibonacci values
|
||||
drop
|
||||
drop
|
||||
|
||||
exec.sys::truncate_stack
|
||||
end
|
||||
Reference in New Issue
Block a user