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 all 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
70 changes: 64 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
2 changes: 1 addition & 1 deletion air/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ winter-prover = { package = "winter-prover", version = "0.11", default-features

[dev-dependencies]
criterion = "0.5"
proptest = "1.5"
proptest = "1.6"
rand-utils = { package = "winter-rand-utils", version = "0.11" }
6 changes: 5 additions & 1 deletion assembly/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ doctest = false
[features]
default = ["std"]
std = ["aho-corasick/std", "miette/fancy", "miette/std", "vm-core/std", "thiserror/std"]
testing = ["dep:regex"]
testing = ["dep:regex", "dep:proptest", "dep:proptest-derive"]

[dependencies]
aho-corasick = { version = "1.1", default-features = false }
Expand All @@ -29,6 +29,10 @@ miette = { package = "miden-miette", version = "8.0", default-features = false,
"fancy-no-syscall",
"derive"
] }
proptest = { version = "1.6", optional = true, default-features = false, features = [
"no_std", "alloc"
] }
proptest-derive = { version = "0.5", optional = true, default-features = false }
regex = { version = "1.10", optional = true, default-features = false, features = ["unicode", "perf"] }
smallvec = { version = "1.13", features = ["union", "const_generics", "const_new"] }
thiserror = { workspace = true }
Expand Down
5 changes: 4 additions & 1 deletion assembly/src/ast/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@ impl Ident {
if !source.starts_with(|c: char| c.is_ascii_alphabetic()) {
return Err(IdentError::InvalidStart);
}
if !source.chars().all(|c| c.is_ascii_alphabetic() || matches!(c, '_' | '0'..='9')) {
if !source
.chars()
.all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-' | ':' | '/' | '@' | '.'))
{
return Err(IdentError::InvalidChars { ident: source.into() });
}
Ok(())
Expand Down
87 changes: 84 additions & 3 deletions 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 All @@ -20,8 +25,10 @@ use crate::{
/// A qualified procedure name can be context-sensitive, i.e. the module path might refer
/// to an imported
#[derive(Clone)]
#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
pub struct QualifiedProcedureName {
/// The source span associated with this identifier.
#[cfg_attr(feature = "testing", proptest(value = "SourceSpan::default()"))]
pub span: SourceSpan,
/// The module path for this procedure.
pub module: LibraryPath,
Expand Down Expand Up @@ -116,6 +123,21 @@ impl fmt::Display for QualifiedProcedureName {
}
}

impl Serializable for QualifiedProcedureName {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.module.write_into(target);
self.name.write_into(target);
}
}

impl Deserializable for QualifiedProcedureName {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let module = LibraryPath::read_from(source)?;
let name = ProcedureName::read_from(source)?;
Ok(Self::new(module, name))
}
}

// PROCEDURE NAME
// ================================================================================================

Expand Down Expand Up @@ -311,10 +333,12 @@ impl FromStr for ProcedureName {
break Err(IdentError::InvalidChars { ident: s.into() });
}
},
Some((_, c)) if c.is_ascii_lowercase() || c == '_' || c == '$' => {
Some((_, c))
if c.is_ascii_lowercase() || c == '_' || c == '-' || c == '$' || c == '.' =>
{
if chars.as_str().contains(|c| match c {
Comment on lines +336 to +338
Copy link
Contributor

Choose a reason for hiding this comment

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

Not for this PR, but the code in this function is a bit difficult to follow. Let's create an issue (could be a "good first issue") to make the code more readable.

c if c.is_ascii_alphanumeric() => false,
'_' | '$' => false,
'_' | '-' | '$' | '.' => false,
_ => true,
}) {
Err(IdentError::InvalidChars { ident: s.into() })
Expand All @@ -328,3 +352,60 @@ 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(str)
.map_err(|e| DeserializationError::InvalidValue(e.to_string()))?;
Ok(proc_name)
}
}

// ARBITRARY IMPLEMENTATION
// ================================================================================================

#[cfg(feature = "testing")]
impl proptest::prelude::Arbitrary for ProcedureName {
type Parameters = ();

fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
use proptest::prelude::*;
// see https://doc.rust-lang.org/rustc/symbol-mangling/v0.html#symbol-grammar-summary
let all_possible_chars_in_mangled_name =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.$";
let mangled_rustc_name = ProcedureName::new(all_possible_chars_in_mangled_name).unwrap();
let plain = ProcedureName::new("user_func").unwrap();
let wasm_cm_style = ProcedureName::new("kebab-case-func").unwrap();
prop_oneof![Just(mangled_rustc_name), Just(plain), Just(wasm_cm_style)].boxed()
}

type Strategy = proptest::prelude::BoxedStrategy<Self>;
}

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

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

use super::ProcedureName;

proptest! {
#[test]
fn procedure_name_serialization_roundtrip(path in any::<ProcedureName>()) {
let bytes = path.to_bytes();
let deserialized = ProcedureName::read_from_bytes(&bytes).unwrap();
assert_eq!(path, deserialized);
}
}
}
23 changes: 15 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,17 @@ impl Library {

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

/// Produces a new library with the existing [`MastForest`] and where all key/values in the
/// provided advice map are added to the internal advice map.
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 +180,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 +197,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
Loading
Loading