From 3066f02493fdec607b28c6aee55ca122a4944ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 23 Sep 2025 12:14:56 -0300 Subject: [PATCH 1/2] Fix typo in MAX constant --- crates/starknet-types-core/src/qm31/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/starknet-types-core/src/qm31/mod.rs b/crates/starknet-types-core/src/qm31/mod.rs index d9a5bf3..ec0988e 100644 --- a/crates/starknet-types-core/src/qm31/mod.rs +++ b/crates/starknet-types-core/src/qm31/mod.rs @@ -208,7 +208,7 @@ mod test { #[test] fn qm31_packing() { - const MAX: u32 = MERSENNE_31_PRIME_FIELD_ORDER - 2; + const MAX: u32 = MERSENNE_31_PRIME_FIELD_ORDER - 1; let cases = [ [1, 2, 3, 4], From 7d0082b1581ee86fc75a175f824ee25f6a494802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Gonz=C3=A1lez=20Calder=C3=B3n?= Date: Tue, 23 Sep 2025 12:30:01 -0300 Subject: [PATCH 2/2] Use representative instead of to_raw when obtaining QM31 coefficients --- crates/starknet-types-core/src/qm31/mod.rs | 36 +++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/crates/starknet-types-core/src/qm31/mod.rs b/crates/starknet-types-core/src/qm31/mod.rs index ec0988e..ea89d8b 100644 --- a/crates/starknet-types-core/src/qm31/mod.rs +++ b/crates/starknet-types-core/src/qm31/mod.rs @@ -62,7 +62,12 @@ impl QM31 { let [c1, c2] = a.value(); let [c3, c4] = b.value(); - (c1.to_raw(), c2.to_raw(), c3.to_raw(), c4.to_raw()) + ( + c1.representative(), + c2.representative(), + c3.representative(), + c4.representative(), + ) } /// Packs the [QM31] into a [Felt]. @@ -262,4 +267,33 @@ mod test { QM31::unpack_from_felt(&invalid_packing).unwrap_err(); } + + /// Tests the QM31 packing when some coefficients have a value of PRIME. + /// + /// If we try to create an M31 with a value of PRIME, it won't be reduced + /// to 0 internally. This tests verifies that a PRIME coefficient is being + /// packed as its representative value, instead of the raw value. + #[test] + fn qm31_packing_with_prime_coefficients() { + const PRIME: u32 = MERSENNE_31_PRIME_FIELD_ORDER; + + let cases = [ + [PRIME, 0, 0, 0], + [0, PRIME, 0, 0], + [0, 0, PRIME, 0], + [0, 0, 0, PRIME], + ]; + + for [c1, c2, c3, c4] in cases { + let qm31 = QM31::from_coefficients(c1, c2, c3, c4); + let packed_qm31 = qm31.pack_into_felt(); + + let expected_packing = BigInt::from(c1 % PRIME) + + (BigInt::from(c2 % PRIME) << 36) + + (BigInt::from(c3 % PRIME) << 72) + + (BigInt::from(c4 % PRIME) << 108); + + assert_eq!(packed_qm31, Felt::from(expected_packing)) + } + } }