Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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,233 changes: 664 additions & 569 deletions Cargo.lock

Large diffs are not rendered by default.

27 changes: 11 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ lto = true
inherits = "dev"
opt-level = 1

# Avoid running the expensive debug assertion in winter-prover
# https://github.com/facebook/winterfell/blob/cd32dce2fd4986c94516113568eefd938fafe31c/prover/src/lib.rs#L355C1-L356
[profile.test-dev.package.winter-prover]
debug-assertions = false

[profile.bench]
codegen-units = 1
lto = true
Expand All @@ -50,17 +45,17 @@ miden-tx = { default-features = false, path = "crates/miden-tx", ve
miden-tx-batch-prover = { default-features = false, path = "crates/miden-tx-batch-prover", version = "0.13" }

# Miden dependencies
miden-air = { default-features = false, version = "0.20" }
miden-assembly = { default-features = false, version = "0.20" }
miden-assembly-syntax = { default-features = false, version = "0.20" }
miden-core = { default-features = false, version = "0.20" }
miden-core-lib = { default-features = false, version = "0.20" }
miden-crypto = { default-features = false, version = "0.19" }
miden-mast-package = { default-features = false, version = "0.20" }
miden-processor = { default-features = false, version = "0.20" }
miden-prover = { default-features = false, version = "0.20" }
miden-utils-sync = { default-features = false, version = "0.20" }
miden-verifier = { default-features = false, version = "0.20" }
miden-air = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-assembly = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-assembly-syntax = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-core = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-core-lib = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-crypto = { default-features = false, version = "0.20.1" }
miden-mast-package = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-processor = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-prover = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-utils-sync = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }
miden-verifier = { branch = "next", default-features = false, git = "https://github.com/0xPolygonMiden/miden-vm" }

# External dependencies
anyhow = { default-features = false, features = ["backtrace", "std"], version = "1.0" }
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ clippy: ## Runs Clippy with configs

.PHONY: clippy-no-std
clippy-no-std: ## Runs Clippy with configs
cargo clippy --no-default-features --target wasm32-unknown-unknown --workspace --lib -- -D warnings
cargo clippy --no-default-features --target wasm32-unknown-unknown --workspace --lib --exclude bench-note-checker --exclude bench-transaction -- -D warnings


.PHONY: fix
Expand Down
2 changes: 1 addition & 1 deletion crates/miden-protocol-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ quote = "1.0"
syn = { features = ["extra-traits", "full"], version = "2.0" }

[dev-dependencies]
miden-protocol = { path = "../miden-protocol" }
miden-protocol = { default-features = false, path = "../miden-protocol" }

