Skip to content

Commit c63dfab

Browse files
change TryFrom<Felt> implementation to read the packed coordinates instead reducing them
1 parent f0751f4 commit c63dfab

File tree

1 file changed

+59
-36
lines changed
  • crates/starknet-types-core/src/felt

1 file changed

+59
-36
lines changed

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

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ use crate::felt::Felt;
44

55
pub const STWO_PRIME: u64 = (1 << 31) - 1;
66
const STWO_PRIME_U128: u128 = STWO_PRIME as u128;
7+
const MASK_36: u64 = (1 << 36) - 1;
8+
const MASK_8: u64 = (1 << 8) - 1;
79

810
#[derive(Debug)]
911
pub enum QM31Error {
12+
UnreducedFelt(Felt),
1013
FeltTooBig(Felt),
1114
InvalidInversion,
1215
}
@@ -17,6 +20,10 @@ impl std::error::Error for QM31Error {}
1720
impl fmt::Display for QM31Error {
1821
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1922
match self {
23+
QM31Error::UnreducedFelt(felt) => writeln!(
24+
f,
25+
"Number is not a packing of a QM31 in reduced form: {felt})"
26+
),
2027
QM31Error::FeltTooBig(felt) => writeln!(
2128
f,
2229
"Number used as QM31 since it's more than 144 bits long: {felt}"
@@ -231,7 +238,21 @@ impl TryFrom<Felt> for QM31Felt {
231238
return Err(QM31Error::FeltTooBig(value));
232239
}
233240

234-
Ok(Self::from_raw(limbs))
241+
let coordinates = [
242+
(limbs[0] & MASK_36),
243+
((limbs[0] >> 36) + ((limbs[1] & MASK_8) << 28)),
244+
((limbs[1] >> 8) & MASK_36),
245+
((limbs[1] >> 44) + (limbs[2] << 20)),
246+
];
247+
248+
// Check if the coordinates were reduced before.
249+
for x in coordinates.iter() {
250+
if *x >= STWO_PRIME {
251+
return Err(QM31Error::UnreducedFelt(value));
252+
}
253+
}
254+
255+
Ok(Self(coordinates))
235256
}
236257
}
237258

@@ -248,13 +269,27 @@ impl TryFrom<&Felt> for QM31Felt {
248269
return Err(QM31Error::FeltTooBig(*value));
249270
}
250271

251-
Ok(Self::from_raw(limbs))
272+
// Check if the coordinates were reduced before.
273+
let coordinates = [
274+
(limbs[0] & MASK_36),
275+
((limbs[0] >> 36) + ((limbs[1] & MASK_8) << 28)),
276+
((limbs[1] >> 8) & MASK_36),
277+
((limbs[1] >> 44) + (limbs[2] << 20)),
278+
];
279+
280+
for x in coordinates.iter() {
281+
if *x >= STWO_PRIME {
282+
return Err(QM31Error::UnreducedFelt(*value));
283+
}
284+
}
285+
286+
Ok(Self(coordinates))
252287
}
253288
}
254289

255290
#[cfg(test)]
256291
mod test {
257-
use core::{u128, u16, u8};
292+
use core::u64;
258293

259294
use proptest::{
260295
array::uniform4,
@@ -268,47 +303,35 @@ mod test {
268303
};
269304

270305
#[test]
271-
fn qm31_to_felt_packed() {
272-
let u64_max_reduced = u64::MAX % STWO_PRIME;
273-
274-
let value = u8::MAX;
275-
let felt = Felt::from(value);
276-
let qm31: QM31Felt = felt.try_into().unwrap();
277-
let qm31_to_felt = qm31.pack_into_felt();
278-
279-
assert_eq!(qm31_to_felt, Felt::from(value));
280-
281-
let value = u16::MAX;
282-
let felt = Felt::from(value);
283-
let qm31: QM31Felt = felt.try_into().unwrap();
284-
let qm31_to_felt = qm31.pack_into_felt();
306+
fn qm31_to_felt() {
307+
let coordinates = QM31Felt::from_raw([1, 2, 3, 4]);
308+
let packed_coordinates = Felt::from(coordinates);
309+
let unpacked_coordinates = QM31Felt::try_from(packed_coordinates).unwrap();
310+
assert_eq!(coordinates, unpacked_coordinates);
285311

286-
assert_eq!(qm31_to_felt, Felt::from(value));
312+
let qm31 = QM31Felt::from_raw([u64::MAX, 0, 0, 0]);
313+
let felt: Felt = qm31.try_into().unwrap();
314+
let felt_to_qm31 = QM31Felt::try_from(felt).unwrap();
287315

288-
let value = u32::MAX;
289-
let felt = Felt::from(value);
290-
let qm31: QM31Felt = felt.try_into().unwrap();
291-
let qm31_to_felt = qm31.pack_into_felt();
316+
assert_eq!(felt_to_qm31, qm31);
292317

293-
assert_eq!(qm31_to_felt, Felt::from(value as u64 % STWO_PRIME));
318+
let qm31 = QM31Felt::from_raw([u64::MAX, u64::MAX, 0, 0]);
319+
let felt: Felt = qm31.try_into().unwrap();
320+
let felt_to_qm31 = QM31Felt::try_from(felt).unwrap();
294321

295-
let felt = Felt::from(u64::MAX);
296-
let qm31: QM31Felt = felt.try_into().unwrap();
297-
let qm31_to_felt = qm31.pack_into_felt();
298-
dbg!(felt.to_le_digits());
322+
assert_eq!(felt_to_qm31, qm31);
299323

300-
assert_eq!(qm31_to_felt, Felt::from(u64_max_reduced));
324+
let qm31 = QM31Felt::from_raw([u64::MAX, u64::MAX, u64::MAX, 0]);
325+
let felt: Felt = qm31.try_into().unwrap();
326+
let felt_to_qm31 = QM31Felt::try_from(felt).unwrap();
301327

302-
let felt = Felt::from(u128::MAX);
303-
let qm31: QM31Felt = felt.try_into().unwrap();
304-
let qm31_to_felt = qm31.pack_into_felt();
328+
assert_eq!(felt_to_qm31, qm31);
305329

306-
let mut bytes = [0u8; 32];
307-
let bytes_part1 =
308-
((u64_max_reduced) as u128 + (((u64_max_reduced) as u128) << 36)).to_le_bytes();
309-
bytes[0..9].copy_from_slice(&bytes_part1[0..9]);
330+
let qm31 = QM31Felt::from_raw([u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
331+
let felt: Felt = qm31.try_into().unwrap();
332+
let felt_to_qm31 = QM31Felt::try_from(felt).unwrap();
310333

311-
assert_eq!(qm31_to_felt, Felt::from_bytes_le(&bytes));
334+
assert_eq!(felt_to_qm31, qm31);
312335
}
313336

314337
#[test]

0 commit comments

Comments
 (0)