Skip to content

zkVM Zisk Integration#475

Merged
povi merged 1 commit intograndinetech:developfrom
jimmychu0807:feature/zkvm-zisk
Jan 2, 2026
Merged

zkVM Zisk Integration#475
povi merged 1 commit intograndinetech:developfrom
jimmychu0807:feature/zkvm-zisk

Conversation

@jimmychu0807
Copy link
Copy Markdown
Contributor

@jimmychu0807 jimmychu0807 commented Nov 12, 2025

@ArtiomTr @povi
Zisk integration is completed in this PR.
sha2 and bls12_381 is pointing to my own repository, so you may want to review and merge these two PRs:

and then update Cargo.toml pointing back to grandinetech repo.

@jimmychu0807 jimmychu0807 force-pushed the feature/zkvm-zisk branch 2 times, most recently from 99e585f to 0c3dddc Compare December 4, 2025 06:00
@jimmychu0807 jimmychu0807 marked this pull request as ready for review December 4, 2025 06:00
Cargo.toml Outdated
Comment on lines +301 to +305
# bls12_381 = { git = 'https://github.com/grandinetech/universal-precompiles.git', tag = 'bls12_381-6bb9695-up.1' }
# bls12_381 = { package = "sp1_bls12_381", path = "../zisk-bls12_381" }
# bls12_381 = { path = "../grandine-universal-precompiles-bls12_381" }
bls12_381 = { git = 'https://github.com/jimmychu0807/grandine-universal-precompiles.git', branch = 'jc/zkvm-zisk-bls12_381' }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

putting here this comment just as a reminder to change it once precompiles are merged

Comment on lines +57 to +63
let VMGuestInput {
config,
state_ssz,
block_ssz,
cache_ssz,
phase_bytes,
} = bincode::deserialize(input).unwrap();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use double encoding here -- you're currently serializing state&block&cache into SSZ, and then serialize SSZ bytes into bincode. Instead, you can pass those 3 directly as bytes into zkvm, the same as with other backends.

Copy link
Copy Markdown
Contributor Author

@jimmychu0807 jimmychu0807 Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I found, ziskemu only takes input in a file format, not bytes directly.

So the issue becomes, I either not using bincode and add byte separators and then concatenate the 5 inputs myself, or using bincode and let the lib handles this for me.

For ref, input is serialized here:
https://github.com/grandinetech/grandine/pull/475/changes#r2625605370

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I found, ziskemu only takes input in a file format, not bytes directly.

Yeah, but you still can write bytes directly into file, so in that sense, it accepts bytes as input.

So the issue becomes, I either not using bincode and add byte separators and then concatenate the 5 inputs myself, or using bincode and let the lib handles this for me.

I just see it as with every other backend - you just read directly from byte array. As far as I remember, when we tried using bincode instead of ssz, we saw pretty large performance decrease. But you can try both approaches and compare, which one performs better:

  • Using bincode (your current implementation).
  • Doing as every other vm - reading 4 usize's from byte stream, then reading 4 slices with appropriate lengths, something like so:
    let mut buffer = [0u8; size_of::<usize>()];
    input.read_exact(&mut buffer)?;
    let state_ssz_len = usize::from_be_bytes(&v);
    
    // same for block_ssz_len, cache_ssz_len and phase_bytes_len
    
    let mut state_ssz = vec![0u8; state_ssz_len];
    input.read_exact(&mut state_ssz)?;
    
    // same for block_ssz, cache_ssz and phase_bytes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated this section of code to plainly write bytes to a file and updated the guest code to read bytes from the file.

This is indeed faster than using bincode as it is simpler.


// Gather back the last set_output() from the VM guest output.
// Note: maybe able to read from the output dir the public output.
let state_root = Self::collect_result(&output)?;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to keep this line here. Because I have never able to execute to this point actually (prove mode). So keeping this line let future dev know they could either read from the output dir (I'm not sure what's the output file name), or collect the result from the screen output.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can just comment out whole guest program, keep empty main, and then run prove mode locally, so that you can find where file is located.

It is better to check proving mode before merging, because after preparing all zkvms, we want to conduct some kind of report. So we will likely hand out code to zisk team and ask them to run proving on their rig.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion. I am able to create the proof file. I realize Zisk proof mode doesn't output the result, so I have to run self.execute() first to get the result and the proof output.

Have also updated Proof::verify() and Proof::save() methods accordingly with the output path.

@jimmychu0807
Copy link
Copy Markdown
Contributor Author

jimmychu0807 commented Dec 17, 2025

@ArtiomTr I have handled your comments above to the best of my knowledge. I see two remaining issues to discuss:

Copy link
Copy Markdown
Collaborator

@ArtiomTr ArtiomTr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, few changes needed. Also, looks like pipeline currently fails? This needs to be fixed before merging

Comment on lines +57 to +63
let VMGuestInput {
config,
state_ssz,
block_ssz,
cache_ssz,
phase_bytes,
} = bincode::deserialize(input).unwrap();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I found, ziskemu only takes input in a file format, not bytes directly.

