Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

zkvm: eval opcode #499

Merged
merged 3 commits into from
Mar 30, 2021
Merged
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
21 changes: 16 additions & 5 deletions zkvm/docs/zkvm-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ Then, the VM executes the current program till completion:
1. Each instruction is read at the current program offset, including its immediate data (if any).
2. Program offset is advanced immediately after reading the instruction to the next instruction.
3. The instruction is executed per [specification below](#instructions). If the instruction fails, VM exits early with an error result.
4. If VM encounters [`call`](#call), [`signid`](#signid) or [`signtag`](#signtag) instruction, the new program with offset zero is set as the current program. The next iteration of the vm will start from the beginning of the new program.
4. If VM encounters [`eval`](#eval), [`call`](#call), [`signid`](#signid) or [`signtag`](#signtag) instruction, the new program with offset zero is set as the current program. The next iteration of the vm will start from the beginning of the new program.
5. If the offset is less than the current program’s length, a new instruction is read (go back to step 1).
6. Otherwise (reached the end of the current program):
1. If the program stack is not empty, pop top item from the program stack and set it to the current program. Go to step 5.
Expand Down Expand Up @@ -965,10 +965,11 @@ Code | Instruction | Stack diagram |
0x1b | [`output:k`](#output) | _items... pred_ → ø | Modifies [tx log](#transaction-log)
0x1c | [`contract:k`](#contract) | _items... pred_ → _contract_ |
0x1d | [`log`](#log) | _data_ → ø | Modifies [tx log](#transaction-log)
0x1e | [`call`](#call) |_contract(P) proof prog_ → _results..._ | [Defers point operations](#deferred-point-operations)
0x1f | [`signtx`](#signtx) | _contract_ → _results..._ | Modifies [deferred verification keys](#transaction-signature)
0x20 | [`signid`](#signid) |_contract prog sig_ → _results..._ | [Defers point operations](#deferred-point-operations)
0x21 | [`signtag`](#signtag) |_contract prog sig_ → _results..._ | [Defers point operations](#deferred-point-operations)
0x1e | [`eval`](#eval) | _prog_ → _results..._ |
0x1f | [`call`](#call) |_contract(P) proof prog_ → _results..._ | [Defers point operations](#deferred-point-operations)
0x20 | [`signtx`](#signtx) | _contract_ → _results..._ | Modifies [deferred verification keys](#transaction-signature)
0x21 | [`signid`](#signid) |_contract prog sig_ → _results..._ | [Defers point operations](#deferred-point-operations)
0x22 | [`signtag`](#signtag) |_contract prog sig_ → _results..._ | [Defers point operations](#deferred-point-operations)
— | [`ext`](#ext) | ø → ø | Fails if [extension flag](#vm-state) is not set.


Expand Down Expand Up @@ -1409,6 +1410,16 @@ _data_ **log** → ø
Fails if `data` is not a [string](#string-type).


#### eval

_prog_ **eval** → _results..._

1. Pops [program](#program-type) `prog`.
2. Set the `prog` as current.

Fails if `prog` is not a [program](#program-type).


#### call

_contract(P) proof prog_ **call** → _results..._
Expand Down
1 change: 1 addition & 0 deletions zkvm/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ impl Instruction {
Instruction::Output(k) => write!(f, "output:{}", k),
Instruction::Contract(k) => write!(f, "contract:{}", k),
Instruction::Log => write!(f, "log"),
Instruction::Eval => write!(f, "eval"),
Instruction::Call => write!(f, "call"),
Instruction::Signtx => write!(f, "signtx"),
Instruction::Signid => write!(f, "signid"),
Expand Down
20 changes: 16 additions & 4 deletions zkvm/src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,14 @@ pub enum Instruction {
/// Fails if `data` is not a _string_.
Log,

/// _prog_ **eval** → _results..._
///
/// 1. Pops _program_ `prog`.
/// 2. Set the `prog` as current.
///
/// Fails if `prog` is not a _program_.
Eval,

/// _contract(P) proof prog_ **call** → _results..._
///
/// 1. Pops _program_ `prog`, the _call proof_ `proof`, and a _contract_ `contract`.
Expand Down Expand Up @@ -561,17 +569,19 @@ pub enum Opcode {
Contract = 0x1c,
/// A code for [Instruction::Log]
Log = 0x1d,
/// A code for [Instruction::Eval]
Eval = 0x1e,
/// A code for [Instruction::Call]
Call = 0x1e,
Call = 0x1f,
/// A code for [Instruction::Signtx]
Signtx = 0x1f,
Signtx = 0x20,
/// A code for [Instruction::Signid]
Signid = 0x20,
Signid = 0x21,
/// A code for [Instruction::Signtag]
Signtag = MAX_OPCODE,
}

const MAX_OPCODE: u8 = 0x21;
const MAX_OPCODE: u8 = 0x22;

impl Opcode {
/// Converts the opcode to `u8`.
Expand Down Expand Up @@ -650,6 +660,7 @@ impl Encodable for Instruction {
w.write_u32(b"k", *k as u32)?;
}
Instruction::Log => write(Opcode::Log)?,
Instruction::Eval => write(Opcode::Eval)?,
Instruction::Call => write(Opcode::Call)?,
Instruction::Signtx => write(Opcode::Signtx)?,
Instruction::Signid => write(Opcode::Signid)?,
Expand Down Expand Up @@ -749,6 +760,7 @@ impl Instruction {
Ok(Instruction::Contract(k))
}
Opcode::Log => Ok(Instruction::Log),
Opcode::Eval => Ok(Instruction::Eval),
Opcode::Call => Ok(Instruction::Call),
Opcode::Signtx => Ok(Instruction::Signtx),
Opcode::Signid => Ok(Instruction::Signid),
Expand Down
2 changes: 1 addition & 1 deletion zkvm/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ impl Program {
def_op!(contract, Contract, usize, "contract:k");

def_op!(log, Log, "log");
def_op!(eval, Eval, "eval");
def_op!(call, Call, "call");

def_op!(signtx, Signtx, "signtx");
def_op!(signid, Signid, "signid");
def_op!(signtag, Signtag, "signtag");
Expand Down
10 changes: 10 additions & 0 deletions zkvm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ where
Instruction::Output(k) => self.output(k)?,
Instruction::Contract(k) => self.contract(k)?,
Instruction::Log => self.log()?,
Instruction::Eval => self.eval()?,
Instruction::Call => self.call()?,
Instruction::Signtx => self.signtx()?,
Instruction::Signid => self.signid()?,
Expand Down Expand Up @@ -572,6 +573,15 @@ where
Ok(())
}

fn eval(&mut self) -> Result<(), VMError> {
// Pop program
let program_item = self.pop_item()?.to_program()?;

// Replace current program with new program
self.continue_with_program(program_item)?;
Ok(())
}

fn call(&mut self) -> Result<(), VMError> {
// Pop program, call proof, and contract
let program_item = self.pop_item()?.to_program()?;
Expand Down
30 changes: 30 additions & 0 deletions zkvm/tests/zkvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,36 @@ fn constraints_cannot_be_copied() {
);
}

#[test]
fn eval_test() {
let (pred, prv) = generate_predicate();
let prog = Program::build(|p| {
p.push(String::from(Scalar::from(20u64)));
p.scalar();
p.program(Program::build(|p2| {
p2.push(String::from(Scalar::from(1u64)));
p2.scalar();
p2.program(Program::build(|p3| {
p3.add();
}));
p2.eval();
}));
p.eval();
p.push(String::from(Scalar::from(21u64)));
p.scalar();
p.eq();
p.verify();

// to make program finish we need to spend a dummy input
p.input_helper(0, Scalar::zero(), pred.clone());
p.output_helper(pred);
});

dbg!(&prog);

build_and_verify(prog, &vec![prv]).expect("should succeed");
}

#[test]
fn borrow_output() {
//inputs 10 units, borrows 5 units, outputs two (5 units)
Expand Down