Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -17,6 +17,7 @@
- Fixed mismatched Push expectations in decoder syscall_block test ([#2207](https://github.com/0xMiden/miden-vm/pull/2207))
- [BREAKING] `Memory::read_element()` now requires `&self` instead of `&mut self` ([#2237](https://github.com/0xMiden/miden-vm/issues/2237))
- Added `proptest`'s `Arbitrary` instances for `Program`, fixed `Attribute` serialization ([#2224](https://github.com/0xMiden/miden-vm/pull/2224)).
- Fixed hex word parsing to guard against missing 0x prefix ([#2245](https://github.com/0xMiden/miden-vm/pull/2245)).

## 0.18.0 (2025-09-21)

Expand Down
41 changes: 40 additions & 1 deletion miden-vm/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,9 @@ impl InputFile {

/// Parse a `Word` from a hex string.
pub fn parse_word(word_hex: &str) -> Result<Word, String> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Theoretically, we should be able to replace this function with Word::try_from() - though, this would not support "incomplete strings" (i.e., the string would need to be 66 characters). Maybe it is worth updating how Word::try_from() works in miden-crypto? cc @huitseeker.

let word_value = &word_hex[2..];
let Some(word_value) = word_hex.strip_prefix("0x") else {
return Err(format!("failed to decode `Word` from hex {word_hex} - missing 0x prefix"));
};
let mut word_data = [0u8; 32];
hex::decode_to_slice(word_value, &mut word_data)
.map_err(|e| format!("failed to decode `Word` from hex {word_hex} - {e}"))?;
Expand Down Expand Up @@ -365,4 +367,41 @@ mod tests {
let merkle_store = inputs.parse_merkle_store().unwrap();
assert!(merkle_store.is_some());
}

#[test]
fn test_parse_word_missing_0x_prefix() {
let result = InputFile::parse_word(
"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
);
assert!(result.is_err());
assert!(result.unwrap_err().contains("missing 0x prefix"));
}

#[test]
fn test_parse_word_edge_cases() {
// Empty string
let result = InputFile::parse_word("");
assert!(result.is_err());
assert!(result.unwrap_err().contains("missing 0x prefix"));

// Just "0x" without hex data
let result = InputFile::parse_word("0x");
assert!(result.is_err());

// Too short hex (less than 64 chars after 0x)
let result = InputFile::parse_word("0x123");
assert!(result.is_err());
}

#[test]
fn test_parse_word_valid_hex() {
let valid_hex = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
let result = InputFile::parse_word(valid_hex);
assert!(result.is_ok());

// Test that the parsed word is not zero word
let word = result.unwrap();
let zero_word = Word::from([ZERO; 4]);
assert_ne!(word, zero_word);
}
}