From b58bf352115ebba9e87dd50eda292c65491338a7 Mon Sep 17 00:00:00 2001 From: Dominik1999 Date: Wed, 11 Oct 2023 14:56:14 +0200 Subject: [PATCH 1/2] feat: writing ProgramAst to files --- assembly/src/ast/mod.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/assembly/src/ast/mod.rs b/assembly/src/ast/mod.rs index f423d1b6f1..044d35d7c6 100644 --- a/assembly/src/ast/mod.rs +++ b/assembly/src/ast/mod.rs @@ -10,6 +10,8 @@ use super::{ MAX_LABEL_LEN, }; use core::{fmt, iter, str::from_utf8}; +#[cfg(feature = "std")] +use std::{fs, io, path::Path}; use vm_core::utils::bound_into_included_u64; pub use super::tokens::SourceLocation; @@ -336,6 +338,23 @@ impl ProgramAst { pub fn clear_imports(&mut self) { self.import_info = None; } + + // WRITE TO FILE + // -------------------------------------------------------------------------------------------- + #[cfg(feature = "std")] + /// Writes ProgramAst to provided file path + pub fn write_to_file

(&self, dir_path: P) -> io::Result<()> + where + P: AsRef, + { + fs::create_dir_all(&dir_path)?; + let path = dir_path; + + let bytes = self.to_bytes(AstSerdeOptions { + serialize_imports: true, + }); + fs::write(path, bytes) + } } impl fmt::Display for ProgramAst { From c63d9ccdb54ab65cd256c96515034d2df45aa188 Mon Sep 17 00:00:00 2001 From: Bobbin Threadbare Date: Wed, 11 Oct 2023 14:46:25 -0700 Subject: [PATCH 2/2] feat: add serialization of masb files to the CLI --- CHANGELOG.md | 7 ++++- assembly/src/assembler/mod.rs | 14 +++++++-- assembly/src/ast/mod.rs | 11 ++++--- miden/src/cli/compile.rs | 15 ++++++--- miden/src/cli/data.rs | 59 +++++++++++++++++++++++++++-------- miden/src/cli/debug/mod.rs | 3 +- miden/src/cli/prove.rs | 3 +- miden/src/cli/run.rs | 3 +- miden/src/lib.rs | 13 +++++--- 9 files changed, 96 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3baa3b74..6c630e1e31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 0.7.0 (TBD) +## 0.7.0 (2023-10-11) #### Assembly - Added ability to attach doc comments to re-exported procedures (#994). @@ -12,6 +12,9 @@ - Added `debug` decorator (#1069). - Refactored `push` instruction so now it parses long hex string in little-endian (#1076). +#### CLI +- Implemented ability to output compiled `.masb` files to disk (#1102). + #### VM Internals - Simplified range checker and removed 1 main and 1 auxiliary trace column (#949). - Migrated range checker lookups to use LogUp and reduced the number of trace columns to 2 main and @@ -23,9 +26,11 @@ - Added `TraceLenSummary` struct which holds information about traces lengths to the `ExecutionTrace` (#1029). - Imposed the 2^32 limit for the memory addresses used in the memory chiplet (#1049). - Supported `PartialMerkleTree` as a secret input in `.input` file (#1072). +- [BREAKING] Refactored `AdviceProvider` interface into [Host] interface (#1082). #### Stdlib - Completed `std::collections::smt` module by implementing `insert` and `set` procedures (#1036, #1038, #1046). +- Added new module `std::crypto::dsa::rpo_falcon512` to support Falcon signature verification (#1000, #1094) ## 0.6.1 (2023-06-29) diff --git a/assembly/src/assembler/mod.rs b/assembly/src/assembler/mod.rs index 8dbd584fb0..af92112779 100644 --- a/assembly/src/assembler/mod.rs +++ b/assembly/src/assembler/mod.rs @@ -130,9 +130,19 @@ impl Assembler { let source = source.as_ref(); let program = ProgramAst::parse(source)?; + // compile the program and return + self.compile_ast(&program) + } + + /// Compiles the provided abstract syntax tree into a [Program]. The resulting program can be + /// executed on Miden VM. + /// + /// # Errors + /// Returns an error if the compilation of the specified program fails. + pub fn compile_ast(&self, program: &ProgramAst) -> Result { // compile the program - let mut context = AssemblyContext::for_program(Some(&program)); - let program_root = self.compile_in_context(&program, &mut context)?; + let mut context = AssemblyContext::for_program(Some(program)); + let program_root = self.compile_in_context(program, &mut context)?; // convert the context into a call block table for the program let cb_table = context.into_cb_table(&self.proc_cache.borrow())?; diff --git a/assembly/src/ast/mod.rs b/assembly/src/ast/mod.rs index 044d35d7c6..24e2d746b7 100644 --- a/assembly/src/ast/mod.rs +++ b/assembly/src/ast/mod.rs @@ -341,14 +341,17 @@ impl ProgramAst { // WRITE TO FILE // -------------------------------------------------------------------------------------------- - #[cfg(feature = "std")] + /// Writes ProgramAst to provided file path - pub fn write_to_file

(&self, dir_path: P) -> io::Result<()> + #[cfg(feature = "std")] + pub fn write_to_file

(&self, file_path: P) -> io::Result<()> where P: AsRef, { - fs::create_dir_all(&dir_path)?; - let path = dir_path; + let path = file_path.as_ref(); + if let Some(dir) = path.parent() { + fs::create_dir_all(dir)?; + } let bytes = self.to_bytes(AstSerdeOptions { serialize_imports: true, diff --git a/miden/src/cli/compile.rs b/miden/src/cli/compile.rs index 9eb5018b18..7b0de2e6ce 100644 --- a/miden/src/cli/compile.rs +++ b/miden/src/cli/compile.rs @@ -12,6 +12,9 @@ pub struct CompileCmd { /// Paths to .masl library files #[clap(short = 'l', long = "libraries", value_parser)] library_paths: Vec, + /// Path to output file + #[clap(short = 'o', long = "output", value_parser)] + output_file: Option, } impl CompileCmd { @@ -20,16 +23,20 @@ impl CompileCmd { println!("Compile program"); println!("============================================================"); + // load the program from file and parse it + let program = ProgramFile::read(&self.assembly_file)?; + // load libraries from files let libraries = Libraries::new(&self.library_paths)?; - // load program from file and compile - let program = ProgramFile::read(&self.assembly_file, &Debug::Off, libraries.libraries)?; + // compile the program + let compiled_program = program.compile(&Debug::Off, libraries.libraries)?; // report program hash to user - let program_hash: [u8; 32] = program.hash().into(); + let program_hash: [u8; 32] = compiled_program.hash().into(); println!("program hash is {}", hex::encode(program_hash)); - Ok(()) + // write the compiled file + program.write(self.output_file.clone()) } } diff --git a/miden/src/cli/data.rs b/miden/src/cli/data.rs index 17267b62ad..aef6b6b691 100644 --- a/miden/src/cli/data.rs +++ b/miden/src/cli/data.rs @@ -3,8 +3,8 @@ use miden::{ crypto::{MerkleStore, MerkleTree, NodeIndex, PartialMerkleTree, RpoDigest, SimpleSmt}, math::Felt, utils::{Deserializable, SliceReader}, - AdviceInputs, Assembler, Digest, ExecutionProof, MemAdviceProvider, Program, StackInputs, - StackOutputs, Word, + AdviceInputs, Assembler, Digest, ExecutionProof, MemAdviceProvider, Program, ProgramAst, + StackInputs, StackOutputs, Word, }; use serde_derive::{Deserialize, Serialize}; use std::{ @@ -69,7 +69,7 @@ pub enum MerkleData { pub struct InputFile { /// String representation of the initial operand stack, composed of chained field elements. pub operand_stack: Vec, - /// Opitonal string representation of the initial advice stack, composed of chained field + /// Optional string representation of the initial advice stack, composed of chained field /// elements. pub advice_stack: Option>, /// Optional map of 32 byte hex strings to vectors of u64s representing the initial advice map. @@ -371,21 +371,40 @@ impl OutputFile { // PROGRAM FILE // ================================================================================================ -pub struct ProgramFile; +pub struct ProgramFile { + ast: ProgramAst, + path: PathBuf, +} -/// Helper methods to interact with masm program file +/// Helper methods to interact with masm program file. impl ProgramFile { - pub fn read(path: &PathBuf, debug: &Debug, libraries: I) -> Result + /// Reads the masm file at the specified path and parses it into a [ProgramAst]. + pub fn read(path: &PathBuf) -> Result { + // read program file to string + println!("Reading program file `{}`", path.display()); + let source = fs::read_to_string(&path) + .map_err(|err| format!("Failed to open program file `{}` - {}", path.display(), err))?; + + // parse the program into an AST + print!("Parsing program... "); + let now = Instant::now(); + let ast = ProgramAst::parse(&source).map_err(|err| { + format!("Failed to parse program file `{}` - {}", path.display(), err) + })?; + println!("done ({} ms)", now.elapsed().as_millis()); + + Ok(Self { + ast, + path: path.clone(), + }) + } + + /// Compiles this program file into a [Program]. + pub fn compile(&self, debug: &Debug, libraries: I) -> Result where I: IntoIterator, L: Library, { - println!("Reading program file `{}`", path.display()); - - // read program file to string - let program_file = fs::read_to_string(&path) - .map_err(|err| format!("Failed to open program file `{}` - {}", path.display(), err))?; - print!("Compiling program... "); let now = Instant::now(); @@ -400,13 +419,27 @@ impl ProgramFile { .map_err(|err| format!("Failed to load libraries `{}`", err))?; let program = assembler - .compile(&program_file) + .compile_ast(&self.ast) .map_err(|err| format!("Failed to compile program - {}", err))?; println!("done ({} ms)", now.elapsed().as_millis()); Ok(program) } + + /// Writes this file into the specified path, if one is provided. If the path is not provided, + /// writes the file into the same directory as the source file, but with `.masb` extension. + pub fn write(&self, out_path: Option) -> Result<(), String> { + let out_path = out_path.unwrap_or_else(|| { + let mut out_file = self.path.clone(); + out_file.set_extension("masb"); + out_file + }); + + self.ast + .write_to_file(out_path) + .map_err(|err| format!("Failed to write the compiled file: {err}")) + } } // PROOF FILE diff --git a/miden/src/cli/debug/mod.rs b/miden/src/cli/debug/mod.rs index 96d5c0a676..bd683fde29 100644 --- a/miden/src/cli/debug/mod.rs +++ b/miden/src/cli/debug/mod.rs @@ -36,7 +36,8 @@ impl DebugCmd { let libraries = Libraries::new(&self.library_paths)?; // load program from file and compile - let program = ProgramFile::read(&self.assembly_file, &Debug::On, libraries.libraries)?; + let program = + ProgramFile::read(&self.assembly_file)?.compile(&Debug::On, libraries.libraries)?; let program_hash: [u8; 32] = program.hash().into(); println!("Debugging program with hash {}... ", hex::encode(program_hash)); diff --git a/miden/src/cli/prove.rs b/miden/src/cli/prove.rs index a6e0da9b32..eb9b7d8d33 100644 --- a/miden/src/cli/prove.rs +++ b/miden/src/cli/prove.rs @@ -75,7 +75,8 @@ impl ProveCmd { let libraries = Libraries::new(&self.library_paths)?; // load program from file and compile - let program = ProgramFile::read(&self.assembly_file, &Debug::Off, libraries.libraries)?; + let program = + ProgramFile::read(&self.assembly_file)?.compile(&Debug::Off, libraries.libraries)?; // load input data from file let input_data = InputFile::read(&self.input_file, &self.assembly_file)?; diff --git a/miden/src/cli/run.rs b/miden/src/cli/run.rs index 443265b8b4..f123093dd2 100644 --- a/miden/src/cli/run.rs +++ b/miden/src/cli/run.rs @@ -45,7 +45,8 @@ impl RunCmd { let libraries = Libraries::new(&self.library_paths)?; // load program from file and compile - let program = ProgramFile::read(&self.assembly_file, &Debug::Off, libraries.libraries)?; + let program = + ProgramFile::read(&self.assembly_file)?.compile(&Debug::Off, libraries.libraries)?; // load input data from file let input_data = InputFile::read(&self.input_file, &self.assembly_file)?; diff --git a/miden/src/lib.rs b/miden/src/lib.rs index c6158eb773..bb308090cf 100644 --- a/miden/src/lib.rs +++ b/miden/src/lib.rs @@ -4,14 +4,17 @@ // EXPORTS // ================================================================================================ -pub use assembly::{Assembler, AssemblyError, ParsingError}; +pub use assembly::{ + ast::{ModuleAst, ProgramAst}, + Assembler, AssemblyError, ParsingError, +}; pub use processor::{ crypto, execute, execute_iter, utils, AdviceInputs, AdviceProvider, AsmOpInfo, DefaultHost, - ExecutionError, ExecutionTrace, Host, Kernel, MemAdviceProvider, Operation, ProgramInfo, - StackInputs, VmState, VmStateIterator, ZERO, + ExecutionError, ExecutionTrace, Host, Kernel, MemAdviceProvider, Operation, Program, + ProgramInfo, StackInputs, VmState, VmStateIterator, ZERO, }; pub use prover::{ - math, prove, Digest, ExecutionProof, FieldExtension, HashFunction, InputError, Program, - ProvingOptions, StackOutputs, StarkProof, Word, + math, prove, Digest, ExecutionProof, FieldExtension, HashFunction, InputError, ProvingOptions, + StackOutputs, StarkProof, Word, }; pub use verifier::{verify, VerificationError};