Yeah, but you still can write bytes directly into file, so in that sense, it accepts bytes as input.

So the issue becomes, I either not using bincode and add byte separators and then concatenate the 5 inputs myself, or using bincode and let the lib handles this for me.

I just see it as with every other backend - you just read directly from byte array. As far as I remember, when we tried using bincode instead of ssz, we saw pretty large performance decrease. But you can try both approaches and compare, which one performs better:

  • Using bincode (your current implementation).
  • Doing as every other vm - reading 4 usize's from byte stream, then reading 4 slices with appropriate lengths, something like so:
    let mut buffer = [0u8; size_of::<usize>()];
    input.read_exact(&mut buffer)?;
    let state_ssz_len = usize::from_be_bytes(&v);
    
    // same for block_ssz_len, cache_ssz_len and phase_bytes_len
    
    let mut state_ssz = vec![0u8; state_ssz_len];
    input.read_exact(&mut state_ssz)?;
    
    // same for block_ssz, cache_ssz and phase_bytes


// Gather back the last set_output() from the VM guest output.
// Note: maybe able to read from the output dir the public output.
let state_root = Self::collect_result(&output)?;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can just comment out whole guest program, keep empty main, and then run prove mode locally, so that you can find where file is located.

It is better to check proving mode before merging, because after preparing all zkvms, we want to conduct some kind of report. So we will likely hand out code to zisk team and ask them to run proving on their rig.

Copy link
Copy Markdown
Collaborator

@ArtiomTr ArtiomTr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good, however, when I try to prove locally, I get this error:

Error: Failed to copy file from "/home/necolt/workspace/grandine/zkvm/guest/zisk/artifacts/vadcop_final_proof.compressed.bin" to "/home/necolt/workspace/grandine/zkvm/host/proof.bin"

Caused by:
    No such file or directory (os error 2)

And indeed, I don't have such file:

/zkvm/guest/zisk/artifacts/vadcop_final_proof.compressed.bin

Contents of whole artifacts directory:

input.bin
result.json
vadcop_final_proof.bin

Maybe zisk won't generate .compressed proof by default?

Comment on lines +51 to +52
let _ = fs::copy(&proof_path, path.as_ref())
.map_err(|e| anyhow!("Copy file failed. stderr:\n{}", e.to_string()))?;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can make this error a bit nicer, by providing a bit more context:

Suggested change
let _ = fs::copy(&proof_path, path.as_ref())
.map_err(|e| anyhow!("Copy file failed. stderr:\n{}", e.to_string()))?;
fs::copy(&proof_path, path.as_ref()).context(format!(
"Failed to copy file from {proof_path:?} to {:?}",
path.as_ref()
))?;

Mentioning this, because I've got this error:

Error: Copy file failed. stderr:
No such file or directory (os error 2)

As you can see, it's not very helpful :). With suggested change, it looks like:

Error: Failed to copy file from "/home/necolt/workspace/grandine/zkvm/guest/zisk/artifacts/vadcop_final_proof.compressed.bin" to "/home/necolt/workspace/grandine/zkvm/host/proof.bin"

Caused by:
    No such file or directory (os error 2)

Which is much nicer in my opinion

}

fn get_guest_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../guest/zisk")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to make path a bit nicer, you can do:

Suggested change
Path::new(env!("CARGO_MANIFEST_DIR")).join("../guest/zisk")
Path::new(env!("CARGO_MANIFEST_DIR")).parent().expect("project cannot be at root directory").join("guest/zisk")

this way paths will look better when trying to print them:

instead of:

/<project-path>/grandine/zkvm/host/../guest/zisk

you'll see:

/<project-path>/grandine/zkvm/guest/zisk

@jimmychu0807
Copy link
Copy Markdown
Contributor Author

@ArtiomTr
Just realized Zisk no longer output compressed proof by default, and there is no CLI argument to specify that. We can do that with the SDK by converting a raw proof into compressed proof. Since I am using CLI to drive all executions here, let's drop this compressed proof and just deal with the ordinary proof output.

I have updated the rest of the PRs based on the comment and squashed all commits into one.

Copy link
Copy Markdown
Collaborator

@ArtiomTr ArtiomTr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

"serde",
"serde_utils",
"sha2 0.10.9 (git+https://github.com/grandinetech/universal-precompiles.git?tag=sha2-v0.10.9-up.1)",
"sha2 0.10.9 (git+https://github.com/jimmychu0807/grandine-universal-precompiles.git?branch=jc%2Fzkvm-zisk-sha2)",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't include cryptography (or other) dependencies from a personal repo, thanks.

Copy link
Copy Markdown
Contributor Author

@jimmychu0807 jimmychu0807 Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@povi Nice catch! I wasn't aware of that.

Now I have rebuilt the guest code of pico, sp1, and ziren and have the corresponding Cargo.lock updated.

Co-authored-by: Artiom Tretjakovas <hi@sirse.dev>
@povi povi merged commit 0418ecd into grandinetech:develop Jan 2, 2026
1 check passed
@jimmychu0807 jimmychu0807 deleted the feature/zkvm-zisk branch January 2, 2026 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants