Skip to content

Commit 21ec03e

Browse files
change qm31 representation, remove outdated comments
1 parent 176c1de commit 21ec03e

File tree

1 file changed

+27
-49
lines changed
  • crates/starknet-types-core/src/felt

1 file changed

+27
-49
lines changed

crates/starknet-types-core/src/felt/qm31.rs

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use core::fmt;
22

33
use crate::felt::Felt;
4-
use lambdaworks_math::field::{
5-
element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField,
6-
};
74

85
pub const STWO_PRIME: u64 = (1 << 31) - 1;
96
const STWO_PRIME_U128: u128 = STWO_PRIME as u128;
@@ -12,7 +9,7 @@ const MASK_8: u64 = (1 << 8) - 1;
129

1310
#[derive(Debug)]
1411
pub enum QM31Error {
15-
InvalidQM31(Felt),
12+
FeltTooBig(Felt),
1613
}
1714

1815
#[cfg(feature = "std")]
@@ -21,7 +18,7 @@ impl std::error::Error for QM31Error {}
2118
impl fmt::Display for QM31Error {
2219
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2320
match self {
24-
QM31Error::InvalidQM31(felt) => writeln!(
21+
QM31Error::FeltTooBig(felt) => writeln!(
2522
f,
2623
"Number used as QM31 since it's more than 144 bits long: {}",
2724
felt
@@ -32,23 +29,15 @@ impl fmt::Display for QM31Error {
3229

3330
#[repr(transparent)]
3431
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
35-
pub struct QM31Felt(pub(crate) FieldElement<Stark252PrimeField>);
32+
pub struct QM31Felt([u64; 4]);
3633

3734
impl QM31Felt {
3835
/// [QM31Felt] constant that's equal to 0.
39-
pub const ZERO: Self = Self(FieldElement::<Stark252PrimeField>::from_hex_unchecked("0"));
36+
pub const ZERO: Self = Self([0, 0, 0, 0]);
4037

41-
/// Reads four u64 coordinates from a single Felt. STWO_PRIME fits in 36 bits, hence each coordinate
42-
/// can be represented by 36 bits and a QM31 element can be stored in the first 144 bits of a Felt.
38+
4339
pub fn as_raw(&self) -> [u64; 4] {
44-
let limbs = self.as_le_digits();
45-
46-
[
47-
(limbs[0] & MASK_36),
48-
((limbs[0] >> 36) + ((limbs[1] & MASK_8) << 28)),
49-
((limbs[1] >> 8) & MASK_36),
50-
((limbs[1] >> 44) + (limbs[2] << 20)),
51-
]
40+
self.0
5241
}
5342

5443
/// Create a [QM31Felt] from the raw internal representation. Reduces four u64 coordinates and packs them
@@ -61,17 +50,25 @@ impl QM31Felt {
6150
let bytes_part2 = ((coordinates[2] % STWO_PRIME) as u128
6251
+ (((coordinates[3] % STWO_PRIME) as u128) << 36))
6352
.to_le_bytes();
64-
let mut result_bytes = [0u8; 32];
53+
let mut result_bytes = [0; 32];
54+
6555
result_bytes[0..9].copy_from_slice(&bytes_part1[0..9]);
6656
result_bytes[9..18].copy_from_slice(&bytes_part2[0..9]);
6757

68-
let value = Felt::from_bytes_le(&result_bytes);
58+
let limbs = {
59+
let felt = Felt::from_bytes_le_slice(&result_bytes);
60+
felt.to_le_digits()
61+
};
6962

70-
Self(value.0)
63+
Self([
64+
(limbs[0] & MASK_36),
65+
((limbs[0] >> 36) + ((limbs[1] & MASK_8) << 28)),
66+
((limbs[1] >> 8) & MASK_36),
67+
((limbs[1] >> 44) + (limbs[2] << 20)),
68+
])
7169
}
7270

7371
/// Computes the addition of two QM31 elements in reduced form.
74-
/// Returns an error if either operand is not reduced.
7572
pub fn add(&self, rhs: &QM31Felt) -> QM31Felt {
7673
let coordinates1 = self.as_raw();
7774
let coordinates2 = rhs.as_raw();
@@ -85,7 +82,6 @@ impl QM31Felt {
8582
}
8683

8784
/// Computes the negative of a QM31 element in reduced form.
88-
/// Returns an error if the input is not reduced.
8985
pub fn neg(&self) -> QM31Felt {
9086
let coordinates = self.as_raw();
9187
Self::from_raw([
@@ -97,7 +93,6 @@ impl QM31Felt {
9793
}
9894

9995
/// Computes the subtraction of two QM31 elements in reduced form.
100-
/// Returns an error if either operand is not reduced.
10196
pub fn sub(&self, rhs: &QM31Felt) -> QM31Felt {
10297
let coordinates1 = self.as_raw();
10398
let coordinates2 = rhs.as_raw();
@@ -111,7 +106,6 @@ impl QM31Felt {
111106
}
112107

113108
/// Computes the multiplication of two QM31 elements in reduced form.
114-
/// Returns an error if either operand is not reduced.
115109
pub fn mul(&self, rhs: &QM31Felt) -> QM31Felt {
116110
let coordinates1_u64 = self.as_raw();
117111
let coordinates2_u64 = rhs.as_raw();
@@ -147,7 +141,7 @@ impl QM31Felt {
147141

148142
/// Computes the inverse in the M31 field using Fermat's little theorem, i.e., returns
149143
/// `v^(STWO_PRIME-2) modulo STWO_PRIME`, which is the inverse of v unless v % STWO_PRIME == 0.
150-
fn pow2147483645(v: u64) -> u64 {
144+
fn m31_inverse(v: u64) -> u64 {
151145
let t0 = (Self::sqn(v, 2) * v) % STWO_PRIME;
152146
let t1 = (Self::sqn(t0, 1) * t0) % STWO_PRIME;
153147
let t2 = (Self::sqn(t1, 3) * t0) % STWO_PRIME;
@@ -167,7 +161,6 @@ impl QM31Felt {
167161
}
168162

169163
/// Computes the inverse of a QM31 element in reduced form.
170-
/// Returns an error if the denominator is zero or either operand is not reduced.
171164
/// # Safety
172165
/// If the value is zero will panic.
173166
pub fn inverse(&self) -> QM31Felt {
@@ -190,7 +183,7 @@ impl QM31Felt {
190183
(2 * coordinates[0] * coordinates[1] + 3 * STWO_PRIME - 2 * b2_i - b2_r) % STWO_PRIME;
191184

192185
let denom_norm_squared = (denom_r * denom_r + denom_i * denom_i) % STWO_PRIME;
193-
let denom_norm_inverse_squared = Self::pow2147483645(denom_norm_squared);
186+
let denom_norm_inverse_squared = Self::m31_inverse(denom_norm_squared);
194187

195188
let denom_inverse_r = (denom_r * denom_norm_inverse_squared) % STWO_PRIME;
196189
let denom_inverse_i = ((STWO_PRIME - denom_i) * denom_norm_inverse_squared) % STWO_PRIME;
@@ -208,7 +201,6 @@ impl QM31Felt {
208201
}
209202

210203
/// Computes the division of two QM31 elements in reduced form.
211-
/// Returns an error if the input is zero.
212204
/// # Safety
213205
/// Will panic if the rhs value is equal to zero.
214206
pub fn div(&self, rhs: &QM31Felt) -> Result<QM31Felt, QM31Error> {
@@ -219,31 +211,17 @@ impl QM31Felt {
219211
pub fn is_zero(&self) -> bool {
220212
*self == Self::ZERO
221213
}
222-
223-
/// Convert `self`'s representative into an array of `u64` digits,
224-
/// least significant digits first.
225-
pub fn as_le_digits(&self) -> [u64; 4] {
226-
let mut limbs = self.0.representative().limbs;
227-
limbs.reverse();
228-
limbs
229-
}
230-
231-
/// Convert `self`'s representative into an array of `u64` digits,
232-
/// most significant digits first.
233-
pub fn as_be_digits(&self) -> [u64; 4] {
234-
self.0.representative().limbs
235-
}
236214
}
237215

238216
impl From<&QM31Felt> for Felt {
239217
fn from(value: &QM31Felt) -> Self {
240-
Felt(value.0)
218+
Felt::from_raw(value.0)
241219
}
242220
}
243221

244222
impl From<QM31Felt> for Felt {
245223
fn from(value: QM31Felt) -> Self {
246-
Felt(value.0)
224+
Felt::from_raw(value.0)
247225
}
248226
}
249227

@@ -257,10 +235,10 @@ impl TryFrom<Felt> for QM31Felt {
257235
// because we are trying to convert a Felt into a QM31Felt. This
258236
// Felt should represent a packed QM31 which is at most 144 bits long.
259237
if limbs[3] != 0 || limbs[2] >= 1 << 16 {
260-
return Err(QM31Error::InvalidQM31(value));
238+
return Err(QM31Error::FeltTooBig(value));
261239
}
262240

263-
Ok(Self(value.0))
241+
Ok(Self(limbs))
264242
}
265243
}
266244

@@ -274,10 +252,10 @@ impl TryFrom<&Felt> for QM31Felt {
274252
// because we are trying to convert a Felt into a QM31Felt. This
275253
// Felt should represent a packed QM31 which is at most 144 bits long.
276254
if limbs[3] != 0 || limbs[2] >= 1 << 16 {
277-
return Err(QM31Error::InvalidQM31(*value));
255+
return Err(QM31Error::FeltTooBig(*value));
278256
}
279257

280-
Ok(Self(value.0))
258+
Ok(Self(limbs))
281259
}
282260
}
283261

@@ -302,7 +280,7 @@ mod test {
302280
let qm31: Result<QM31Felt, QM31Error> = felt.try_into();
303281
assert!(matches!(
304282
qm31,
305-
Err(QM31Error::InvalidQM31(bx)) if bx == felt
283+
Err(QM31Error::FeltTooBig(bx)) if bx == felt
306284
));
307285
}
308286

0 commit comments

Comments
 (0)