Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[target.x86_64-pc-windows-msvc]
linker = "rust-lld.exe"
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
18 changes: 18 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ members = [
"examples/merkle-tree/guest",
"examples/hash-bench",
"examples/hash-bench/guest",
"examples/modexp",
"examples/modexp/guest",
"zklean-extractor",
]

Expand Down
12 changes: 12 additions & 0 deletions examples/modexp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "modexp"
version = "0.1.0"
edition = "2021"

[dependencies]
jolt-sdk = { path = "../../jolt-sdk", features = ["host"] }
tracing-subscriber = "0.3"
tracing = "0.1"
guest = { package = "modexp-guest", path = "./guest" }

hex = "0.4.3"
10 changes: 10 additions & 0 deletions examples/modexp/guest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "modexp-guest"
version = "0.1.0"
edition = "2021"

[features]
guest = []

[dependencies]
jolt = { package = "jolt-sdk", path = "../../../jolt-sdk", features = [] }
45 changes: 45 additions & 0 deletions examples/modexp/guest/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#![cfg_attr(feature = "guest", no_std)]

#[jolt::provable(memory_size = 10240, max_trace_length = 65536)]
fn modexp_chain(base: u128, exp: u128, modulus: u128, num_iters: u32) -> u128 {
// Multiply modulo m without overflowing using shift-add multiplication
fn mul_mod(mut a: u128, mut b: u128, m: u128) -> u128 {
let mut res: u128 = 0;
a %= m;

while b > 0 {
if (b & 1) == 1 {
res = (res + a) % m;
}
a = (a << 1) % m;
b >>= 1;
}

res
}

// Compute modular exponentiation: base^exp mod m
fn mod_pow(mut base: u128, mut exp: u128, m: u128) -> u128 {
let mut result: u128 = 1 % m;
base %= m;

while exp > 0 {
if (exp & 1) == 1 {
result = mul_mod(result, base, m);
}
base = mul_mod(base, base, m);
exp >>= 1;
}

result
}

// Proper chained computation: output of each iteration feeds into the next
let mut out: u128 = base;

for _ in 0..num_iters {
out = mod_pow(out, exp, modulus);
}

out
}
31 changes: 31 additions & 0 deletions examples/modexp/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::time::Instant;
use tracing::info;

pub fn main() {
tracing_subscriber::fmt::init();

let target_dir = "/tmp/jolt-guest-targets";
let mut program = guest::compile_modexp_chain(target_dir);

let prover_preprocessing = guest::preprocess_prover_modexp_chain(&mut program);
let verifier_preprocessing =
guest::verifier_preprocessing_from_prover_modexp_chain(&prover_preprocessing);

let prove_modexp_chain = guest::build_prover_modexp_chain(program, prover_preprocessing);
let verify_modexp_chain = guest::build_verifier_modexp_chain(verifier_preprocessing);

let input_base = 123456789u128;
let input_exp = 65537u128;
let input_mod = 1000000007u128;
let iters = 100u32;
let native_output = guest::modexp_chain(input_base, input_exp, input_mod, iters);
let now = Instant::now();

Check warning on line 22 in examples/modexp/src/main.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/jolt/jolt/examples/modexp/src/main.rs
let (output, proof, program_io) = prove_modexp_chain(input_base, input_exp, input_mod, iters);
info!("Prover runtime: {} s", now.elapsed().as_secs_f64());
let is_valid = verify_modexp_chain(input_base, input_exp, input_mod, iters, output, program_io.panic, proof);

assert_eq!(output, native_output, "output mismatch");
info!("output: {}", hex::encode(output.to_be_bytes()));
info!("native_output: {}", hex::encode(native_output.to_be_bytes()));

Check warning on line 29 in examples/modexp/src/main.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/jolt/jolt/examples/modexp/src/main.rs
info!("valid: {is_valid}");
}
26 changes: 26 additions & 0 deletions jolt-core/benches/e2e_profiling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
const CYCLES_PER_SHA3: f64 = 4330.0;
const CYCLES_PER_BTREEMAP_OP: f64 = 1550.0;
const CYCLES_PER_FIBONACCI_UNIT: f64 = 12.0;
const CYCLES_PER_MODEXP: f64 = 50000.0;
const SAFETY_MARGIN: f64 = 0.9; // Use 90% of max trace capacity

/// Calculate number of operations to target a specific cycle count
Expand All @@ -32,6 +33,8 @@
Sha2Chain,
#[strum(serialize = "SHA3 Chain")]
Sha3Chain,
#[strum(serialize = "modexp-chain")]
ModExp,
}

pub fn benchmarks(bench_type: BenchType) -> Vec<(tracing::Span, Box<dyn FnOnce()>)> {
Expand All @@ -41,6 +44,7 @@
BenchType::Sha3 => sha3(),
BenchType::Sha2Chain => sha2_chain(),
BenchType::Sha3Chain => sha3_chain(),
BenchType::ModExp => modexp_chain(),
BenchType::Fibonacci => fibonacci(),
}
}
Expand Down Expand Up @@ -87,6 +91,18 @@
prove_example("sha3-chain-guest", inputs)
}

fn modexp_chain() -> Vec<(tracing::Span, Box<dyn FnOnce()>)> {
// simple u128 inputs for example
let mut inputs = vec![];
// base, exp, modulus
inputs.append(&mut postcard::to_stdvec(&123456789u128).unwrap());

Check warning on line 98 in jolt-core/benches/e2e_profiling.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/jolt/jolt/jolt-core/src/bin/../../benches/e2e_profiling.rs

Check warning on line 98 in jolt-core/benches/e2e_profiling.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/jolt/jolt/jolt-core/benches/e2e_profiling.rs
inputs.append(&mut postcard::to_stdvec(&65537u128).unwrap());
inputs.append(&mut postcard::to_stdvec(&1000000007u128).unwrap());
let iters = scale_to_target_ops(((1 << 24) as f64 * SAFETY_MARGIN) as usize, CYCLES_PER_MODEXP);
inputs.append(&mut postcard::to_stdvec(&iters).unwrap());
prove_example("modexp-guest", inputs)
}

pub fn master_benchmark(
bench_type: BenchType,
bench_scale: usize,
Expand Down Expand Up @@ -129,6 +145,16 @@
]
.concat()
}),
BenchType::ModExp => ("modexp-chain", |target| {
let iterations = scale_to_target_ops(target, CYCLES_PER_MODEXP);
[
postcard::to_stdvec(&123456789u128).unwrap(),
postcard::to_stdvec(&65537u128).unwrap(),
postcard::to_stdvec(&1000000007u128).unwrap(),
postcard::to_stdvec(&iterations).unwrap(),
]
.concat()
}),
BenchType::BTreeMap => ("btreemap", |target| {
postcard::to_stdvec(&scale_to_target_ops(target, CYCLES_PER_BTREEMAP_OP)).unwrap()
}),
Expand Down
6 changes: 3 additions & 3 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[toolchain]
channel = "1.88"
targets = ["riscv32imac-unknown-none-elf", "riscv64imac-unknown-none-elf"]
channel = "nightly"
profile = "minimal"
components = ["cargo", "rustc", "clippy", "rustfmt"]
components = ["rust-src", "cargo", "rustc", "clippy", "rustfmt"]
targets = ["riscv32imac-unknown-none-elf", "riscv64imac-unknown-none-elf"]
Binary file added rustup-init.exe
Binary file not shown.
Loading