Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zkvm: question: how to push predicate to Program? #218

Closed
SoraSuegami opened this issue Mar 14, 2019 · 5 comments
Closed

zkvm: question: how to push predicate to Program? #218

SoraSuegami opened this issue Mar 14, 2019 · 5 comments
Labels
question Further information is requested

Comments

@SoraSuegami
Copy link

Hello. I am a beginner of Rust.
I'm interested in your zkvm and trying to make a simple example that proves two pushed data are equal.
I'd like to ask you how to push predicate to the program and set Anchor.

This is the code I wrote.

use zkvm;
use rand::Rng;
use curve25519_dalek::ristretto::CompressedRistretto;
use curve25519_dalek::scalar::Scalar;
use bulletproofs::{BulletproofGens, PedersenGens};
use merlin::Transcript;

fn bytecode(prog: &zkvm::Program) -> Vec<u8> {
        let mut prog_vec = Vec::new();
        prog.encode(&mut prog_vec);
        prog_vec
}

fn main() {
    let mut rng = rand::thread_rng();
    let range = 0..31;
    let mut randoms:[u8;32] = [0;32];
    for i in range {
        randoms[i] = rng.gen();
    }
    let ristretto = CompressedRistretto(randoms);
    let verify_key = zkvm::VerificationKey(ristretto);
    let bp_gens = BulletproofGens::new(64, 1);
    let pc_gens = PedersenGens::default();
    let program1 = zkvm::Program::build(|prog:&mut zkvm::Program|{prog.push(123).r#const().push(123).r#const().eq().verify()});
    let pred = zkvm::Predicate::Program(program1.clone());
    let op = pred.prove_program_predicate(&bytecode(&program1));
    let program2 = zkvm::Program::build(|prog:&mut zkvm::Program|{prog.push(0).push(op).nonce()});
    let tx_header = zkvm::TxHeader{version:0,mintime:0,maxtime:9999999999};
    let privkey = Scalar::random(&mut rand::thread_rng());
    let sign_fn = |transcript:&mut Transcript, verification_keys:&Vec<zkvm::VerificationKey>|{
        let mut trans = transcript;
        zkvm::Signature::sign_single(&mut trans, privkey)
    };
    let (tx,_,_) = zkvm::Prover::build_tx(program2,tx_header,&bp_gens,sign_fn).unwrap();
    let verified = zkvm::Verifier::verify_tx(tx,&bp_gens).unwrap();
}

Running this code, I got error message, "the trait std::convert::From<zkvm::point_ops::PointOp> is not implemented for zkvm::scalar_witness::ScalarWitness".
As far as I saw Instructions in the ZkVM specification, however, no opcode can push predicates or PointOp of predicates to the stack.

I would appreciate it if you could share how to push predicate to the program and set Anchor.

@vickiniu
Copy link
Contributor

Thanks so much for your question, @SoraSuegami ! A good place to look for reference on how to build some basic zkvm programs right now is the unit tests.

To push a Predicate onto the program stack, you construct a Predicate (which you've already done!) and push that as data.

let prog = Program::build(|p| {
    p.push(predicate)
    ....
});

In terms of setting the anchor, the anchor is a field that's managed internally by the VM. We update the anchor on the nonce and input instructions: nonce creates a new anchor from the random Predicate provided and sets that as the VM anchor, and input consumes the UTXO's contract ID as anchor and ratchets it to set the VM anchor.

Finally, in terms of the program you've written — awesome work thus far! I left some inline comments in a few places.

fn main() {
    // Right now, we never actually use this verify_key, so 
    // I think we can skip this section. Also, you can use the 
    // helper VerificationKey::from_secret(&Scalar) to make a 
    // verification key from random Scalar
    let mut rng = rand::thread_rng();
    let range = 0..31;
    let mut randoms:[u8;32] = [0;32];
    for i in range {
        randoms[i] = rng.gen();
    }
    let ristretto = CompressedRistretto(randoms);
    let verify_key = zkvm::VerificationKey(ristretto);

    let bp_gens = BulletproofGens::new(64, 1);
    let pc_gens = PedersenGens::default();

    // This program looks great! We do need to add a `nonce` instruction
    // to set the anchor, so we'll need to generate a nonce predicate + 
    // dummy block ID, push those to the stack and call `nonce` and `signtx`
    let program1 = zkvm::Program::build(|prog:&mut zkvm::Program|{prog.push(123).r#const().push(123).r#const().eq().verify()});

    // For this program in particular, we may not need a program Predicate
    // Those are meant to be satisfied using the `call` VM instruction, for 
    // protecting a contract with some program that must be successfully run 
    // before continuing.
    let pred = zkvm::Predicate::Program(program1.clone());
    let op = pred.prove_program_predicate(&bytecode(&program1));

    // Similarly, we can combine program1 and program2 here!
    let program2 = zkvm::Program::build(|prog:&mut zkvm::Program|{prog.push(0).push(op).nonce()});
    let tx_header = zkvm::TxHeader{version:0,mintime:0,maxtime:9999999999};

    // The only signature we verify inside the transaction is from the nonce, 
    // so here we should only need to sign with the nonce Predicate's private key.
    let privkey = Scalar::random(&mut rand::thread_rng());
    // nit: it may be easier to define the signing function inline in the call to build_tx
    let sign_fn = |transcript:&mut Transcript, verification_keys:&Vec<zkvm::VerificationKey>|{
        let mut trans = transcript;
        zkvm::Signature::sign_single(&mut trans, privkey)
    };
    let (tx,_,_) = zkvm::Prover::build_tx(program2,tx_header,&bp_gens,sign_fn).unwrap();
    let verified = zkvm::Verifier::verify_tx(tx,&bp_gens).unwrap();
}

Let me know if that all makes sense or if you have any more questions!

@oleganza oleganza added the question Further information is requested label Mar 14, 2019
@oleganza oleganza changed the title [Question] zkvm: How to push predicate to Program zkvm: question: how to push predicate to Program? Mar 14, 2019
@SoraSuegami
Copy link
Author

I truly appreciate your courteous reply!
The following code run well!

use zkvm;
use rand::Rng;
use curve25519_dalek::ristretto::CompressedRistretto;
use curve25519_dalek::scalar::Scalar;
use bulletproofs::{BulletproofGens, PedersenGens};
use merlin::Transcript;

fn main() {
    let privkey = Scalar::random(&mut rand::thread_rng());
    let verify_key = zkvm::VerificationKey::from_secret(&privkey);
    let bp_gens = BulletproofGens::new(64, 1);
    let pc_gens = PedersenGens::default();
    let pred = zkvm::Predicate::Key(verify_key);
    let program = zkvm::Program::build(|prog:&mut zkvm::Program|{prog.push(123).r#const().push(123).r#const().eq().verify().push(pred).push(Scalar::from_bytes_mod_order([1;32])).nonce().sign_tx()});
    let tx_header = zkvm::TxHeader{version:0,mintime:0,maxtime:9999999999};
    let sign_fn = |transcript:&mut Transcript, verification_keys:&Vec<zkvm::VerificationKey>|{
        let mut trans = transcript;
        zkvm::Signature::sign_single(&mut trans, privkey)
    };
    let (tx,_,_) = zkvm::Prover::build_tx(program,tx_header,&bp_gens,sign_fn).unwrap();
    println!("prove!");
    let verified = zkvm::Verifier::verify_tx(tx,&bp_gens).unwrap();
    println!("verify!");
}

I understood I can push Predicate to the program and Predicate::Key is used to set Anchor.
I'd like to write more kinds of codes and prove them.
Do you have plans to prepare any programing language or tools that convert into opcodes in zkvm?

@vickiniu
Copy link
Contributor

That's great to hear! Thanks so much for your interest. For the time being, we're more focused on development of zkvm itself but having more robust SDKs and tools is definitely something we're interested in working on a little bit down the pipeline :)

@SoraSuegami
Copy link
Author

It seems to me that a tool to compile wasm (webassembly) into opcodes in zkvm is very useful for developers.
I'd like to develop such a compiler.

@vickiniu
Copy link
Contributor

Hey @SoraSuegami — having zkvm work with wasm would be great! For right now, we're still developing & changing the zkvm internals a lot. We'll definitely keep that in mind, and would love to have your contributions when we get closer to having zkvm be stable enough to start building out those interfaces :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants