a16z / jolt

The simplest and most extensible zkVM. Fast and fully open source from a16z crypto and friends. ⚡
https://jolt.a16zcrypto.com
MIT License
653 stars 137 forks source link

How to specify the verification key and public / private inputs #369

Closed imikushin closed 4 months ago

imikushin commented 4 months ago

RV32IJoltVM::verify requires a JoltPreprocessing, which I guess is easy to obtain by calling RV32IJoltVM::preprocess with the bytecode of the program we're tryin to verify. Is this the recommended way at the moment?

Also, how do we specify public inputs when verifying a function run?

For example, we have a guest function:

#[jolt::provable]
fn correct_factors(p: i32, a: i32, b: i32) -> bool {
    p == a * b
}

In this example, I'd like to specify the value of p as public input when verifying this function for a set of arguments, some of which I'd like to keep private (a and b).

I can't figure if this is currently possible. This is the flow as I currently see it:

    let p = 15;
    let (a, b) = (5, 3);

    // Preprocess the program, prove its execution.
    let (prog, preproc) = guest::preprocess_correct_factors();
    let (output, proof) = guest::prove_correct_factors(prog, preproc.clone(), p, a, b);

    // Transmit the proof to the verifier
    // ...

    // Load the proof
    // ...

    // Preprocess the program on the verifier side, verify the proof.
    let (_, preproc) = guest::preprocess_correct_factors();
    let is_valid = RV32IJoltVM::verify(preproc, proof.proof, proof.commitments).is_ok();

What I can't see is how I can verify the proof against the particular public input value (p == 15)

imikushin commented 4 months ago

Okay, found the way to get all inputs and outputs from the proof, and also a bug!

Adding these lines just after generating the proof:

    println!("proof.proof.program_io.inputs: {:?}", &proof.proof.program_io.inputs);
    println!("proof.proof.program_io.outputs: {:?}", &proof.proof.program_io.outputs);

prints out:

proof.proof.program_io.inputs: [30, 10, 6]
proof.proof.program_io.outputs: [1]

So, questions:

  1. Should it print [15, 5, 3] instead of [30, 10, 6]? (30 != 10 * 6)
  2. How does the proof still verify successfully, even though these are clearly the wrong numbers?
  3. Is there a way to hide some of the inputs?

Pushed the above example here: https://github.com/imikushin/jolt/commit/0ca5de126f8569f89064b45ceb3d9cd136c5b9df

moodlezoup commented 4 months ago

Hi Ivan,

Good question, and thanks for flagging. Currently there is no way to hide some of the inputs; Jolt currently isn't "hiding" (and probably won't be until we compose the prover with Groth16).

Re: the example linked, the program_io.inputs is the serialized version of the program inputs so there's a type mismatch here: p, a and b have type i32, while program_io.inputs has type Vec<u8>.

It's still kind of strange to me that the raw byte representation would be [30, 10, 6], @ncitron does this look right to you?

ncitron commented 4 months ago

The byte representation of the inputs and outputs is from encoding using the postman crate. In postman, then do run length encoding of the integers, where each byte is represented a 7 bits with one bit saved to represent whether the integer is complete, or needs to be extended another byte. This is done to save space, although arguably it might not be the most efficient for jolt (but compared to other encoding libraries postman meets are needs best).

imikushin commented 4 months ago

Thanks @ncitron! Indeed, when using postcard (as Jolt does internally to encode these), inputs and outputs are decoded correctly:

    let (proof_p, proof_a, proof_b): (i32, i32, i32) = postcard::from_bytes(&proof.proof.program_io.inputs).unwrap();
    let proof_output: bool = postcard::from_bytes(&proof.proof.program_io.outputs).unwrap();
    println!("(proof_p, proof_a, proof_b): {:?}", (proof_p, proof_a, proof_b));
    println!("proof_output: {:?}", proof_output);

prints:

(proof_p, proof_a, proof_b): (15, 5, 3)
proof_output: true
imikushin commented 4 months ago

The original issue, boiling down to marking some of the inputs as private and omitting them from the proof, still stands though. I'm willing to help address it.

imikushin commented 4 months ago

Opened a new issue: #371

Closing this one as I feel it's resolved.