Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add miden-package crate with Package type to represent a compiled Miden program/library. #1544

Open
wants to merge 29 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
759eed6
feature: add `miden-package` crate with `Package` type to represent
greenhat Oct 23, 2024
9360362
refactor: remove `Package::rodata`, swap `Package::digest` with `dige…
greenhat Nov 19, 2024
1358e28
refactor: add `Library`, `Program` with advice map constructors,
greenhat Nov 19, 2024
ca9bf14
fix: deserialize LibraryPath for Wasm CM interface named modules
greenhat Nov 25, 2024
82a7d5f
refactor: remove `ToElements` implementation for a byte array
greenhat Dec 18, 2024
809bda9
chore: update CHANGELOG.md
greenhat Dec 18, 2024
2920963
test: add proptest for `Package` roundtrip serialization
greenhat Dec 19, 2024
919bfec
refactor: implement `(De)Serializable` for `ProcedureName`,
greenhat Dec 20, 2024
9e3948c
test: add test deserializing Wasm CM name style `LibraryPath`
greenhat Dec 20, 2024
b1354c1
test: remove test deserializing a Miden package example build by the …
greenhat Dec 20, 2024
8aae530
chore: update package/README.md, clean up doc comments
greenhat Dec 20, 2024
ebc8311
chore: remove unused code and dependencies
greenhat Dec 20, 2024
4d031dd
docs: wording
greenhat Jan 16, 2025
15dfc12
docs: formatting
greenhat Jan 16, 2025
ae31949
docs: formatting
greenhat Jan 16, 2025
2d65242
docs: formatting
greenhat Jan 16, 2025
cc88636
docs: wording
greenhat Jan 16, 2025
86d8974
docs: wording
greenhat Jan 16, 2025
7e37745
chore: fix clippy, formatting, cleanup comments
greenhat Jan 16, 2025
43e0a83
refactor: rename types for resolved dependency for the `Package`
greenhat Jan 16, 2025
ab26b55
refactor: remove `SystemLibraryId` and use `DependencyName(String)`
greenhat Jan 17, 2025
ad3e722
chore: add license in package/README.md and fix docs.rs version in
greenhat Jan 17, 2025
3cd2d1b
refactor: serialize `Package` with `Serializable/Deserializable` impls
greenhat Jan 20, 2025
72b700e
refactor: make `PackageExport::name` to be `QualifiedProcedureName`,
greenhat Jan 20, 2025
a93f3a2
chore: formatting
greenhat Jan 20, 2025
8b60a31
chore: fix no_std build
greenhat Jan 21, 2025
37fe048
fix: relax `Ident` and `ProcedureName` validation, use checked
greenhat Jan 21, 2025
e3fa250
chore: export `Digest`, `MastForest`, `Program` in `miden-package`, c…
greenhat Jan 22, 2025
a1b44a7
refactor: move tests to serialization module, rename `package.rs` to
greenhat Jan 22, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Added `miden_core::mast::MastForest::advice_map` to load it into the advice provider before the `MastForest` execution (#1574).
- Optimized the computation of the DEEP queries in the recursive verifier (#1594).
- Added validity checks for the inputs to the recursive verifier (#1596).
- Added `miden-package` crate with `Package` type to represent a compiled Miden program/library (#1544).

## 0.11.0 (2024-11-04)

Expand Down
108 changes: 102 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"assembly",
"core",
"miden",
"package",
"processor",
"prover",
"stdlib",
Expand Down
51 changes: 50 additions & 1 deletion assembly/src/ast/procedure/name.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use alloc::{string::ToString, sync::Arc};
use alloc::{
string::{String, ToString},
sync::Arc,
};
use core::{
fmt,
hash::{Hash, Hasher},
str::FromStr,
};

use vm_core::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};

use crate::{
ast::{CaseKindError, Ident, IdentError},
diagnostics::{IntoDiagnostic, Report},
Expand Down Expand Up @@ -328,3 +333,47 @@ impl FromStr for ProcedureName {
Ok(Self(Ident::new_unchecked(Span::unknown(raw))))
}
}

impl Serializable for ProcedureName {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.as_str().write_into(target)
}
}

impl Deserializable for ProcedureName {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let str: String = source.read()?;
let proc_name =
ProcedureName::new_unchecked(Ident::new_unchecked(Span::unknown(Arc::from(str))));
Ok(proc_name)
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
}
}

// TESTS
// ================================================================================================

/// Tests
#[cfg(test)]
mod tests {
use vm_core::{
debuginfo::Span,
utils::{Deserializable, Serializable},
};

use super::ProcedureName;
use crate::ast::Ident;

#[test]
fn procedure_name_serialization_rustc_mangled() {
// Tests that rustc mangled symbols are serialized and deserialized
// see https://doc.rust-lang.org/rustc/symbol-mangling/v0.html#symbol-grammar-summary
let all_possible_chars_in_mangled_name =
plafer marked this conversation as resolved.
Show resolved Hide resolved
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.$";
let proc_name = ProcedureName::new_unchecked(Ident::new_unchecked(Span::unknown(
all_possible_chars_in_mangled_name.into(),
)));
let bytes = proc_name.to_bytes();
let deserialized = ProcedureName::read_from_bytes(&bytes).unwrap();
assert_eq!(proc_name, deserialized);
}
}
22 changes: 14 additions & 8 deletions assembly/src/library/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ use alloc::{

use vm_core::{
crypto::hash::RpoDigest,
debuginfo::Span,
mast::{MastForest, MastNodeId},
utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
Kernel,
AdviceMap, Kernel,
};

use crate::ast::{Ident, ProcedureName, QualifiedProcedureName};
use crate::ast::QualifiedProcedureName;

mod error;
mod module;
Expand Down Expand Up @@ -92,6 +91,16 @@ impl Library {

Ok(Self { digest, exports, mast_forest })
}

/// Produces a new library with the existing [`MastForest`] and provided advice map.
greenhat marked this conversation as resolved.
Show resolved Hide resolved
pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
let mut mast_forest = (*self.mast_forest).clone();
mast_forest.advice_map_mut().extend(advice_map);
Self {
mast_forest: Arc::new(mast_forest),
..self
}
}
}

// ------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -170,7 +179,7 @@ impl Serializable for Library {
target.write_usize(exports.len());
for (proc_name, proc_node_id) in exports {
proc_name.module.write_into(target);
proc_name.name.as_str().write_into(target);
proc_name.name.write_into(target);
target.write_u32(proc_node_id.as_u32());
}
}
Expand All @@ -187,10 +196,7 @@ impl Deserializable for Library {
let mut exports = BTreeMap::new();
for _ in 0..num_exports {
let proc_module = source.read()?;
let proc_name: String = source.read()?;
let proc_name = ProcedureName::new_unchecked(Ident::new_unchecked(Span::unknown(
Arc::from(proc_name),
)));
let proc_name = source.read()?;
let proc_name = QualifiedProcedureName::new(proc_module, proc_name);
let proc_node_id = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?;

Expand Down
45 changes: 43 additions & 2 deletions assembly/src/library/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use core::{
};

use smallvec::smallvec;
use vm_core::debuginfo::SourceSpan;

use crate::{
ast::{Ident, IdentError},
Expand Down Expand Up @@ -505,7 +506,26 @@ impl Deserializable for LibraryPath {
let path = source.read_slice(len)?;
let path =
str::from_utf8(path).map_err(|e| DeserializationError::InvalidValue(e.to_string()))?;
Self::new(path).map_err(|e| DeserializationError::InvalidValue(e.to_string()))
let path = LibraryPath::new(path).unwrap_or_else(|_| {
// Try to parse at least the namespace
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we expand the comment a bit here to explain what the code below is intending to cover? My understanding is:

If path is not a valid LibraryPath, we try to take the first "leg" of the path and use it as a namespace and the rest of the string as the module name. And if there is no first "leg", then we use Anon namespace and try to use the whole path as the module name.

If the above is correct, it is not clear to me what exactly we are trying to enable here. It seems like maybe we want to make sure that a path with no namespaces get Anon namespace? If so, could we simplify the code as:

LibraryPath::new(path).or_else(|_| {
    let module_id = Ident::new(path).map_err(|e| {
        DeserializationError::InvalidValue(format!("Invalid module id: {}", e))
    })?;
    Ok(LibraryPath::new_from_components(LibraryNamespace::Anon, [module_id]))
}

match LibraryNamespace::strip_path_prefix(path) {
Ok((ns, rest)) => {
let module_id = Ident::new_unchecked(Span::new(
SourceSpan::default(),
Arc::from(rest.to_string()),
));
LibraryPath::new_from_components(ns, [module_id])
},
Err(_) => {
let module_id = Ident::new_unchecked(Span::new(
SourceSpan::default(),
Arc::from(path.to_string()),
));
LibraryPath::new_from_components(LibraryNamespace::Anon, [module_id])
},
bobbinth marked this conversation as resolved.
Show resolved Hide resolved
}
});
Ok(path)
}
}

Expand Down Expand Up @@ -537,9 +557,16 @@ fn validate_component(component: &str) -> Result<(), PathError> {
/// Tests
#[cfg(test)]
mod tests {
use vm_core::assert_matches;
use std::sync::Arc;

use vm_core::{
assert_matches,
debuginfo::{SourceSpan, Span},
utils::{Deserializable, Serializable},
};

use super::{super::LibraryNamespaceError, IdentError, LibraryPath, PathError};
use crate::{alloc::string::ToString, ast::Ident, LibraryNamespace};

#[test]
fn new_path() {
Expand Down Expand Up @@ -588,4 +615,18 @@ mod tests {
Err(PathError::InvalidNamespace(LibraryNamespaceError::InvalidStart))
);
}

#[test]
fn path_serialization_wasm_cm_style_module_name() {
// Tests that Wasm Component Model names are serialized and deserialized correctly
let wasm_cm_style_module_name = "namespace:package/[email protected]";
let module_id = Ident::new_unchecked(Span::new(
SourceSpan::default(),
Arc::from(wasm_cm_style_module_name.to_string()),
));
let path = LibraryPath::new_from_components(LibraryNamespace::Anon, [module_id]);
let bytes = path.to_bytes();
let deserialized = LibraryPath::read_from_bytes(&bytes).unwrap();
assert_eq!(path, deserialized);
}
}
Loading
Loading