Skip to content

Conversation

FrancoGiachetta
Copy link

@FrancoGiachetta FrancoGiachetta commented Aug 12, 2025

Summary

The purpose of this PR is to move QM31's implementation from Cairo VM to types-rs. It adds a wrapper over FieldElement<Stark252PrimeField> which allows a safer usage of QM31 operations.
The implemented set of operations only corresponds to the ones in Cairo VM.

Pull Request type

Please add the labels corresponding to the type of changes your PR introduces:

  • Feature

What is the current behavior?

QM31 is not implemented in types-rs

Resolves: #NA

What is the new behavior?

Add QM31Felt abstraction for performing QM31 operation in a safe manner.

Does this introduce a breaking change?

No

Other information

@FrancoGiachetta FrancoGiachetta changed the title Add qm31 Add QM31Felt implementation Aug 12, 2025
@FrancoGiachetta FrancoGiachetta marked this pull request as draft August 12, 2025 20:33
@FrancoGiachetta FrancoGiachetta marked this pull request as ready for review August 13, 2025 13:58
@tdelabro tdelabro requested a review from 0xLucqs August 20, 2025 22:14
/// Each of this limbs can be represented by 36 bits.
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct QM31([u64; 4]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

why are we using u64s here ?
and why a limb would be 36 bits ?
Shouldn't we also introduce CM31 as an intermediate type ?

Copy link
Author

Choose a reason for hiding this comment

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

why are we using u64s here

So that we can hold 36 bits.

and why a limb would be 36 bits ?

This is how it was implemented in Cairo VM. This is the commit which introduced it. The comments suggests QM31 is composted of 4 u64 limbs which represent 36 bit values, so 144 bits in total.

Shouldn't we also introduce CM31 as an intermediate type ?

This is implementation of a QM31. Instead of having two CM31, we have the four coordinates.

This PR migrates what was implemented in the Cairo VM. Is there anything you think should be changed?

Copy link
Collaborator

@0xLucqs 0xLucqs Aug 21, 2025

Choose a reason for hiding this comment

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

a felt in M31 is 31 bits i don't get why here it'd be 36, am i missing something ?

This PR migrates what was implemented in the Cairo VM.

I understand that but it feels weird to have the quartic EF and not the base field imo. Fine for now but i think the rest should be added in a follow up PR

Copy link
Author

@FrancoGiachetta FrancoGiachetta Aug 21, 2025

Choose a reason for hiding this comment

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

Found this comment from one of the commits that implemented this feature in Cairo VM. It explains why is was decided to use u64 as m31 representation. Seems it uses 36 bits for a m31 for an efficient Felt representation.
As you suggested, I think it's better to u32 instead of u64. I'll make this change. Sorry about the inconvenience.

Copy link
Author

Choose a reason for hiding this comment

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

Change the representation to u32 coordinates 020c0dc.

Copy link
Collaborator

Choose a reason for hiding this comment

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

you changed the coordinates to be [u32; 4] but 32*4 = 128.
We need 144 bits.
Which is 4,5 u32. So we need [u35; 5].

Or am I missing something?

Copy link
Author

Choose a reason for hiding this comment

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

I mess up with the docs in cairo VM. This firstly was implemented in the cairo VM and since it only operates with felts, a qm31 was always being packed into a Felt. For efficiency reasons (check this lambdaclass/cairo-vm#1944 (comment)), related to the multiplication operation, it's better to represent every M31 with 36 bits instead of 31 (as it should). This mens that, only in the felt representation, a QM31 is 144 bits long.

This implementation treats every M31 as 31 bit value. So only when packing a QM31 into a felt a M31 be represented with 36 bits now. This is why we still check that, when unpacking from a Felt, the value is no longer than 144 bits.

/// [QM31] constant that's equal to 0.
pub const ZERO: Self = Self([0, 0, 0, 0]);

pub fn inner(&self) -> [u32; 4] {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
pub fn inner(&self) -> [u32; 4] {
pub fn to_coordinates(&self) -> [u32; 4] {

Copy link
Author

Choose a reason for hiding this comment

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

Done in: edd3fa5

/// This method is convinient for performing multications and inversions,
/// in which operating with the coordinates could result in overflows if
/// the 32 bit representation was used.
fn inner_u64(&self) -> [u64; 4] {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
fn inner_u64(&self) -> [u64; 4] {
fn to_coordinates_u64(&self) -> [u64; 4] {

Copy link
Author

Choose a reason for hiding this comment

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

Done in: edd3fa5

Copy link
Collaborator

Choose a reason for hiding this comment

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

convinient -> convenient

Copy link
Collaborator

Choose a reason for hiding this comment

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

I didn't realize that renaming to to_coordinates_u64 would cause a clippy error. Maybe we can rename it to as_coordinates_u64 (or as_u64_coordinates) since it's private

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I ended up doing that

@tdelabro
Copy link
Collaborator

tdelabro commented Aug 21, 2025

@FrancoGiachetta We still need top level (//!) documentation to explain what "quadruple mersenne 31" is, and when it should be used.

@FrancoGiachetta
Copy link
Author

Hi @tdelabro! Added the requested top level docs.

@@ -1,3 +1,20 @@
//! A Cairo-like QM31 type.
//!
//! The QM31 type represents a Degree-4 extension the Mersenne 31 Field. This extension can be
Copy link
Collaborator

Choose a reason for hiding this comment

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

in the Mersenne 31 field ?
"in" missing + field don't have to be capitalized

Copy link
Author

Choose a reason for hiding this comment

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

Fix here: 7f3d6ef

//! The QM31 type represents a Degree-4 extension the Mersenne 31 Field. This extension can be
//! represented as two components of the Complex extension the Mersenne 31 Field as follows ((a, b), (c, d)), where
//! a, b, c and d represent a value from the Mersenne 31 Field, denotated as M31.
//! If anly a M31 was used by the verifier, then a 31 bit value wouldn't be enough to provide security
Copy link
Collaborator

Choose a reason for hiding this comment

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

"If any" typo
"a M31" is it "a" like the value you named "a" or a regular english word?

Copy link
Author

Choose a reason for hiding this comment

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

It refers to the value a named. This is to avoid repeating "a value from the Mersenne 31 field". The first typo is already fixed in this commit: b65e34b

//! A Cairo-like QM31 type.
//!
//! The QM31 type represents a Degree-4 extension in the Mersenne 31 field. This extension can be
//! represented as two components of the Complex extension the Mersenne 31 field as follows ((a, b), (c, d)), where
Copy link
Collaborator

Choose a reason for hiding this comment

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

of the Complex extension the Mersenne 31 field

It doesn't seem very clear, maybe a word is missing here?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I forgot to add an "in". Fix here: 6bad58f

//! The QM31 type represents a Degree-4 extension in the Mersenne 31 field. This extension can be
//! represented as two components of the Complex extension the Mersenne 31 field as follows ((a, b), (c, d)), where
//! a, b, c and d represent a value from the Mersenne 31 field, denotated as M31.
//! If only a M31 was used by the verifier, then a 31 bit value wouldn't be enough to provide security
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
//! If only a M31 was used by the verifier, then a 31 bit value wouldn't be enough to provide security
//! If only an M31 was used by the verifier, then a 31 bit value wouldn't be enough to provide security

Copy link
Author

Choose a reason for hiding this comment

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

Done here: 6bad58f

//! If only a M31 was used by the verifier, then a 31 bit value wouldn't be enough to provide security
//! to the verification. A QM31 not only provides an efficient arithmetic field, since it is composed of four M31 values, but
//! also allows for a more secure level of verification as it offers a 124 bit value. By using this extension,
//! the verifier is able to generate challeges with a proper level of randomness, ensuring the security of the protocol.
Copy link
Collaborator

Choose a reason for hiding this comment

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

the verifier is able

What verifier? The Cairo one?

Suggested change
//! the verifier is able to generate challeges with a proper level of randomness, ensuring the security of the protocol.
//! the verifier is able to generate challenges with a proper level of randomness, ensuring the security of the protocol.

Copy link
Author

Choose a reason for hiding this comment

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

A verifier in general. A 31 bit value is not enough to provided security since the range of random values is too short and vulnerable to brute-force attacks

Copy link
Author

Choose a reason for hiding this comment

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

fixed typo here: 6bad58f. Also changed the verifier for a verifier as the comment aims to a verifier in general.

Comment on lines 11 to 12
//! While the Cairo language's representation of QM31 consists of four `BoundedInt`s
//! simulating a 31 bit value, this implementation uses four 32 bit values.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would add the corresponding link to the cairo repo, at the end of this paragraph.

Copy link
Author

Choose a reason for hiding this comment

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

Done here: 6bad58f

Comment on lines 14 to 15
//! The conversion to a Felt is done by using the four elements of the struct, refered to as coordinates, as bytes and then
//! parsed as a little endian value. For a more efficient Felt representation, each coordinate is stored as a 36 bit. Hence,
Copy link
Collaborator

Choose a reason for hiding this comment

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

The conversion to a Felt is done by using the four elements of the struct, refered to as coordinates, as bytes

It doesn't seem very clear. I would briefly explain what a coordinate is and then describe the Felt conversion. That way you don't have to define coordinates in the middle of the description of the conversion.

Copy link
Author

@FrancoGiachetta FrancoGiachetta Aug 22, 2025

Choose a reason for hiding this comment

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

Done here: 035a87c

@FrancoGiachetta FrancoGiachetta changed the title Add QM31Felt implementation Add QM31 implementation Aug 25, 2025
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.

5 participants