-
Notifications
You must be signed in to change notification settings - Fork 130
Description
I'm not able to run pretty simple fibonacci guest function in zkWasm with reasonable performance, meaning I won't be able to run my custom tough app on it.
I've tried to launch that fibonacci program on zkWasm for n > 10000 and it always ends in assertion failed: event_table.0.len() * EVENT_TABLE_ENTRY_ROWS as usize <= self.max_available_rows). I've tried to increase k from default 18 up to 24 and more, and got the same error. For k=25 setup run for more than 20mins, btw.
I understand that wasm is a pretty complex case to zk-verify, but failing calculate fibonacci program means for me no production code could be run on zkWasm. Moreover, other zk-sokutions (such as risk-0) show much better performance. For instance, I'm able to generate proof for n=150000 in 2 mins and verify it for 5ms, compared to my best result with zkWasm with n=1000 with proof generation in 1.5 mins and verification in 170ms.
The question is - is there any way to run the full setup-proof-verify cycle for such a large n like 10000? Is there any parameter other than k which I can change?
Here is the guest function
extern "C" {
fn wasm_input(n: i32) -> i64;
fn log_foreign(value: i64);
}
#[no_mangle]
pub extern "C" fn entrypoint() {
let input: i32 = unsafe { wasm_input(1) } as i32;
let f = fibonacci(input);
unsafe { log_foreign(f as i64) };
}
pub fn fibonacci(n: i32) -> i32 {
let (mut a, mut b) = (0, 1);
for _ in 0..n {
let c = a;
a = b;
b += c;
}
a
}
log_foreign is just a renamed method log added in register_log_foreign.
I've used methods same as cli uses and my host looks like this
fn main() {
let n = 10000;
let wasm_binary = fs::read("res/fib.wasm").expect("No wasm");
let prefix = "zkwasm";
let zkwasm_k = 24;
let function_name = "entrypoint";
let output_dir: PathBuf = "zk".into();
let public_inputs: Vec<u64> = vec![n];
let private_inputs: Vec<u64> = vec![];
let proof_path: PathBuf = "zk/zkwasm.0.transcript.data".into();
/////////// setup
let start = std::time::Instant::now();
let circuit = build_circuit_without_witness(&wasm_binary, function_name);
let params = {
let params_path = &output_dir.join(format!("K{}.params", zkwasm_k));
load_or_build_unsafe_params::<Bn256>(zkwasm_k, Some(params_path))
};
{
let vk_path = &output_dir.join(format!("{}.{}.vkey.data", prefix, 0));
load_or_build_vkey::<Bn256, _>(¶ms, &circuit, Some(vk_path))
};
println!("setup time: {:?}", start.elapsed());
/////////// proof
let start = std::time::Instant::now();
let circuit =
build_circuit_with_witness(&wasm_binary, function_name, &public_inputs, &private_inputs).expect("=== Something went wrong");
let mut public_inputs_fri = public_inputs
.iter()
.map(|v| Fr::from(*v))
.collect::<Vec<_>>()
.clone();
let mut instances = vec![];
instances.append(&mut public_inputs_fri);
circuit.tables.write_json(Some(output_dir.clone()));
let vkey = load_vkey::<Bn256, TestCircuit<_>>(
¶ms,
&output_dir.join(format!("{}.{}.vkey.data", prefix, 0)),
);
load_or_create_proof::<Bn256, _>(
¶ms,
vkey,
circuit.clone(),
&[&instances],
Some(&output_dir.join(format!("{}.{}.transcript.data", prefix, 0))),
TranscriptHash::Poseidon,
false,
);
println!("proof time: {:?}", start.elapsed());
/////////// dry run
build_circuit_with_witness(&wasm_binary, function_name, &public_inputs, &private_inputs);
/////////// verify
let start = std::time::Instant::now();
let public_inputs_size = public_inputs.len() + 1;
let mut public_inputs_fri = public_inputs
.iter()
.map(|v| Fr::from(*v))
.collect::<Vec<_>>()
.clone();
let instances = {
let mut instances = vec![];
instances.append(&mut public_inputs_fri);
instances
};
let vkey = load_vkey::<Bn256, TestCircuit<_>>(
¶ms,
&output_dir.join(format!("{}.{}.vkey.data", prefix, 0)),
);
let proof = load_proof(&proof_path);
let params_verifier: ParamsVerifier<Bn256> = params.verifier(public_inputs_size).unwrap();
let strategy = SingleVerifier::new(¶ms_verifier);
verify_proof(
¶ms_verifier,
&vkey,
strategy,
&[&[&instances]],
&mut PoseidonRead::init(&proof[..]),
)
.expect("Something is incorrect noooooooo");
println!("verify time: {:?}", start.elapsed());
}
I tried using both main and latest v2 branches of zkWasm with default features. I'm running these benchmarks on my M1 mac btw.