[package.metadata.cargo-machete]
ignored = ["proc-macro2"]
10 changes: 5 additions & 5 deletions crates/miden-protocol-macros/tests/integration_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#[cfg(test)]
mod tests {
use miden_protocol::{Felt, FieldElement, Word};
use miden_protocol::{Felt, ONE, Word, ZERO};
use miden_protocol_macros::WordWrapper;

#[derive(Debug, Clone, Copy, PartialEq, Eq, WordWrapper)]
Expand All @@ -9,15 +9,15 @@ mod tests {
#[test]
fn test_word_wrapper_accessors() {
// Create a test Word
let word = Word::from([Felt::ONE, Felt::ONE, Felt::ZERO, Felt::ZERO]);
let word = Word::from([ONE, ONE, ZERO, ZERO]);
// Use the new_unchecked method generated by the macro
let test_id = TestId::from_raw(word);

// Test as_elements
let elements = test_id.as_elements();
assert_eq!(elements.len(), 4);
assert_eq!(elements[0], Felt::ONE);
assert_eq!(elements[1], Felt::ONE);
assert_eq!(elements[0], ONE);
assert_eq!(elements[1], ONE);

// Test as_bytes
let bytes = test_id.as_bytes();
Expand All @@ -35,7 +35,7 @@ mod tests {
#[test]
fn test_new_unchecked_is_generated() {
// This test verifies that new_unchecked is generated by the macro
let word = Word::from([Felt::ONE, Felt::ONE, Felt::ZERO, Felt::ZERO]);
let word = Word::from([ONE, ONE, ZERO, ZERO]);
let test_id = TestId::from_raw(word);
assert_eq!(test_id.as_word(), word);
}
Expand Down
14 changes: 7 additions & 7 deletions crates/miden-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ std = [
"miden-processor/std",
"miden-verifier/std",
]
testing = ["dep:rand_chacha", "dep:rand_xoshiro", "dep:winter-rand-utils", "miden-air/testing"]
testing = ["dep:miden-test-utils", "dep:rand_chacha", "dep:rand_xoshiro", "miden-air/testing"]

[dependencies]
# Miden dependencies
Expand All @@ -43,9 +43,9 @@ miden-crypto = { workspace = true }
miden-mast-package = { workspace = true }
miden-processor = { workspace = true }
miden-protocol-macros = { workspace = true }
miden-test-utils = { branch = "next", git = "https://github.com/0xPolygonMiden/miden-vm", optional = true }
miden-utils-sync = { workspace = true }
miden-verifier = { workspace = true }
winter-rand-utils = { optional = true, version = "0.13" }

# External dependencies
bech32 = { default-features = false, features = ["alloc"], version = "0.11" }
Expand All @@ -65,19 +65,19 @@ getrandom = { features = ["wasm_js"], version = "0.3" }
anyhow = { features = ["backtrace", "std"], workspace = true }
assert_matches = { workspace = true }
criterion = { default-features = false, features = ["html_reports"], version = "0.5" }
miden-protocol = { features = ["testing"], path = "." }
miden-protocol = { default-features = false, features = ["testing"], path = "." }
pprof = { default-features = false, features = ["criterion", "flamegraph"], version = "0.15" }
rstest = { workspace = true }
tempfile = { version = "3.19" }
winter-air = { version = "0.13" }
# for HashFunction/ExecutionProof::new_dummy
color-eyre = { version = "0.5" }
miden-air = { features = ["std", "testing"], workspace = true }
miden-air = { default-features = false, features = ["std", "testing"], workspace = true }

[build-dependencies]
fs-err = { version = "3" }
miden-assembly = { workspace = true }
miden-core = { workspace = true }
miden-core-lib = { workspace = true }
miden-assembly = { default-features = false, workspace = true }
miden-core = { default-features = false, workspace = true }
miden-core-lib = { default-features = false, workspace = true }
regex = { version = "1.11" }
walkdir = { version = "2.5" }
17 changes: 13 additions & 4 deletions crates/miden-protocol/src/account/account_id/id_prefix.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use alloc::string::{String, ToString};
use core::fmt;

use miden_core::field::PrimeField64;

use super::v0;
use crate::Felt;
use crate::account::account_id::AccountIdPrefixV0;
Expand Down Expand Up @@ -162,8 +164,7 @@ impl AccountIdPrefix {
// Set the fungible bit to zero by taking the bitwise `and` of the felt with the
// inverted is_faucet mask.
let clear_fungible_bit_mask = !AccountIdV0::IS_FAUCET_MASK;
Felt::try_from(felt.as_int() & clear_fungible_bit_mask)
.expect("felt should still be valid as we cleared a bit and did not set any")
Felt::from(felt.as_int() & clear_fungible_bit_mask)
},
}
}
Expand Down Expand Up @@ -237,8 +238,16 @@ impl TryFrom<u64> for AccountIdPrefix {
/// Returns an error if any of the ID constraints are not met. See the [constraints
/// documentation](super::AccountId#constraints) for details.
fn try_from(value: u64) -> Result<Self, Self::Error> {
let element = Felt::try_from(value.to_le_bytes().as_slice())
.map_err(AccountIdError::AccountIdInvalidPrefixFieldElement)?;
// Validate that the value is within the field modulus
if value >= Felt::ORDER_U64 {
return Err(AccountIdError::AccountIdInvalidPrefixFieldElement(
DeserializationError::InvalidValue(format!(
"Value {} outside field modulus",
value
)),
));
}
let element = Felt::new(value);
Self::new(element)
}
}
Expand Down
46 changes: 34 additions & 12 deletions crates/miden-protocol/src/account/account_id/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use core::hash::Hash;

use bech32::Bech32m;
use bech32::primitives::decode::{ByteIter, CheckedHrpstring};
use miden_core::field::PrimeField64;
use miden_crypto::utils::hex_to_bytes;
pub use prefix::AccountIdPrefixV0;

Expand Down Expand Up @@ -118,8 +119,7 @@ impl AccountIdV0 {

let prefix_bytes =
bytes[0..8].try_into().expect("we should have sliced off exactly 8 bytes");
let prefix = Felt::try_from(u64::from_be_bytes(prefix_bytes))
.expect("should be a valid felt due to the most significant bit being zero");
let prefix = Felt::from(u64::from_be_bytes(prefix_bytes));

let mut suffix_bytes = [0; 8];
// Overwrite first 7 bytes, leaving the 8th byte 0 (which will be cleared by
Expand All @@ -130,8 +130,7 @@ impl AccountIdV0 {
let mut suffix = Felt::new(u64::from_be_bytes(suffix_bytes));

// Clear the most significant bit of the suffix.
suffix = Felt::try_from(suffix.as_int() & 0x7fff_ffff_ffff_ffff)
.expect("no bits were set so felt should still be valid");
suffix = Felt::from(suffix.as_int() & 0x7fff_ffff_ffff_ffff);

suffix = shape_suffix(suffix);

Expand Down Expand Up @@ -369,11 +368,34 @@ impl TryFrom<[u8; 15]> for AccountIdV0 {
let mut suffix_bytes = [0; 8];
suffix_bytes[1..8].copy_from_slice(suffix_slice);

let prefix = Felt::try_from(prefix_slice)
.map_err(AccountIdError::AccountIdInvalidPrefixFieldElement)?;

let suffix = Felt::try_from(suffix_bytes.as_slice())
.map_err(AccountIdError::AccountIdInvalidSuffixFieldElement)?;
// Convert prefix bytes to u64 and validate
let prefix_array: [u8; 8] = prefix_slice.try_into().map_err(|_| {
AccountIdError::AccountIdInvalidPrefixFieldElement(DeserializationError::InvalidValue(
"Invalid prefix byte length".to_string(),
))
})?;
let prefix_u64 = u64::from_le_bytes(prefix_array);
if prefix_u64 >= Felt::ORDER_U64 {
return Err(AccountIdError::AccountIdInvalidPrefixFieldElement(
DeserializationError::InvalidValue(format!(
"Prefix value {} outside field modulus",
prefix_u64
)),
));
}
let prefix = Felt::new(prefix_u64);

// Convert suffix bytes to u64 and validate
let suffix_u64 = u64::from_le_bytes(suffix_bytes);
if suffix_u64 >= Felt::ORDER_U64 {
return Err(AccountIdError::AccountIdInvalidSuffixFieldElement(
DeserializationError::InvalidValue(format!(
"Suffix value {} outside field modulus",
suffix_u64
)),
));
}
let suffix = Felt::new(suffix_u64);

Self::try_from([prefix, suffix])
}
Expand Down Expand Up @@ -509,7 +531,7 @@ fn shape_suffix(suffix: Felt) -> Felt {
suffix &= 0xffff_ffff_ffff_ff00;

// SAFETY: Felt was previously valid and we only cleared bits, so it must still be valid.
Felt::try_from(suffix).expect("no bits were set so felt should still be valid")
Felt::from(suffix)
}

// COMMON TRAIT IMPLS
Expand Down Expand Up @@ -562,8 +584,8 @@ mod tests {

#[test]
fn account_id_from_felts_with_max_pop_count() {
let valid_suffix = Felt::try_from(0x7fff_ffff_ffff_ff00u64).unwrap();
let valid_prefix = Felt::try_from(0x7fff_ffff_ffff_ff70u64).unwrap();
let valid_suffix = Felt::from(0x7fff_ffff_ffff_ff00u64);
let valid_prefix = Felt::from(0x7fff_ffff_ffff_ff70u64);

let id1 = AccountIdV0::new_unchecked([valid_prefix, valid_suffix]);
assert_eq!(id1.account_type(), AccountType::NonFungibleFaucet);
Expand Down
35 changes: 26 additions & 9 deletions crates/miden-protocol/src/account/account_id/v0/prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use core::fmt;
use core::hash::Hash;

use miden_core::Felt;
use miden_core::field::PrimeField64;
use miden_core::utils::{ByteReader, ByteWriter, Deserializable, Serializable};
use miden_processor::DeserializationError;

Expand Down Expand Up @@ -142,13 +143,21 @@ impl TryFrom<[u8; 8]> for AccountIdPrefixV0 {
/// See [`TryFrom<[u8; 8]> for
/// AccountIdPrefix`](crate::account::AccountIdPrefix#impl-TryFrom<%5Bu8;+8%
/// 5D>-for-AccountIdPrefix) for details.
fn try_from(mut value: [u8; 8]) -> Result<Self, Self::Error> {
// Felt::try_from expects little-endian order.
value.reverse();

Felt::try_from(value.as_slice())
.map_err(AccountIdError::AccountIdInvalidPrefixFieldElement)
.and_then(Self::new)
fn try_from(value: [u8; 8]) -> Result<Self, Self::Error> {
// Convert from big-endian bytes to u64
// (serialization uses to_be_bytes, so deserialization must use from_be_bytes)
let value_u64 = u64::from_be_bytes(value);
// Validate that the value is within the field modulus
if value_u64 >= Felt::ORDER_U64 {
return Err(AccountIdError::AccountIdInvalidPrefixFieldElement(
DeserializationError::InvalidValue(format!(
"Value {} is outside field modulus",
value_u64
)),
));
}
let element = Felt::new(value_u64);
Self::new(element)
}
}

Expand All @@ -159,8 +168,16 @@ impl TryFrom<u64> for AccountIdPrefixV0 {
/// AccountIdPrefix`](crate::account::AccountIdPrefix#impl-TryFrom<u64>-for-AccountIdPrefix)
/// for details.
fn try_from(value: u64) -> Result<Self, Self::Error> {
let element = Felt::try_from(value.to_le_bytes().as_slice())
.map_err(AccountIdError::AccountIdInvalidPrefixFieldElement)?;
// Validate that the value is within the field modulus
if value >= Felt::ORDER_U64 {
return Err(AccountIdError::AccountIdInvalidPrefixFieldElement(
DeserializationError::InvalidValue(format!(
"Value {} is outside field modulus",
value
)),
));
}
let element = Felt::new(value);
Self::new(element)
}
}
Expand Down
Loading
Loading