diff --git a/goas/Cargo.toml b/goas/Cargo.toml index 63b3854..8aa6d3c 100644 --- a/goas/Cargo.toml +++ b/goas/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["host", "methods"] +members = [ "common","host", "methods"] # Always optimize; building and running the guest takes much longer without optimization. [profile.dev] diff --git a/goas/common/Cargo.toml b/goas/common/Cargo.toml new file mode 100644 index 0000000..0e28ae9 --- /dev/null +++ b/goas/common/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "common" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1", features = ["derive"] } \ No newline at end of file diff --git a/goas/common/src/lib.rs b/goas/common/src/lib.rs new file mode 100644 index 0000000..d7ed49e --- /dev/null +++ b/goas/common/src/lib.rs @@ -0,0 +1,35 @@ +use serde::{Serialize, Deserialize}; +use std::collections::BTreeMap; + +#[derive(Clone, Serialize, Deserialize)] +pub struct Note { + pub state_cm: [u8; 32], + pub journal_cm: [u8; 32], + pub zone_input: Input, +} + +// state of the zone +pub type State = BTreeMap; +// list of all inputs that were executed up to this point +pub type Journal = Vec; + +#[derive(Clone, Copy, Serialize, Deserialize)] +pub enum Input { + Transfer { from: u32, to: u32, amount: u32 }, + None, +} + + +/// State transition function of the zone +pub 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; + } + Input::None => {} + } + state +} \ No newline at end of file diff --git a/goas/host/Cargo.toml b/goas/host/Cargo.toml index 3527033..1550019 100644 --- a/goas/host/Cargo.toml +++ b/goas/host/Cargo.toml @@ -9,4 +9,5 @@ risc0-zkvm = { version = "1.0.1" } tracing-subscriber = { version = "0.3", features = ["env-filter"] } serde = "1.0" blake2 = "0.10" -bincode = "1" \ No newline at end of file +bincode = "1" +common = { path = "../common" } \ No newline at end of file diff --git a/goas/host/src/main.rs b/goas/host/src/main.rs index f555dc8..b541a70 100644 --- a/goas/host/src/main.rs +++ b/goas/host/src/main.rs @@ -3,25 +3,8 @@ use blake2::{Blake2s256, Digest}; use methods::{METHOD_ELF, METHOD_ID}; use risc0_zkvm::{default_prover, ExecutorEnv}; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; +use common::*; -// state of the zone -type State = BTreeMap; -// list of all inputs that were executed up to this point -type Journal = Vec; - -#[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` @@ -29,28 +12,43 @@ fn main() { .with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env()) .init(); - let state: BTreeMap = [(0, 1000)].into_iter().collect(); + let state: State = [(0, 1000)].into_iter().collect(); let journal = vec![]; + let zone_input = Input::Transfer { + from: 0, + to: 1, + amount: 10, + }; - let note = Note { + let in_note = Note { state_cm: calculate_state_hash(&state), journal_cm: calculate_journal_hash(&journal), - zone_input: Input::Transfer { - from: 0, - to: 1, - amount: 10, - }, + zone_input, + }; + + let mut out_journal = journal.clone(); + out_journal.push(zone_input); + + let out_note = Note { + state_cm: calculate_state_hash(&stf(state.clone(), zone_input)), + journal_cm: calculate_journal_hash(&out_journal), + zone_input: Input::None, }; 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]]; let env = ExecutorEnv::builder() .write(&ptx_root) .unwrap() .write(&in_ptx_path) .unwrap() - .write(¬e) + .write(&out_ptx_path) + .unwrap() + .write(&in_note) + .unwrap() + .write(&out_note) .unwrap() .write(&state) .unwrap() @@ -64,7 +62,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(); + let opts = risc0_zkvm::ProverOpts::succinct(); let prove_info = prover.prove_with_opts(env, METHOD_ELF, &opts).unwrap(); // extract the receipt. @@ -72,10 +70,7 @@ fn main() { // TODO: Implement code for retrieving receipt journal here. - // For example: - let (state_cm, journal_cm): ([u8; 32], [u8; 32]) = receipt.journal.decode().unwrap(); - // println!("After: {:?}", output); - + std::fs::write("proof.stark", bincode::serialize(&receipt).unwrap()).unwrap(); // The receipt was verified at the end of proving, but the below code is an // example of how someone else could verify this receipt. receipt.verify(METHOD_ID).unwrap(); diff --git a/goas/methods/guest/Cargo.toml b/goas/methods/guest/Cargo.toml index 33dab58..cb06bf3 100644 --- a/goas/methods/guest/Cargo.toml +++ b/goas/methods/guest/Cargo.toml @@ -9,4 +9,5 @@ edition = "2021" risc0-zkvm = { version = "1.0.1", default-features = false, features = ['std'] } blake2 = "0.10" serde = { version = "1.0", features = ["derive"] } -bincode = "1" \ No newline at end of file +bincode = "1" +common = { path = "../../common" } \ No newline at end of file diff --git a/goas/methods/guest/src/main.rs b/goas/methods/guest/src/main.rs index 68f09a2..22bc96f 100644 --- a/goas/methods/guest/src/main.rs +++ b/goas/methods/guest/src/main.rs @@ -1,43 +1,12 @@ use blake2::{Blake2s256, Digest}; use risc0_zkvm::guest::env; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; +use common::*; /// Public Inputs: /// * ptx_root: the root of the partial tx merkle tree of inputs/outputs /// Private inputs: /// TODO -// state of the zone -type State = BTreeMap; -// list of all inputs that were executed up to this point -type Journal = Vec; - -#[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) { @@ -47,36 +16,42 @@ fn verify_ptx_inputs(ptx_root: [u8; 32], ptx_path: &[[u8; 32]], note: &Note) { /// 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) { +fn verify_ptx_outputs(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, + in_ptx_path: Vec<[u8; 32]>, + out_ptx_path: Vec<[u8; 32]>, + in_note: Note, + out_note: Note, state: State, mut journal: Journal, ) -> (State, Journal) { // verify ptx/cl preconditions - verify_ptx_inputs(ptx_root, &ptx_path, ¬e); + verify_ptx_inputs(ptx_root, &in_ptx_path, &in_note); // 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); + assert_eq!(state_cm, in_note.state_cm); + assert_eq!(journal_cm, in_note.journal_cm); // then run the state transition function - let input = note.zone_input; + let input = in_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); + // TODO: verify death constraints are propagated + assert_eq!(state_cm, out_note.state_cm); + assert_eq!(journal_cm, out_note.journal_cm); + // verifying ptx/cl postconditions - verify_ptx_outputs(ptx_root, &ptx_path, out_note); + verify_ptx_outputs(ptx_root, &out_ptx_path, &out_note); // output the new state and the execution receipt (state, journal) } @@ -88,11 +63,12 @@ fn main() { // private input let in_ptx_path: Vec<[u8; 32]> = env::read(); let out_ptx_path: Vec<[u8; 32]> = env::read(); - let note: Note = env::read(); + let in_note: Note = env::read(); + let out_note: Note = env::read(); let state: State = env::read(); let journal: Journal = env::read(); - execute(ptx_root, in_ptx_path, out_ptx_path, note, state, journal); + execute(ptx_root, in_ptx_path, out_ptx_path, in_note, out_note, state, journal); } fn calculate_state_hash(state: &State) -> [u8; 32] {