refactor risc0 zone
This commit is contained in:
parent
b2c0f7eda0
commit
507e1627d7
|
@ -8,3 +8,5 @@ methods = { path = "../methods" }
|
|||
risc0-zkvm = { version = "1.0.1" }
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
serde = "1.0"
|
||||
blake2 = "0.10"
|
||||
bincode = "1"
|
|
@ -1,49 +1,60 @@
|
|||
// These constants represent the RISC-V ELF and the image ID generated by risc0-build.
|
||||
// The ELF is used for proving and the ID is used for verification.
|
||||
use blake2::{Blake2s256, Digest};
|
||||
use methods::{METHOD_ELF, METHOD_ID};
|
||||
use risc0_zkvm::{default_prover, ExecutorEnv};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
type Note = BTreeMap<u32, u32>;
|
||||
|
||||
// state of the zone
|
||||
type State = BTreeMap<u32, u32>;
|
||||
// list of all inputs that were executed up to this point
|
||||
type Journal = Vec<Input>;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
struct Note {
|
||||
state_cm: [u8; 32],
|
||||
journal_cm: [u8; 32],
|
||||
zone_input: Input,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
enum Input {
|
||||
Transfer { from: u32, to: u32, amount: u32 },
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Initialize tracing. In order to view logs, run `RUST_LOG=info cargo run`
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
|
||||
.init();
|
||||
|
||||
let in_note: BTreeMap<u32, u32> = [(0, 1000)].into_iter().collect();
|
||||
let in_note_cm = calculate_note_hash(&in_note);
|
||||
let state: BTreeMap<u32, u32> = [(0, 1000)].into_iter().collect();
|
||||
let journal = vec![];
|
||||
|
||||
let out_note: BTreeMap<u32, u32> = [(0, 990), (1, 10)].into_iter().collect();
|
||||
let out_note_cm = calculate_note_hash(&out_note);
|
||||
let note = Note {
|
||||
state_cm: calculate_state_hash(&state),
|
||||
journal_cm: calculate_journal_hash(&journal),
|
||||
zone_input: Input::Transfer {
|
||||
from: 0,
|
||||
to: 1,
|
||||
amount: 10,
|
||||
},
|
||||
};
|
||||
|
||||
let ptx_root = [0u8; 32];
|
||||
let in_ptx_path: Vec<[u8; 32]> = vec![[0; 32]];
|
||||
let out_ptx_path: Vec<[u8; 32]> = vec![[0; 32]];
|
||||
|
||||
println!("Before: {:?}", in_note);
|
||||
|
||||
let from = 0;
|
||||
let to = 1;
|
||||
let amount: u32 = 10;
|
||||
|
||||
let env = ExecutorEnv::builder()
|
||||
.write(&ptx_root)
|
||||
.unwrap()
|
||||
.write(&in_ptx_path)
|
||||
.unwrap()
|
||||
.write(&out_ptx_path)
|
||||
.write(¬e)
|
||||
.unwrap()
|
||||
.write(&in_note_cm)
|
||||
.write(&state)
|
||||
.unwrap()
|
||||
.write(&out_note_cm)
|
||||
.unwrap()
|
||||
.write(&from)
|
||||
.unwrap()
|
||||
.write(&to)
|
||||
.unwrap()
|
||||
.write(&amount)
|
||||
.unwrap()
|
||||
.write(&in_note)
|
||||
.write(&journal)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
@ -53,8 +64,7 @@ fn main() {
|
|||
|
||||
// Proof information by proving the specified ELF binary.
|
||||
// This struct contains the receipt along with statistics about execution of the guest
|
||||
let opts =
|
||||
risc0_zkvm::ProverOpts::default().with_receipt_kind(risc0_zkvm::ReceiptKind::Groth16);
|
||||
let opts = risc0_zkvm::ProverOpts::default();
|
||||
let prove_info = prover.prove_with_opts(env, METHOD_ELF, &opts).unwrap();
|
||||
|
||||
// extract the receipt.
|
||||
|
@ -63,7 +73,7 @@ fn main() {
|
|||
// TODO: Implement code for retrieving receipt journal here.
|
||||
|
||||
// For example:
|
||||
// let output: BTreeMap<u32, u32> = receipt.journal.decode().unwrap();
|
||||
let (state_cm, journal_cm): ([u8; 32], [u8; 32]) = receipt.journal.decode().unwrap();
|
||||
// println!("After: {:?}", output);
|
||||
|
||||
// The receipt was verified at the end of proving, but the below code is an
|
||||
|
@ -71,8 +81,12 @@ fn main() {
|
|||
receipt.verify(METHOD_ID).unwrap();
|
||||
}
|
||||
|
||||
fn calculate_note_hash(n: &Note) -> [u8; 32] {
|
||||
let mut out = [0u8; 32];
|
||||
out[0] = n.len() as u8;
|
||||
out
|
||||
fn calculate_state_hash(state: &State) -> [u8; 32] {
|
||||
let bytes = bincode::serialize(state).unwrap();
|
||||
Blake2s256::digest(&bytes).into()
|
||||
}
|
||||
|
||||
fn calculate_journal_hash(journal: &Journal) -> [u8; 32] {
|
||||
let bytes = bincode::serialize(journal).unwrap();
|
||||
Blake2s256::digest(&bytes).into()
|
||||
}
|
||||
|
|
|
@ -7,4 +7,6 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
risc0-zkvm = { version = "1.0.1", default-features = false, features = ['std'] }
|
||||
blake2 = "0.10"
|
||||
blake2 = "0.10"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
bincode = "1"
|
|
@ -1,61 +1,108 @@
|
|||
use blake2::{Blake2s256, Digest};
|
||||
use risc0_zkvm::guest::env;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Public Inputs:
|
||||
/// * ptx_root: the root of the partial tx merkle tree of inputs/outputs
|
||||
|
||||
/// * in_note_cm: a commitment to the input note
|
||||
/// * out_note_cm: a commitment to the output note
|
||||
/// Private inputs:
|
||||
/// * in_note: a note corresponding to the input commitment
|
||||
/// * in_ptx_path: the path from a leaf containing the input state commitment in the ptx
|
||||
/// * out_ptx_path: the path from a leaf containing the output state commitment in the ptx
|
||||
/// * from: u32, the account to transfer from
|
||||
/// * to: u32, the account to transfer to
|
||||
/// * amount: u32, the amount to transfer
|
||||
///
|
||||
type Note = BTreeMap<u32, u32>;
|
||||
/// TODO
|
||||
|
||||
// state of the zone
|
||||
type State = BTreeMap<u32, u32>;
|
||||
// list of all inputs that were executed up to this point
|
||||
type Journal = Vec<Input>;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
struct Note {
|
||||
state_cm: [u8; 32],
|
||||
journal_cm: [u8; 32],
|
||||
zone_input: Input,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
enum Input {
|
||||
Transfer { from: u32, to: u32, amount: u32 },
|
||||
}
|
||||
|
||||
/// State transition function
|
||||
fn stf(mut state: State, input: Input) -> State {
|
||||
match input {
|
||||
Input::Transfer { from, to, amount } => {
|
||||
// compute transfer
|
||||
let from = state.entry(from).or_insert(0);
|
||||
*from = from.checked_sub(amount).unwrap();
|
||||
*state.entry(to).or_insert(0) += amount;
|
||||
}
|
||||
}
|
||||
state
|
||||
}
|
||||
|
||||
/// Glue the zone and the cl together, specifically, it verifies the note requesting
|
||||
/// a transfer is included as part of the same transaction in the cl
|
||||
fn verify_ptx_inputs(ptx_root: [u8; 32], ptx_path: &[[u8; 32]], note: &Note) {
|
||||
assert!(verify_path(&ptx_root, &ptx_path, ¬e));
|
||||
}
|
||||
|
||||
/// Glue the zone and the cl together, specifically, it verifies an output note
|
||||
/// containing the zone state is included as part of the same transaction in the cl
|
||||
/// (this is done in the death condition to disallow burning)
|
||||
fn verify_ptx_output(ptx_root: [u8; 32], ptx_path: &[[u8; 32]], note: &Note) {
|
||||
assert!(verify_path(&ptx_root, &ptx_path, ¬e));
|
||||
}
|
||||
|
||||
fn execute(
|
||||
ptx_root: [u8; 32],
|
||||
ptx_path: Vec<[u8; 32]>,
|
||||
note: Note,
|
||||
state: State,
|
||||
mut journal: Journal,
|
||||
) -> (State, Journal) {
|
||||
// verify ptx/cl preconditions
|
||||
verify_ptx_inputs(ptx_root, &ptx_path, ¬e);
|
||||
|
||||
// check the commitments match the actual data
|
||||
let state_cm = calculate_state_hash(&state);
|
||||
let journal_cm = calculate_journal_hash(&journal);
|
||||
assert_eq!(state_cm, note.state_cm);
|
||||
assert_eq!(journal_cm, note.journal_cm);
|
||||
|
||||
// then run the state transition function
|
||||
let input = note.zone_input;
|
||||
let state = stf(state, input);
|
||||
journal.push(input);
|
||||
|
||||
let state_cm = calculate_state_hash(&state);
|
||||
let journal_cm = calculate_journal_hash(&journal);
|
||||
|
||||
// verifying ptx/cl postconditions
|
||||
verify_ptx_outputs(ptx_root, &ptx_path, out_note);
|
||||
// output the new state and the execution receipt
|
||||
(state, journal)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// public input
|
||||
let ptx_root: [u8; 32] = env::read();
|
||||
let in_ptx_path: Vec<[u8; 32]> = env::read();
|
||||
let out_ptx_path: Vec<[u8; 32]> = env::read();
|
||||
|
||||
let in_note_cm: [u8; 32] = env::read();
|
||||
let out_note_cm: [u8; 32] = env::read();
|
||||
|
||||
let from: u32 = env::read();
|
||||
let to: u32 = env::read();
|
||||
let amount: u32 = env::read();
|
||||
|
||||
// private input
|
||||
let in_note: Note = env::read();
|
||||
let in_ptx_path: Vec<[u8; 32]> = env::read();
|
||||
let out_ptx_path: Vec<[u8; 32]> = env::read();
|
||||
let note: Note = env::read();
|
||||
let state: State = env::read();
|
||||
let journal: Journal = env::read();
|
||||
|
||||
// check the note is consistent with the state commitment and is part of the path
|
||||
assert_eq!(in_note_cm, calculate_note_hash(&in_note));
|
||||
// verify the input state commitment is part of the partial tx
|
||||
assert!(verify_path(&ptx_root, &in_ptx_path, &in_note));
|
||||
|
||||
// the note is just the state
|
||||
let mut state = in_note.clone();
|
||||
|
||||
// compute transfer
|
||||
let from = state.entry(from).or_insert(0);
|
||||
|
||||
*from = from.checked_sub(amount).unwrap();
|
||||
*state.entry(to).or_insert(0) += amount;
|
||||
|
||||
// check that the new state is consistent with the output state commitment and it's part of the output
|
||||
assert_eq!(calculate_note_hash(&state), out_note_cm);
|
||||
let out_note = state;
|
||||
assert!(verify_path(&ptx_root, &out_ptx_path, &out_note));
|
||||
execute(ptx_root, in_ptx_path, out_ptx_path, note, state, journal);
|
||||
}
|
||||
|
||||
fn calculate_note_hash(n: &Note) -> [u8; 32] {
|
||||
let mut out = [0u8; 32];
|
||||
out[0] = n.len() as u8;
|
||||
out
|
||||
fn calculate_state_hash(state: &State) -> [u8; 32] {
|
||||
let bytes = bincode::serialize(state).unwrap();
|
||||
Blake2s256::digest(&bytes).into()
|
||||
}
|
||||
|
||||
fn calculate_journal_hash(journal: &Journal) -> [u8; 32] {
|
||||
let bytes = bincode::serialize(journal).unwrap();
|
||||
Blake2s256::digest(&bytes).into()
|
||||
}
|
||||
|
||||
fn verify_path(_ptx_root: &[u8; 32], _ptx_path: &[[u8; 32]], _note: &Note) -> bool {
|
||||
|
|
Loading…
Reference in New Issue