Skip to content

Commit

Permalink
create E2E simple example
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelDkhn committed Jan 7, 2025
1 parent 4d79601 commit c5345a2
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 23 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
**/target
.DS_Store
repomix-output.txt
repomix-output.txt
**/*.bin
40 changes: 25 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["crates/air", "crates/compiler"]
members = ["crates/air", "crates/compiler", "examples/simple"]

[workspace.package]
version = "0.0.1"
Expand All @@ -10,4 +10,5 @@ license = "MIT"

[workspace.dependencies]
stwo-prover = { git = "https://github.com/starkware-libs/stwo.git", rev = "36b17ac" }
luminal = { git = "https://github.com/raphaelDkhn/luminal.git", rev = "0309ea4" }
rayon = "1.10.0"
8 changes: 4 additions & 4 deletions crates/compiler/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
[package]
name = "compiler"
name = "luminair_compiler"
version.workspace = true
edition.workspace = true
repository.workspace = true
license.workspace = true

[dependencies]
stwo-prover.workspace =true
luminal = { git = "https://github.com/raphaelDkhn/luminal.git", rev = "0309ea4" }
stwo-prover.workspace = true
luminal.workspace = true
rayon.workspace = true
luminair_air = {path = "../air"}
luminair_air = { path = "../air" }

[dev-dependencies]
luminal_cpu = { git = "https://github.com/raphaelDkhn/luminal.git", rev = "0309ea4" }
Expand Down
13 changes: 12 additions & 1 deletion crates/compiler/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
use std::path::PathBuf;

use luminal::prelude::GenericCompiler;
use prim::PrimitiveCompiler;

pub mod data;
pub mod fixed_point;
pub mod prim;

#[cfg(test)]
mod tests;

pub type StwoCompiler<'a> = (prim::PrimitiveCompiler,);
pub type StwoCompiler = (prim::PrimitiveCompiler,);

pub fn init_compiler(trace_registry: Option<PathBuf>) -> (GenericCompiler, StwoCompiler) {
let config = prim::Config { trace_registry };
let primitive_compiler = PrimitiveCompiler::new(config);
(GenericCompiler::default(), (primitive_compiler,))
}
2 changes: 1 addition & 1 deletion crates/compiler/src/prim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use luminair_air::{
utils::calculate_log_size,
};

#[derive(Debug, Default)]
#[derive(Default)]
pub struct PrimitiveCompiler {
config: Arc<Config>,
}
Expand Down
12 changes: 12 additions & 0 deletions examples/simple/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "simple"
version.workspace = true
edition.workspace = true
repository.workspace = true
license.workspace = true

[dependencies]
stwo-prover.workspace = true
luminal.workspace = true
luminair_air = { path = "../../crates/air" }
luminair_compiler = { path = "../../crates/compiler" }
92 changes: 92 additions & 0 deletions examples/simple/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use std::{fs, path::PathBuf};

use luminair_air::{ops::add::TensorAdd, serde::SerializableTrace, Circuit};
use luminair_compiler::{data::GraphOutputConverter, init_compiler};
use luminal::prelude::*;
use stwo_prover::core::{backend::simd::SimdBackend, vcs::blake2_merkle::Blake2sMerkleChannel};

// =============== Example Overview ===============
// This example demonstrates how to:
// 1. Build a computation graph with tensor operations.
// 2. Compile and execute the graph while generating execution traces.
// 3. Generate ZK proofs from those traces with Stwo prover.
// 4. Verify the proofs to ensure computation integrity.

fn main() -> Result<(), Box<dyn std::error::Error>> {
// =============== Step 1: Building the Graph ===============
// Create a new computation graph that will hold our tensor operations
let mut cx = Graph::new();

// Create three 2x2 tensors initialized with test data
// In a real application, these could be input features, weights, etc.
let a = cx.tensor((2, 2)).set(vec![1., 2., 3., 4.]);
let b = cx.tensor((2, 2)).set(vec![10., 20., 30., 40.]);
let w = cx.tensor((2, 2)).set(vec![-1., -1., -1., -1.]);

// Define the computation operations:
// 1. First add tensors a and b
let c = a + b;
// 2. Add tensor w to the result and mark it for retrieval
let mut d = (c + w).retrieve();

// Note: No computation happens yet! We've only built a graph of operations.
// This lazy execution model allows for optimization before running.

// =============== Step 2: Compilation & Execution ===============
// Set up a directory to store execution traces
let trace_registry = PathBuf::from("./traces");

// Initialize LuminAIR's StwoCompiler with the trace registry
// This compiler will transform our high-level operations into
// a format suitable for generating trace of executions.
let compiler = init_compiler(Some(trace_registry.clone()));

// Compile the graph - this transforms operations and prepares for execution
cx.compile(compiler, &mut d);

// Optional: Visualize the computation graph
// cx.display();

// Execute the graph - this is where actual computation happens
// During execution, traces will be generated and stored for each operation
cx.execute();

// Retrieve the final result as f32 values
let result = cx.get_final_output(d.id);
println!("result: {:?}", result);

// =============== Step 3: Proving & Verification ===============
// For each trace file generated during execution:
// 1. Load the trace
// 2. Generate a ZK proof
// 3. Verify the proof
//
// Note: Currently we prove and verify traces independently.
// Future versions will use proof recursion to combine them.
for entry in fs::read_dir(trace_registry)? {
let entry = entry?;
let path = entry.path();

if path.is_file() && path.extension().map_or(false, |ext| ext == "bin") {
// Load and convert the trace to SIMD format.
let loaded = SerializableTrace::load(path.to_str().unwrap())?;
let trace = loaded.to_trace::<SimdBackend>();

let config = Default::default();
println!("==================");

// Generate a proof for this trace
println!("Proving trace file: {:?} 🏗️", path);
let (components, proof) = TensorAdd::prove::<Blake2sMerkleChannel>(&trace, config);
println!("Proving was successful ✅");

// Verify the proof to ensure computation integrity
println!("Verifying proof 🕵️");
TensorAdd::verify::<Blake2sMerkleChannel>(components, proof, config)
.unwrap_or_else(|_| panic!("Verification failed for trace {:?}", path));
println!("Verication was successful 🎉");
}
}

Ok(())
}

0 comments on commit c5345a2

Please sign in to comment.