Skip to content

Feat: Kaspa-Math 32 bit malachite support#889

Draft
hmoog wants to merge 3 commits intokaspanet:masterfrom
hmoog:feat/kaspa-math-32bit
Draft

Feat: Kaspa-Math 32 bit malachite support#889
hmoog wants to merge 3 commits intokaspanet:masterfrom
hmoog:feat/kaspa-math-32bit

Conversation

@hmoog
Copy link

@hmoog hmoog commented Feb 27, 2026

This PR fixes a compilation failure when kaspa-math is used in a workspace alongside risc0-based crates.

Problem

kaspa-math's mod_inverse passes its internal [u64; N] limb array directly to malachite's Natural::from_limbs_asc(&[Limb]), assuming Limb = u64. This breaks when malachite's 32_bit_limbs feature is enabled, causing a type
mismatch (expected &[u32], found &[u64; N]).

Root cause: Cargo feature unification

malachite-nz has an optional 32_bit_limbs feature that switches Limb from u64 to u32. By default it is disabled, so Limb = u64 and kaspa-math compiles fine in the rusty-kaspa workspace.

However, Cargo unifies features across an entire workspace. In the vprogs workspace, risc0-circuit-rv32im (RISC Zero zkVM) depends on malachite with:

features = ["naturals_and_integers", "32_bit_limbs"]

This activates 32_bit_limbs globally - including for kaspa-math - making Limb = u32 and breaking mod_inverse.

Fix

Make mod_inverse generic over the Limb type by converting between the internal u64 words and malachite Limbs at the boundary:

  • u64 → Limb (input): When Limb is 32-bit, each u64 word is split into two u32 limbs (low, high) in little-endian order. When Limb is 64-bit, the words pass through directly.
  • Limb → u64 (output): The inverse operation - pairs of u32 limbs are reassembled into u64 words.

The size_of::() check is a compile-time constant, so the compiler eliminates the unused branch entirely - zero runtime cost.

@coderofstuff coderofstuff requested a review from elichai February 28, 2026 04:55
// feature is enabled (e.g. by risc0 via Cargo feature unification).
// On little-endian, [u64; N] and [Limb; N * 8/sizeof(Limb)] have
// identical byte layouts, so we reinterpret directly without copying.
#[cfg(not(target_endian = "little"))]
Copy link
Contributor

Choose a reason for hiding this comment

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

we can allow not(target_endian = "little") if core::mem::size_of::<u64>() == core::mem::size_of::<Limb>()

@biryukovmaxim
Copy link
Collaborator

biryukovmaxim commented Mar 4, 2026

https://github.com/biryukovmaxim/rusty-kaspa/blob/e77acc2afb1950ffdffb568e467cd4f6005761d3/Cargo.toml#L222-L223
I had the same issue and solved it by enforcing different major version of malachite. I still consider it as a workaround but at least it doesn't force 32 bit on host/kaspad which I would see wrong

@michaelsutton michaelsutton marked this pull request as draft March 4, 2026 12:25
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.

3 participants