diff --git a/playground/miden-wasm/src/lib.rs b/playground/miden-wasm/src/lib.rs index ef80e76..61dbc97 100644 --- a/playground/miden-wasm/src/lib.rs +++ b/playground/miden-wasm/src/lib.rs @@ -1,18 +1,9 @@ +mod transaction; mod utils_debug; mod utils_input; mod utils_program; -use miden_objects::{ - notes::Note, - transaction::{PreparedTransaction, ProvenTransaction}, -}; -use miden_tx::{mock::MockDataStore, TransactionExecutor, TransactionProver}; -use miden_vm::{ - crypto::RpoDigest, - math::{Felt, StarkField}, - ExecutionProof, ProgramInfo, ProofOptions, Word, -}; +use miden_vm::{ExecutionProof, ProofOptions}; use serde::{Deserialize, Serialize}; -use serde_wasm_bindgen::Serializer; use wasm_bindgen::prelude::*; #[wasm_bindgen(getter_with_clone)] @@ -134,241 +125,6 @@ pub fn verify_program( Ok(result) } -pub struct Digest(pub Vec); - -impl From for Digest { - fn from(digest: RpoDigest) -> Self { - Digest(digest.into_iter().map(|n| n.as_int()).collect::>()) - } -} - -impl From for Vec { - fn from(digest: Digest) -> Self { - digest.0 - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct WasmPreparedTransaction { - pub account_id: u64, - pub block_hash: Vec, - pub block_number: u32, - pub consumed_notes: Vec, - pub tx_script_root: Option>, - pub tx_program_root: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct WasmNote { - pub script_root: Vec, - pub inputs_hash: Vec, - pub vault_hash: Vec, - pub assets: Vec>, - pub serial_num: Vec, - pub metadata: Vec, -} - -impl From<&Note> for WasmNote { - fn from(note: &Note) -> Self { - let assets = note - .vault() - .iter() - .map(|x| { - Word::from(*x) - .iter() - .map(|x| x.as_int()) - .collect::>() - }) - .collect(); - Self { - script_root: Into::::into(note.script().hash()).into(), - inputs_hash: Into::::into(note.inputs().hash()).into(), - vault_hash: Into::::into(note.vault().hash()).into(), - assets, - serial_num: note.serial_num().into_iter().map(|x| x.as_int()).collect(), - metadata: Into::::into(note.metadata()) - .into_iter() - .map(|x| x.as_int()) - .collect(), - } - } -} - -impl From for WasmPreparedTransaction { - fn from(tx: PreparedTransaction) -> Self { - Self { - account_id: tx.account().id().into(), - block_hash: Into::::into(tx.block_header().hash()).into(), - block_number: tx.block_header().block_num().as_int() as u32, - consumed_notes: tx.consumed_notes().notes().iter().map(Into::into).collect(), - tx_script_root: tx - .tx_script_root() - .and_then(|x| Some(Into::::into(x).into())), - tx_program_root: Into::::into(tx.tx_program().root().hash()).into(), - } - } -} - -#[wasm_bindgen] -pub fn prepare_transaction() -> Result { - let data_store = MockDataStore::new(); - let mut executor = TransactionExecutor::new(data_store.clone()); - - let account_id = data_store.account.id(); - executor - .load_account(account_id) - .map_err(|err| format!("Failed to load account - {:?}", err))?; - - let block_ref = data_store.block_header.block_num().as_int() as u32; - let note_origins = data_store - .notes - .iter() - .map(|note| note.proof().as_ref().unwrap().origin().clone()) - .collect::>(); - - let result: WasmPreparedTransaction = executor - .prepare_transaction(data_store.account.id(), block_ref, ¬e_origins, None) - .map_err(|err| format!("Failed to prepare transaction - {:?}", err))? - .into(); - - let serializer = Serializer::new().serialize_large_number_types_as_bigints(true); - Ok(result.serialize(&serializer)?) -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct WasmProvenTransaction { - pub account_id: u64, - pub initial_account_hash: Vec, - pub final_account_hash: Vec, - pub consumed_notes: Vec>, - pub created_notes: Vec>, - pub tx_script_root: Option>, - pub proof: Vec, -} - -impl From for WasmProvenTransaction { - fn from(proven_transaction: ProvenTransaction) -> WasmProvenTransaction { - let consumed_notes = proven_transaction - .consumed_notes() - .iter() - .map(|x| { - Into::<[Felt; 8]>::into(*x) - .iter() - .map(|x| x.as_int()) - .collect::>() - }) - .collect::>(); - let created_notes = proven_transaction - .created_notes() - .iter() - .map(|x| { - Into::<[Felt; 8]>::into(*x) - .iter() - .map(|x| x.as_int()) - .collect::>() - }) - .collect::>(); - - WasmProvenTransaction { - account_id: proven_transaction.account_id().into(), - initial_account_hash: Into::::into(proven_transaction.initial_account_hash()) - .into(), - final_account_hash: Into::::into(proven_transaction.final_account_hash()) - .into(), - consumed_notes, - created_notes, - tx_script_root: proven_transaction - .tx_script_root() - .and_then(|x| Some(Into::::into(x).into())), - proof: proven_transaction.proof().to_bytes(), - } - } -} - -#[wasm_bindgen] -pub fn prove_transaction() -> Result { - let data_store = MockDataStore::new(); - let mut executor = TransactionExecutor::new(data_store.clone()); - - let account_id = data_store.account.id(); - executor - .load_account(account_id) - .map_err(|err| format!("Failed to load account - {:?}", err))?; - - let block_ref = data_store.block_header.block_num().as_int() as u32; - let note_origins = data_store - .notes - .iter() - .map(|note| note.proof().as_ref().unwrap().origin().clone()) - .collect::>(); - - let prepared_transaction = executor - .prepare_transaction(data_store.account.id(), block_ref, ¬e_origins, None) - .map_err(|err| format!("Failed to prepare transaction - {:?}", err))?; - - let prover = TransactionProver::new(ProofOptions::default()); - let proven_transaction: WasmProvenTransaction = prover - .prove_prepared_transaction(prepared_transaction) - .map_err(|e| format!("Failed to prove prepared transaction - {:?}", e))? - .into(); - - let serializer = Serializer::new().serialize_large_number_types_as_bigints(true); - Ok(proven_transaction.serialize(&serializer)?) -} - -#[wasm_bindgen(getter_with_clone)] -#[derive(Serialize, Deserialize, Debug)] -pub struct WasmVerifyTransactionResult { - pub success: bool, - pub proof: Vec, -} - -#[wasm_bindgen] -pub fn verify_transaction() -> Result { - let data_store = MockDataStore::new(); - let mut executor = TransactionExecutor::new(data_store.clone()); - - let account_id = data_store.account.id(); - executor - .load_account(account_id) - .map_err(|err| format!("Failed to load account - {:?}", err))?; - - let block_ref = data_store.block_header.block_num().as_int() as u32; - let note_origins = data_store - .notes - .iter() - .map(|note| note.proof().as_ref().unwrap().origin().clone()) - .collect::>(); - - let prepared_transaction = executor - .prepare_transaction(data_store.account.id(), block_ref, ¬e_origins, None) - .map_err(|err| format!("Failed to prepare transaction - {:?}", err))?; - - let program_hash = prepared_transaction.tx_program().hash(); - let kernel = prepared_transaction.tx_program().kernel().clone(); - - let prover = TransactionProver::new(ProofOptions::default()); - let proven_transaction = prover - .prove_prepared_transaction(prepared_transaction) - .map_err(|e| format!("Failed to prove prepared transaction - {:?}", e))?; - - let stack_inputs = proven_transaction.stack_inputs(); - let stack_outputs = proven_transaction.stack_outputs(); - let program_info = ProgramInfo::new(program_hash, kernel); - let result: u32 = miden_vm::verify( - program_info, - stack_inputs, - stack_outputs, - proven_transaction.proof().clone(), - ) - .map_err(|err| format!("Program failed verification! - {}", err))?; - - Ok(WasmVerifyTransactionResult { - success: true, - proof: proven_transaction.proof().to_bytes(), - }) -} - // TESTS // ================================================================================================ @@ -603,8 +359,3 @@ fn test_verify_program() { assert_eq!(result, 96); } - -#[test] -fn test_verify_transaction() { - println!("{:?}", verify_transaction().unwrap()); -} diff --git a/playground/miden-wasm/src/transaction.rs b/playground/miden-wasm/src/transaction.rs new file mode 100644 index 0000000..c22321b --- /dev/null +++ b/playground/miden-wasm/src/transaction.rs @@ -0,0 +1,277 @@ +use miden_objects::{ + notes::Note, + transaction::{PreparedTransaction, ProvenTransaction}, +}; +use miden_tx::{mock::MockDataStore, TransactionExecutor, TransactionProver}; +use miden_vm::{ + crypto::RpoDigest, + math::{Felt, StarkField}, + ProgramInfo, ProofOptions, Word, +}; +use serde::{Deserialize, Serialize}; +use serde_wasm_bindgen::Serializer; +use wasm_bindgen::prelude::*; + +// PREPARE TRANSACTION TYPES +// ================================================================================================ + +pub struct Digest(pub Vec); + +impl From for Digest { + fn from(digest: RpoDigest) -> Self { + Digest(digest.into_iter().map(|n| n.as_int()).collect::>()) + } +} + +impl From for Vec { + fn from(digest: Digest) -> Self { + digest.0 + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct WasmPreparedTransaction { + pub account_id: u64, + pub block_hash: Vec, + pub block_number: u32, + pub consumed_notes: Vec, + pub tx_script_root: Option>, + pub tx_program_root: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct WasmNote { + pub script_root: Vec, + pub inputs_hash: Vec, + pub vault_hash: Vec, + pub assets: Vec>, + pub serial_num: Vec, + pub metadata: Vec, +} + +impl From<&Note> for WasmNote { + fn from(note: &Note) -> Self { + let assets = note + .vault() + .iter() + .map(|x| { + Word::from(*x) + .iter() + .map(|x| x.as_int()) + .collect::>() + }) + .collect(); + Self { + script_root: Into::::into(note.script().hash()).into(), + inputs_hash: Into::::into(note.inputs().hash()).into(), + vault_hash: Into::::into(note.vault().hash()).into(), + assets, + serial_num: note.serial_num().into_iter().map(|x| x.as_int()).collect(), + metadata: Into::::into(note.metadata()) + .into_iter() + .map(|x| x.as_int()) + .collect(), + } + } +} + +impl From for WasmPreparedTransaction { + fn from(tx: PreparedTransaction) -> Self { + Self { + account_id: tx.account().id().into(), + block_hash: Into::::into(tx.block_header().hash()).into(), + block_number: tx.block_header().block_num().as_int() as u32, + consumed_notes: tx.consumed_notes().notes().iter().map(Into::into).collect(), + tx_script_root: tx + .tx_script_root() + .and_then(|x| Some(Into::::into(x).into())), + tx_program_root: Into::::into(tx.tx_program().root().hash()).into(), + } + } +} + +// PREPARE TRANSACTION +// ================================================================================================ + +#[wasm_bindgen] +pub fn prepare_transaction() -> Result { + let data_store = MockDataStore::new(); + let mut executor = TransactionExecutor::new(data_store.clone()); + + let account_id = data_store.account.id(); + executor + .load_account(account_id) + .map_err(|err| format!("Failed to load account - {:?}", err))?; + + let block_ref = data_store.block_header.block_num().as_int() as u32; + let note_origins = data_store + .notes + .iter() + .take(1) + .map(|note| note.proof().as_ref().unwrap().origin().clone()) + .collect::>(); + + let result: WasmPreparedTransaction = executor + .prepare_transaction(data_store.account.id(), block_ref, ¬e_origins, None) + .map_err(|err| format!("Failed to prepare transaction - {:?}", err))? + .into(); + + let serializer = Serializer::new().serialize_large_number_types_as_bigints(true); + Ok(result.serialize(&serializer)?) +} + +// PROVE TRANSACTION TYPES +// ================================================================================================ + +#[derive(Serialize, Deserialize, Debug)] +pub struct WasmProvenTransaction { + pub account_id: u64, + pub initial_account_hash: Vec, + pub final_account_hash: Vec, + pub consumed_notes: Vec>, + pub created_notes: Vec>, + pub tx_script_root: Option>, + pub proof: Vec, +} + +impl From for WasmProvenTransaction { + fn from(proven_transaction: ProvenTransaction) -> WasmProvenTransaction { + let consumed_notes = proven_transaction + .consumed_notes() + .iter() + .map(|x| { + Into::<[Felt; 8]>::into(*x) + .iter() + .map(|x| x.as_int()) + .collect::>() + }) + .collect::>(); + let created_notes = proven_transaction + .created_notes() + .iter() + .map(|x| { + Into::<[Felt; 8]>::into(*x) + .iter() + .map(|x| x.as_int()) + .collect::>() + }) + .collect::>(); + + WasmProvenTransaction { + account_id: proven_transaction.account_id().into(), + initial_account_hash: Into::::into(proven_transaction.initial_account_hash()) + .into(), + final_account_hash: Into::::into(proven_transaction.final_account_hash()) + .into(), + consumed_notes, + created_notes, + tx_script_root: proven_transaction + .tx_script_root() + .and_then(|x| Some(Into::::into(x).into())), + proof: proven_transaction.proof().to_bytes(), + } + } +} + +// PROVE TRANSACTION +// ================================================================================================ + +#[wasm_bindgen] +pub fn prove_transaction() -> Result { + let data_store = MockDataStore::new(); + let mut executor = TransactionExecutor::new(data_store.clone()); + + let account_id = data_store.account.id(); + executor + .load_account(account_id) + .map_err(|err| format!("Failed to load account - {:?}", err))?; + + let block_ref = data_store.block_header.block_num().as_int() as u32; + let note_origins = data_store + .notes + .iter() + .take(1) + .map(|note| note.proof().as_ref().unwrap().origin().clone()) + .collect::>(); + + let prepared_transaction = executor + .prepare_transaction(data_store.account.id(), block_ref, ¬e_origins, None) + .map_err(|err| format!("Failed to prepare transaction - {:?}", err))?; + + let prover = TransactionProver::new(ProofOptions::default()); + let proven_transaction: WasmProvenTransaction = prover + .prove_prepared_transaction(prepared_transaction) + .map_err(|e| format!("Failed to prove prepared transaction - {:?}", e))? + .into(); + + let serializer = Serializer::new().serialize_large_number_types_as_bigints(true); + Ok(proven_transaction.serialize(&serializer)?) +} + +// VERIFY TRANSACTION TYPES +// ================================================================================================ + +#[wasm_bindgen(getter_with_clone)] +#[derive(Serialize, Deserialize, Debug)] +pub struct WasmVerifyTransactionResult { + pub success: bool, + pub proof: Vec, +} + +// VERIFY TRANSACTION +// ================================================================================================ + +#[wasm_bindgen] +pub fn verify_transaction() -> Result { + let data_store = MockDataStore::new(); + let mut executor = TransactionExecutor::new(data_store.clone()); + + let account_id = data_store.account.id(); + executor + .load_account(account_id) + .map_err(|err| format!("Failed to load account - {:?}", err))?; + + let block_ref = data_store.block_header.block_num().as_int() as u32; + let note_origins = data_store + .notes + .iter() + .take(1) + .map(|note| note.proof().as_ref().unwrap().origin().clone()) + .collect::>(); + + let prepared_transaction = executor + .prepare_transaction(data_store.account.id(), block_ref, ¬e_origins, None) + .map_err(|err| format!("Failed to prepare transaction - {:?}", err))?; + + let program_hash = prepared_transaction.tx_program().hash(); + let kernel = prepared_transaction.tx_program().kernel().clone(); + + let prover = TransactionProver::new(ProofOptions::default()); + let proven_transaction = prover + .prove_prepared_transaction(prepared_transaction) + .map_err(|e| format!("Failed to prove prepared transaction - {:?}", e))?; + + let stack_inputs = proven_transaction.stack_inputs(); + let stack_outputs = proven_transaction.stack_outputs(); + let program_info = ProgramInfo::new(program_hash, kernel); + let _result: u32 = miden_vm::verify( + program_info, + stack_inputs, + stack_outputs, + proven_transaction.proof().clone(), + ) + .map_err(|err| format!("Program failed verification! - {}", err))?; + + Ok(WasmVerifyTransactionResult { + success: true, + proof: proven_transaction.proof().to_bytes(), + }) +} + +// TESTS +// ================================================================================================ + +#[test] +fn test_verify_transaction() { + println!("{:?}", verify_transaction().unwrap()); +} diff --git a/playground/src/pages/CodingEnvironment.tsx b/playground/src/pages/CodingEnvironment.tsx index 3f8b37f..bd896ed 100644 --- a/playground/src/pages/CodingEnvironment.tsx +++ b/playground/src/pages/CodingEnvironment.tsx @@ -114,8 +114,6 @@ export default function CodingEnvironment(): JSX.Element { try { const start = Date.now(); const { stack_output, trace_len }: Outputs = run_program(code, inputs); - const verify = verify_transaction(); - console.log(verify); setOutput(`{ "stack_output" : [${stack_output.toString()}], "trace_len" : ${trace_len}