Skip to content

refactor: swap Goldilocks re-export to the Felt type unified for off-chain and on-chain code#819

Draft
greenhat wants to merge 5 commits intomainfrom
greenhat-unified-felt
Draft

refactor: swap Goldilocks re-export to the Felt type unified for off-chain and on-chain code#819
greenhat wants to merge 5 commits intomainfrom
greenhat-unified-felt

Conversation

@greenhat
Copy link
Collaborator

@greenhat greenhat commented Feb 6, 2026

Close #771

This PR swaps the p3_goldilocks::Goldilocks as Felt re-export to the wrapper Felt(p3_goldilocks::Goldilocks) type for non-Miden targets. For the Miden target Felt(f32) is compiled (see explanation in #771).
Besides that Word type is changed to have the WIT-compatible shape (struct with a named field).

All Felt methods and implemented traits are delegating everything to the underlying Goldilocks type and its trait implementations. So the Felt should be 100% API equivalent to the Goldilocks type and can be used as a drop-in replacement. This allows us to release it as a v0.22.x patch version so that it can be included in VM v0.21 release. That's why I made this PR against the main branch.

The corresponding PR in the VM repo that updates VM to the version of miden-crypto from this branch is 0xMiden/miden-vm#2649.

The corresponding PR in the compiler repo migrating to the miden-field crate from this PR is 0xMiden/compiler#923

TODO:

  • convert Word shape to named fields (a, b, c, d);
  • impl Arbitrary for Felt;
  • convert to proptest in miden-field/src/word/tests.rs;
  • rebase;
  • test in VM branch;

@greenhat greenhat changed the title refactor: add Felt type unified for off-chain and on-chain code refactor: swap Goldilocks re-export to the Felt type unified for off-chain and on-chain code Feb 6, 2026
@greenhat greenhat force-pushed the greenhat-unified-felt branch from f38f76c to bff706b Compare February 9, 2026 07:59
make `Word` type to have the WIT-compatible shape
Copy link
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

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

Some concerns with unsafe conversions, and questions inline.

///
/// # Safety
/// This assumes `(Felt, Felt, Felt, Felt)` has the same memory layout as `[Felt; 4]`.
fn as_elements_array(&self) -> &[Felt; WORD_SIZE_FELT] {
Copy link
Contributor

Choose a reason for hiding this comment

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

The cast from &(Felt, Felt, Felt, Felt) to &[Felt; 4] indeed assumes identical memory layout, but Rust does not guarantee tuple layout. This could lead to UB if the compiler changes layout.

I'd suggest adding compile-time assertions like const_assert!(size_of::<(Felt, Felt, Felt, Felt)>() == size_of::<[Felt; 4]>()); at least (and a proptest) to verify the assumption of equivalence at build (/test) time.

@@ -161,14 +208,13 @@ impl Word {
where
I: Iterator<Item = &'a Self>,
{
words.flat_map(|d| d.0.iter())
words.flat_map(|d| d.as_elements().iter())
}

/// Returns all elements of multiple words as a slice.
pub fn words_as_elements(words: &[Self]) -> &[Felt] {
Copy link
Contributor

Choose a reason for hiding this comment

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

words_as_elements casts &[Word] to &[Felt] via raw pointer. With #[repr(C, align(16))] on Word, this assumes no padding between elements and specific field ordering. Suggest adding const_assert! checks for size and alignment, or using the safe words_as_elements_iter instead where performance allows.

@@ -0,0 +1,20 @@
//! A unified `Felt` for Miden Rust code.
Copy link
Contributor

Choose a reason for hiding this comment

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

The new miden-field crate has no tests. Since this is cryptographic code used throughout the codebase, consider adding unit tests for both the native and WASM implementations to ensure correctness of field operations.

Comment on lines +46 to +49
// We cannot define this type as `Word([Felt;4])` since there is no struct tuple support
// and fixed array support is not complete in WIT. For the type remapping to work the
// bindings are expecting the remapped type to be the same shape as the one generated from
// WIT.
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it not be possible to use:

  #[repr(C)]
  pub struct Word {
      a: Felt,
      b: Felt,
      c: Felt,
      d: Felt,
  }

from a WIT PoV, or do you need the tuple?

Because that is layout-compatible with [Felt; 4].

@greenhat greenhat marked this pull request as draft February 10, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants