1mod is_prime;
2
3pub use is_prime::is_prime;
4
5use core::cmp::min;
6
7use crate::stdlib::{boxed::Box, ops::Shr, prelude::Vec};
8use crate::types::errors::math_errors::MathError;
9use crate::utils::CAIRO_PRIME;
10use crate::Felt252;
11use lazy_static::lazy_static;
12use num_bigint::{BigInt, BigUint, RandBigInt, ToBigInt};
13use num_integer::Integer;
14use num_traits::{One, Signed, Zero};
15use rand::{rngs::SmallRng, SeedableRng};
16use starknet_types_core::felt::NonZeroFelt;
17
18lazy_static! {
19 pub static ref SIGNED_FELT_MAX: BigUint = (&*CAIRO_PRIME).shr(1_u32);
20 static ref POWERS_OF_TWO: Vec<NonZeroFelt> =
21 core::iter::successors(Some(Felt252::ONE), |x| Some(x * Felt252::TWO))
22 .take(252)
23 .map(|x| x.try_into().unwrap())
24 .collect::<Vec<_>>();
25}
26
27pub const STWO_PRIME: u64 = (1 << 31) - 1;
28const STWO_PRIME_U128: u128 = STWO_PRIME as u128;
29const MASK_36: u64 = (1 << 36) - 1;
30const MASK_8: u64 = (1 << 8) - 1;
31
32pub fn pow2_const(n: u32) -> Felt252 {
36 POWERS_OF_TWO
38 .get(n as usize)
39 .unwrap_or(&POWERS_OF_TWO[0])
40 .into()
41}
42
43pub fn pow2_const_nz(n: u32) -> &'static NonZeroFelt {
47 POWERS_OF_TWO.get(n as usize).unwrap_or(&POWERS_OF_TWO[0])
49}
50
51pub fn signed_felt(felt: Felt252) -> BigInt {
66 let biguint = felt.to_biguint();
67 if biguint > *SIGNED_FELT_MAX {
68 BigInt::from_biguint(num_bigint::Sign::Minus, &*CAIRO_PRIME - &biguint)
69 } else {
70 biguint.to_bigint().expect("cannot fail")
71 }
72}
73
74fn qm31_packed_reduced_read_coordinates(felt: Felt252) -> Result<[u64; 4], MathError> {
81 let limbs = felt.to_le_digits();
82 if limbs[3] != 0 || limbs[2] >= 1 << 16 {
83 return Err(MathError::QM31UnreducedError(Box::new(felt)));
84 }
85 let coordinates = [
86 (limbs[0] & MASK_36),
87 ((limbs[0] >> 36) + ((limbs[1] & MASK_8) << 28)),
88 ((limbs[1] >> 8) & MASK_36),
89 ((limbs[1] >> 44) + (limbs[2] << 20)),
90 ];
91 for x in coordinates.iter() {
92 if *x >= STWO_PRIME {
93 return Err(MathError::QM31UnreducedError(Box::new(felt)));
94 }
95 }
96 Ok(coordinates)
97}
98
99pub fn qm31_coordinates_to_packed_reduced(coordinates: [u64; 4]) -> Felt252 {
105 let bytes_part1 = ((coordinates[0] % STWO_PRIME) as u128
106 + (((coordinates[1] % STWO_PRIME) as u128) << 36))
107 .to_le_bytes();
108 let bytes_part2 = ((coordinates[2] % STWO_PRIME) as u128
109 + (((coordinates[3] % STWO_PRIME) as u128) << 36))
110 .to_le_bytes();
111 let mut result_bytes = [0u8; 32];
112 result_bytes[0..9].copy_from_slice(&bytes_part1[0..9]);
113 result_bytes[9..18].copy_from_slice(&bytes_part2[0..9]);
114 Felt252::from_bytes_le(&result_bytes)
115}
116
117pub fn qm31_packed_reduced_add(felt1: Felt252, felt2: Felt252) -> Result<Felt252, MathError> {
122 let coordinates1 = qm31_packed_reduced_read_coordinates(felt1)?;
123 let coordinates2 = qm31_packed_reduced_read_coordinates(felt2)?;
124 let result_unreduced_coordinates = [
125 coordinates1[0] + coordinates2[0],
126 coordinates1[1] + coordinates2[1],
127 coordinates1[2] + coordinates2[2],
128 coordinates1[3] + coordinates2[3],
129 ];
130 Ok(qm31_coordinates_to_packed_reduced(
131 result_unreduced_coordinates,
132 ))
133}
134
135pub fn qm31_packed_reduced_neg(felt: Felt252) -> Result<Felt252, MathError> {
140 let coordinates = qm31_packed_reduced_read_coordinates(felt)?;
141 Ok(qm31_coordinates_to_packed_reduced([
142 STWO_PRIME - coordinates[0],
143 STWO_PRIME - coordinates[1],
144 STWO_PRIME - coordinates[2],
145 STWO_PRIME - coordinates[3],
146 ]))
147}
148
149pub fn qm31_packed_reduced_sub(felt1: Felt252, felt2: Felt252) -> Result<Felt252, MathError> {
154 let coordinates1 = qm31_packed_reduced_read_coordinates(felt1)?;
155 let coordinates2 = qm31_packed_reduced_read_coordinates(felt2)?;
156 let result_unreduced_coordinates = [
157 STWO_PRIME + coordinates1[0] - coordinates2[0],
158 STWO_PRIME + coordinates1[1] - coordinates2[1],
159 STWO_PRIME + coordinates1[2] - coordinates2[2],
160 STWO_PRIME + coordinates1[3] - coordinates2[3],
161 ];
162 Ok(qm31_coordinates_to_packed_reduced(
163 result_unreduced_coordinates,
164 ))
165}
166
167pub fn qm31_packed_reduced_mul(felt1: Felt252, felt2: Felt252) -> Result<Felt252, MathError> {
172 let coordinates1_u64 = qm31_packed_reduced_read_coordinates(felt1)?;
173 let coordinates2_u64 = qm31_packed_reduced_read_coordinates(felt2)?;
174 let coordinates1 = coordinates1_u64.map(u128::from);
175 let coordinates2 = coordinates2_u64.map(u128::from);
176
177 let result_coordinates = [
178 ((5 * STWO_PRIME_U128 * STWO_PRIME_U128 + coordinates1[0] * coordinates2[0]
179 - coordinates1[1] * coordinates2[1]
180 + 2 * coordinates1[2] * coordinates2[2]
181 - 2 * coordinates1[3] * coordinates2[3]
182 - coordinates1[2] * coordinates2[3]
183 - coordinates1[3] * coordinates2[2])
184 % STWO_PRIME_U128) as u64,
185 ((STWO_PRIME_U128 * STWO_PRIME_U128
186 + coordinates1[0] * coordinates2[1]
187 + coordinates1[1] * coordinates2[0]
188 + 2 * (coordinates1[2] * coordinates2[3] + coordinates1[3] * coordinates2[2])
189 + coordinates1[2] * coordinates2[2]
190 - coordinates1[3] * coordinates2[3])
191 % STWO_PRIME_U128) as u64,
192 2 * STWO_PRIME * STWO_PRIME + coordinates1_u64[0] * coordinates2_u64[2]
193 - coordinates1_u64[1] * coordinates2_u64[3]
194 + coordinates1_u64[2] * coordinates2_u64[0]
195 - coordinates1_u64[3] * coordinates2_u64[1],
196 coordinates1_u64[0] * coordinates2_u64[3]
197 + coordinates1_u64[1] * coordinates2_u64[2]
198 + coordinates1_u64[2] * coordinates2_u64[1]
199 + coordinates1_u64[3] * coordinates2_u64[0],
200 ];
201 Ok(qm31_coordinates_to_packed_reduced(result_coordinates))
202}
203
204pub fn pow2147483645(v: u64) -> u64 {
209 let t0 = (sqn(v, 2) * v) % STWO_PRIME;
210 let t1 = (sqn(t0, 1) * t0) % STWO_PRIME;
211 let t2 = (sqn(t1, 3) * t0) % STWO_PRIME;
212 let t3 = (sqn(t2, 1) * t0) % STWO_PRIME;
213 let t4 = (sqn(t3, 8) * t3) % STWO_PRIME;
214 let t5 = (sqn(t4, 8) * t3) % STWO_PRIME;
215 (sqn(t5, 7) * t2) % STWO_PRIME
216}
217
218fn sqn(v: u64, n: usize) -> u64 {
222 let mut u = v;
223 for _ in 0..n {
224 u = (u * u) % STWO_PRIME;
225 }
226 u
227}
228
229pub fn qm31_packed_reduced_inv(felt: Felt252) -> Result<Felt252, MathError> {
234 if felt.is_zero() {
235 return Err(MathError::DividedByZero);
236 }
237 let coordinates = qm31_packed_reduced_read_coordinates(felt)?;
238
239 let b2_r = (coordinates[2] * coordinates[2] + STWO_PRIME * STWO_PRIME
240 - coordinates[3] * coordinates[3])
241 % STWO_PRIME;
242 let b2_i = (2 * coordinates[2] * coordinates[3]) % STWO_PRIME;
243
244 let denom_r = (coordinates[0] * coordinates[0] + STWO_PRIME * STWO_PRIME
245 - coordinates[1] * coordinates[1]
246 + 2 * STWO_PRIME
247 - 2 * b2_r
248 + b2_i)
249 % STWO_PRIME;
250 let denom_i =
251 (2 * coordinates[0] * coordinates[1] + 3 * STWO_PRIME - 2 * b2_i - b2_r) % STWO_PRIME;
252
253 let denom_norm_squared = (denom_r * denom_r + denom_i * denom_i) % STWO_PRIME;
254 let denom_norm_inverse_squared = pow2147483645(denom_norm_squared);
255
256 let denom_inverse_r = (denom_r * denom_norm_inverse_squared) % STWO_PRIME;
257 let denom_inverse_i = ((STWO_PRIME - denom_i) * denom_norm_inverse_squared) % STWO_PRIME;
258
259 Ok(qm31_coordinates_to_packed_reduced([
260 coordinates[0] * denom_inverse_r + STWO_PRIME * STWO_PRIME
261 - coordinates[1] * denom_inverse_i,
262 coordinates[0] * denom_inverse_i + coordinates[1] * denom_inverse_r,
263 coordinates[3] * denom_inverse_i + STWO_PRIME * STWO_PRIME
264 - coordinates[2] * denom_inverse_r,
265 2 * STWO_PRIME * STWO_PRIME
266 - coordinates[2] * denom_inverse_i
267 - coordinates[3] * denom_inverse_r,
268 ]))
269}
270
271pub fn qm31_packed_reduced_div(felt1: Felt252, felt2: Felt252) -> Result<Felt252, MathError> {
276 let felt2_inv = qm31_packed_reduced_inv(felt2)?;
277 qm31_packed_reduced_mul(felt1, felt2_inv)
278}
279
280pub fn isqrt(n: &BigUint) -> Result<BigUint, MathError> {
284 let mut x = n.clone();
295 let mut y = (&x + 1_u32).shr(1_u32);
297
298 while y < x {
299 x = y;
300 y = (&x + n.div_floor(&x)).shr(1_u32);
301 }
302
303 if !(&BigUint::pow(&x, 2_u32) <= n && n < &BigUint::pow(&(&x + 1_u32), 2_u32)) {
304 return Err(MathError::FailedToGetSqrt(Box::new(n.clone())));
305 };
306 Ok(x)
307}
308
309pub fn safe_div(x: &Felt252, y: &Felt252) -> Result<Felt252, MathError> {
311 let (q, r) = x.div_rem(&y.try_into().map_err(|_| MathError::DividedByZero)?);
312
313 if !r.is_zero() {
314 Err(MathError::SafeDivFail(Box::new((*x, *y))))
315 } else {
316 Ok(q)
317 }
318}
319
320pub fn safe_div_bigint(x: &BigInt, y: &BigInt) -> Result<BigInt, MathError> {
322 if y.is_zero() {
323 return Err(MathError::DividedByZero);
324 }
325
326 let (q, r) = x.div_mod_floor(y);
327
328 if !r.is_zero() {
329 return Err(MathError::SafeDivFailBigInt(Box::new((
330 x.clone(),
331 y.clone(),
332 ))));
333 }
334
335 Ok(q)
336}
337
338pub fn safe_div_usize(x: usize, y: usize) -> Result<usize, MathError> {
340 if y.is_zero() {
341 return Err(MathError::DividedByZero);
342 }
343
344 let (q, r) = x.div_mod_floor(&y);
345
346 if !r.is_zero() {
347 return Err(MathError::SafeDivFailUsize(Box::new((x, y))));
348 }
349
350 Ok(q)
351}
352
353pub(crate) fn mul_inv(num_a: &BigInt, p: &BigInt) -> BigInt {
355 if num_a.is_zero() {
356 return BigInt::zero();
357 }
358 let mut a = num_a.abs();
359 let x_sign = num_a.signum();
360 let mut b = p.abs();
361 let (mut x, mut r) = (BigInt::one(), BigInt::zero());
362 let (mut c, mut q);
363 while !b.is_zero() {
364 (q, c) = a.div_mod_floor(&b);
365 x -= &q * &r;
366 (a, b, r, x) = (b, c, x, r)
367 }
368
369 x * x_sign
370}
371
372fn igcdex(num_a: &BigInt, num_b: &BigInt) -> (BigInt, BigInt, BigInt) {
374 match (num_a, num_b) {
375 (a, b) if a.is_zero() && b.is_zero() => (BigInt::zero(), BigInt::one(), BigInt::zero()),
376 (a, _) if a.is_zero() => (BigInt::zero(), num_b.signum(), num_b.abs()),
377 (_, b) if b.is_zero() => (num_a.signum(), BigInt::zero(), num_a.abs()),
378 _ => {
379 let mut a = num_a.abs();
380 let x_sign = num_a.signum();
381 let mut b = num_b.abs();
382 let y_sign = num_b.signum();
383 let (mut x, mut y, mut r, mut s) =
384 (BigInt::one(), BigInt::zero(), BigInt::zero(), BigInt::one());
385 let (mut c, mut q);
386 while !b.is_zero() {
387 (q, c) = a.div_mod_floor(&b);
388 x -= &q * &r;
389 y -= &q * &s;
390 (a, b, r, s, x, y) = (b, c, x, y, r, s)
391 }
392 (x * x_sign, y * y_sign, a)
393 }
394 }
395}
396
397pub fn div_mod(n: &BigInt, m: &BigInt, p: &BigInt) -> Result<BigInt, MathError> {
399 let (a, _, c) = igcdex(m, p);
400 if !c.is_one() {
401 return Err(MathError::DivModIgcdexNotZero(Box::new((
402 n.clone(),
403 m.clone(),
404 p.clone(),
405 ))));
406 }
407 Ok((n * a).mod_floor(p))
408}
409
410pub(crate) fn div_mod_unsigned(
411 n: &BigUint,
412 m: &BigUint,
413 p: &BigUint,
414) -> Result<BigUint, MathError> {
415 div_mod(
417 &n.to_bigint().unwrap(),
418 &m.to_bigint().unwrap(),
419 &p.to_bigint().unwrap(),
420 )
421 .map(|i| i.to_biguint().unwrap())
422}
423
424pub fn ec_add(
425 point_a: (BigInt, BigInt),
426 point_b: (BigInt, BigInt),
427 prime: &BigInt,
428) -> Result<(BigInt, BigInt), MathError> {
429 let m = line_slope(&point_a, &point_b, prime)?;
430 let x = (m.clone() * m.clone() - point_a.0.clone() - point_b.0).mod_floor(prime);
431 let y = (m * (point_a.0 - x.clone()) - point_a.1).mod_floor(prime);
432 Ok((x, y))
433}
434
435pub fn line_slope(
438 point_a: &(BigInt, BigInt),
439 point_b: &(BigInt, BigInt),
440 prime: &BigInt,
441) -> Result<BigInt, MathError> {
442 debug_assert!(!(&point_a.0 - &point_b.0).is_multiple_of(prime));
443 div_mod(
444 &(&point_a.1 - &point_b.1),
445 &(&point_a.0 - &point_b.0),
446 prime,
447 )
448}
449
450pub fn ec_double(
453 point: (BigInt, BigInt),
454 alpha: &BigInt,
455 prime: &BigInt,
456) -> Result<(BigInt, BigInt), MathError> {
457 let m = ec_double_slope(&point, alpha, prime)?;
458 let x = ((&m * &m) - (2_i32 * &point.0)).mod_floor(prime);
459 let y = (m * (point.0 - &x) - point.1).mod_floor(prime);
460 Ok((x, y))
461}
462pub fn ec_double_slope(
466 point: &(BigInt, BigInt),
467 alpha: &BigInt,
468 prime: &BigInt,
469) -> Result<BigInt, MathError> {
470 debug_assert!(!point.1.is_multiple_of(prime));
471 div_mod(
472 &(3_i32 * &point.0 * &point.0 + alpha),
473 &(2_i32 * &point.1),
474 prime,
475 )
476}
477
478pub fn sqrt_prime_power(a: &BigUint, p: &BigUint) -> Option<BigUint> {
480 if p.is_zero() || !is_prime(p) {
481 return None;
482 }
483 let two = BigUint::from(2_u32);
484 let a = a.mod_floor(p);
485 if p == &two {
486 return Some(a);
487 }
488 if !(a < two || (a.modpow(&(p - 1_u32).div_floor(&two), p)).is_one()) {
489 return None;
490 };
491
492 if p.mod_floor(&BigUint::from(4_u32)) == 3_u32.into() {
493 let res = a.modpow(&(p + 1_u32).div_floor(&BigUint::from(4_u32)), p);
494 return Some(min(res.clone(), p - res));
495 };
496
497 if p.mod_floor(&BigUint::from(8_u32)) == 5_u32.into() {
498 let sign = a.modpow(&(p - 1_u32).div_floor(&BigUint::from(4_u32)), p);
499 if sign.is_one() {
500 let res = a.modpow(&(p + 3_u32).div_floor(&BigUint::from(8_u32)), p);
501 return Some(min(res.clone(), p - res));
502 } else {
503 let b = (4_u32 * &a).modpow(&(p - 5_u32).div_floor(&BigUint::from(8_u32)), p);
504 let x = (2_u32 * &a * b).mod_floor(p);
505 if x.modpow(&two, p) == a {
506 return Some(x);
507 }
508 }
509 };
510
511 Some(sqrt_tonelli_shanks(&a, p))
512}
513
514fn sqrt_tonelli_shanks(n: &BigUint, prime: &BigUint) -> BigUint {
515 if n.is_zero() || n.is_one() {
518 return n.clone();
519 }
520 let s = (prime - 1_u32).trailing_zeros().unwrap_or_default();
521 let t = prime >> s;
522 let a = n.modpow(&t, prime);
523 let mut rng = SmallRng::seed_from_u64(11480028852697973135);
525 let mut d;
526 loop {
527 d = RandBigInt::gen_biguint_range(&mut rng, &BigUint::from(2_u32), &(prime - 1_u32));
528 let r = legendre_symbol(&d, prime);
529 if r == -1 {
530 break;
531 };
532 }
533 d = d.modpow(&t, prime);
534 let mut m = BigUint::zero();
535 let mut exponent = BigUint::one() << (s - 1);
536 let mut adm;
537 for i in 0..s as u32 {
538 adm = &a * &d.modpow(&m, prime);
539 adm = adm.modpow(&exponent, prime);
540 exponent >>= 1;
541 if adm == (prime - 1_u32) {
542 m += BigUint::from(1_u32) << i;
543 }
544 }
545 let root_1 =
546 (n.modpow(&((t + 1_u32) >> 1), prime) * d.modpow(&(m >> 1), prime)).mod_floor(prime);
547 let root_2 = prime - &root_1;
548 if root_1 < root_2 {
549 root_1
550 } else {
551 root_2
552 }
553}
554
555fn legendre_symbol(a: &BigUint, p: &BigUint) -> i8 {
572 if a.is_zero() {
573 return 0;
574 };
575 if is_quad_residue(a, p).unwrap_or_default() {
576 1
577 } else {
578 -1
579 }
580}
581
582pub(crate) fn is_quad_residue(a: &BigUint, p: &BigUint) -> Result<bool, MathError> {
586 if p.is_zero() {
587 return Err(MathError::IsQuadResidueZeroPrime);
588 }
589 let a = if a >= p { a.mod_floor(p) } else { a.clone() };
590 if a < BigUint::from(2_u8) || p < &BigUint::from(3_u8) {
591 return Ok(true);
592 }
593 Ok(
594 a.modpow(&(p - BigUint::one()).div_floor(&BigUint::from(2_u8)), p)
595 .is_one(),
596 )
597}
598
599#[cfg(test)]
600mod tests {
601 use super::*;
602 use crate::utils::test_utils::*;
603 use crate::utils::CAIRO_PRIME;
604 use assert_matches::assert_matches;
605
606 use num_traits::Num;
607 use rand::Rng;
608
609 #[cfg(feature = "std")]
610 use num_prime::RandPrime;
611
612 #[cfg(feature = "std")]
613 use proptest::prelude::*;
614
615 #[cfg(feature = "std")]
617 use num_bigint::Sign;
618
619 #[cfg(target_arch = "wasm32")]
620 use wasm_bindgen_test::*;
621
622 #[test]
623 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
624 fn calculate_divmod_a() {
625 let a = bigint_str!(
626 "11260647941622813594563746375280766662237311019551239924981511729608487775604310196863705127454617186486639011517352066501847110680463498585797912894788"
627 );
628 let b = bigint_str!(
629 "4020711254448367604954374443741161860304516084891705811279711044808359405970"
630 );
631 assert_eq!(
632 bigint_str!(
633 "2904750555256547440469454488220756360634457312540595732507835416669695939476"
634 ),
635 div_mod(
636 &a,
637 &b,
638 &BigInt::from_str_radix(&crate::utils::PRIME_STR[2..], 16)
639 .expect("Couldn't parse prime")
640 )
641 .unwrap()
642 );
643 }
644
645 #[test]
646 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
647 fn calculate_divmod_b() {
648 let a = bigint_str!(
649 "29642372811668969595956851264770043260610851505766181624574941701711520154703788233010819515917136995474951116158286220089597404329949295479559895970988"
650 );
651 let b = bigint_str!(
652 "3443173965374276972000139705137775968422921151703548011275075734291405722262"
653 );
654 assert_eq!(
655 bigint_str!(
656 "3601388548860259779932034493250169083811722919049731683411013070523752439691"
657 ),
658 div_mod(
659 &a,
660 &b,
661 &BigInt::from_str_radix(&crate::utils::PRIME_STR[2..], 16)
662 .expect("Couldn't parse prime")
663 )
664 .unwrap()
665 );
666 }
667
668 #[test]
669 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
670 fn calculate_divmod_c() {
671 let a = bigint_str!(
672 "1208267356464811040667664150251401430616174694388968865551115897173431833224432165394286799069453655049199580362994484548890574931604445970825506916876"
673 );
674 let b = bigint_str!(
675 "1809792356889571967986805709823554331258072667897598829955472663737669990418"
676 );
677 assert_eq!(
678 bigint_str!(
679 "1545825591488572374291664030703937603499513742109806697511239542787093258962"
680 ),
681 div_mod(
682 &a,
683 &b,
684 &BigInt::from_str_radix(&crate::utils::PRIME_STR[2..], 16)
685 .expect("Couldn't parse prime")
686 )
687 .unwrap()
688 );
689 }
690
691 #[test]
692 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
693 fn compute_safe_div() {
694 let x = Felt252::from(26);
695 let y = Felt252::from(13);
696 assert_matches!(safe_div(&x, &y), Ok(i) if i == Felt252::from(2));
697 }
698
699 #[test]
700 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
701 fn compute_safe_div_non_divisor() {
702 let x = Felt252::from(25);
703 let y = Felt252::from(4);
704 let result = safe_div(&x, &y);
705 assert_matches!(
706 result,
707 Err(MathError::SafeDivFail(bx)) if *bx == (Felt252::from(25), Felt252::from(4)));
708 }
709
710 #[test]
711 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
712 fn compute_safe_div_by_zero() {
713 let x = Felt252::from(25);
714 let y = Felt252::ZERO;
715 let result = safe_div(&x, &y);
716 assert_matches!(result, Err(MathError::DividedByZero));
717 }
718
719 #[test]
720 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
721 fn compute_safe_div_usize() {
722 assert_matches!(safe_div_usize(26, 13), Ok(2));
723 }
724
725 #[test]
726 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
727 fn compute_safe_div_usize_non_divisor() {
728 assert_matches!(
729 safe_div_usize(25, 4),
730 Err(MathError::SafeDivFailUsize(bx)) if *bx == (25, 4)
731 );
732 }
733
734 #[test]
735 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
736 fn compute_safe_div_usize_by_zero() {
737 assert_matches!(safe_div_usize(25, 0), Err(MathError::DividedByZero));
738 }
739
740 #[test]
741 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
742 fn compute_line_slope_for_valid_points() {
743 let point_a = (
744 bigint_str!(
745 "3139037544796708144595053687182055617920475701120786241351436619796497072089"
746 ),
747 bigint_str!(
748 "2119589567875935397690285099786081818522144748339117565577200220779667999801"
749 ),
750 );
751 let point_b = (
752 bigint_str!(
753 "3324833730090626974525872402899302150520188025637965566623476530814354734325"
754 ),
755 bigint_str!(
756 "3147007486456030910661996439995670279305852583596209647900952752170983517249"
757 ),
758 );
759 let prime = (*CAIRO_PRIME).clone().into();
760 assert_eq!(
761 bigint_str!(
762 "992545364708437554384321881954558327331693627531977596999212637460266617010"
763 ),
764 line_slope(&point_a, &point_b, &prime).unwrap()
765 );
766 }
767
768 #[test]
769 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
770 fn compute_double_slope_for_valid_point_a() {
771 let point = (
772 bigint_str!(
773 "3143372541908290873737380228370996772020829254218248561772745122290262847573"
774 ),
775 bigint_str!(
776 "1721586982687138486000069852568887984211460575851774005637537867145702861131"
777 ),
778 );
779 let prime = (*CAIRO_PRIME).clone().into();
780 let alpha = bigint!(1);
781 assert_eq!(
782 bigint_str!(
783 "3601388548860259779932034493250169083811722919049731683411013070523752439691"
784 ),
785 ec_double_slope(&point, &alpha, &prime).unwrap()
786 );
787 }
788
789 #[test]
790 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
791 fn compute_double_slope_for_valid_point_b() {
792 let point = (
793 bigint_str!(
794 "1937407885261715145522756206040455121546447384489085099828343908348117672673"
795 ),
796 bigint_str!(
797 "2010355627224183802477187221870580930152258042445852905639855522404179702985"
798 ),
799 );
800 let prime = (*CAIRO_PRIME).clone().into();
801 let alpha = bigint!(1);
802 assert_eq!(
803 bigint_str!(
804 "2904750555256547440469454488220756360634457312540595732507835416669695939476"
805 ),
806 ec_double_slope(&point, &alpha, &prime).unwrap()
807 );
808 }
809
810 #[test]
811 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
812 fn calculate_ec_double_for_valid_point_a() {
813 let point = (
814 bigint_str!(
815 "1937407885261715145522756206040455121546447384489085099828343908348117672673"
816 ),
817 bigint_str!(
818 "2010355627224183802477187221870580930152258042445852905639855522404179702985"
819 ),
820 );
821 let prime = (*CAIRO_PRIME).clone().into();
822 let alpha = bigint!(1);
823 assert_eq!(
824 (
825 bigint_str!(
826 "58460926014232092148191979591712815229424797874927791614218178721848875644"
827 ),
828 bigint_str!(
829 "1065613861227134732854284722490492186040898336012372352512913425790457998694"
830 )
831 ),
832 ec_double(point, &alpha, &prime).unwrap()
833 );
834 }
835
836 #[test]
837 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
838 fn calculate_ec_double_for_valid_point_b() {
839 let point = (
840 bigint_str!(
841 "3143372541908290873737380228370996772020829254218248561772745122290262847573"
842 ),
843 bigint_str!(
844 "1721586982687138486000069852568887984211460575851774005637537867145702861131"
845 ),
846 );
847 let prime = (*CAIRO_PRIME).clone().into();
848 let alpha = bigint!(1);
849 assert_eq!(
850 (
851 bigint_str!(
852 "1937407885261715145522756206040455121546447384489085099828343908348117672673"
853 ),
854 bigint_str!(
855 "2010355627224183802477187221870580930152258042445852905639855522404179702985"
856 )
857 ),
858 ec_double(point, &alpha, &prime).unwrap()
859 );
860 }
861
862 #[test]
863 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
864 fn calculate_ec_double_for_valid_point_c() {
865 let point = (
866 bigint_str!(
867 "634630432210960355305430036410971013200846091773294855689580772209984122075"
868 ),
869 bigint_str!(
870 "904896178444785983993402854911777165629036333948799414977736331868834995209"
871 ),
872 );
873 let prime = (*CAIRO_PRIME).clone().into();
874 let alpha = bigint!(1);
875 assert_eq!(
876 (
877 bigint_str!(
878 "3143372541908290873737380228370996772020829254218248561772745122290262847573"
879 ),
880 bigint_str!(
881 "1721586982687138486000069852568887984211460575851774005637537867145702861131"
882 )
883 ),
884 ec_double(point, &alpha, &prime).unwrap()
885 );
886 }
887
888 #[test]
889 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
890 fn calculate_ec_add_for_valid_points_a() {
891 let point_a = (
892 bigint_str!(
893 "1183418161532233795704555250127335895546712857142554564893196731153957537489"
894 ),
895 bigint_str!(
896 "1938007580204102038458825306058547644691739966277761828724036384003180924526"
897 ),
898 );
899 let point_b = (
900 bigint_str!(
901 "1977703130303461992863803129734853218488251484396280000763960303272760326570"
902 ),
903 bigint_str!(
904 "2565191853811572867032277464238286011368568368717965689023024980325333517459"
905 ),
906 );
907 let prime = (*CAIRO_PRIME).clone().into();
908 assert_eq!(
909 (
910 bigint_str!(
911 "1977874238339000383330315148209250828062304908491266318460063803060754089297"
912 ),
913 bigint_str!(
914 "2969386888251099938335087541720168257053975603483053253007176033556822156706"
915 )
916 ),
917 ec_add(point_a, point_b, &prime).unwrap()
918 );
919 }
920
921 #[test]
922 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
923 fn calculate_ec_add_for_valid_points_b() {
924 let point_a = (
925 bigint_str!(
926 "3139037544796708144595053687182055617920475701120786241351436619796497072089"
927 ),
928 bigint_str!(
929 "2119589567875935397690285099786081818522144748339117565577200220779667999801"
930 ),
931 );
932 let point_b = (
933 bigint_str!(
934 "3324833730090626974525872402899302150520188025637965566623476530814354734325"
935 ),
936 bigint_str!(
937 "3147007486456030910661996439995670279305852583596209647900952752170983517249"
938 ),
939 );
940 let prime = (*CAIRO_PRIME).clone().into();
941 assert_eq!(
942 (
943 bigint_str!(
944 "1183418161532233795704555250127335895546712857142554564893196731153957537489"
945 ),
946 bigint_str!(
947 "1938007580204102038458825306058547644691739966277761828724036384003180924526"
948 )
949 ),
950 ec_add(point_a, point_b, &prime).unwrap()
951 );
952 }
953
954 #[test]
955 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
956 fn calculate_ec_add_for_valid_points_c() {
957 let point_a = (
958 bigint_str!(
959 "1183418161532233795704555250127335895546712857142554564893196731153957537489"
960 ),
961 bigint_str!(
962 "1938007580204102038458825306058547644691739966277761828724036384003180924526"
963 ),
964 );
965 let point_b = (
966 bigint_str!(
967 "1977703130303461992863803129734853218488251484396280000763960303272760326570"
968 ),
969 bigint_str!(
970 "2565191853811572867032277464238286011368568368717965689023024980325333517459"
971 ),
972 );
973 let prime = (*CAIRO_PRIME).clone().into();
974 assert_eq!(
975 (
976 bigint_str!(
977 "1977874238339000383330315148209250828062304908491266318460063803060754089297"
978 ),
979 bigint_str!(
980 "2969386888251099938335087541720168257053975603483053253007176033556822156706"
981 )
982 ),
983 ec_add(point_a, point_b, &prime).unwrap()
984 );
985 }
986
987 #[test]
988 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
989 fn calculate_isqrt_a() {
990 let n = biguint!(81);
991 assert_matches!(isqrt(&n), Ok(x) if x == biguint!(9));
992 }
993
994 #[test]
995 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
996 fn calculate_isqrt_b() {
997 let n = biguint_str!("4573659632505831259480");
998 assert_matches!(isqrt(&BigUint::pow(&n, 2_u32)), Ok(num) if num == n);
999 }
1000
1001 #[test]
1002 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1003 fn calculate_isqrt_c() {
1004 let n = biguint_str!(
1005 "3618502788666131213697322783095070105623107215331596699973092056135872020481"
1006 );
1007 assert_matches!(isqrt(&BigUint::pow(&n, 2_u32)), Ok(inner) if inner == n);
1008 }
1009
1010 #[test]
1011 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1012 fn calculate_isqrt_zero() {
1013 let n = BigUint::zero();
1014 assert_matches!(isqrt(&n), Ok(inner) if inner.is_zero());
1015 }
1016
1017 #[test]
1018 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1019 fn safe_div_bigint_by_zero() {
1020 let x = BigInt::one();
1021 let y = BigInt::zero();
1022 assert_matches!(safe_div_bigint(&x, &y), Err(MathError::DividedByZero))
1023 }
1024
1025 #[test]
1026 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1027 fn test_sqrt_prime_power() {
1028 let n: BigUint = 25_u32.into();
1029 let p: BigUint = 18446744069414584321_u128.into();
1030 assert_eq!(sqrt_prime_power(&n, &p), Some(5_u32.into()));
1031 }
1032
1033 #[test]
1034 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1035 fn test_sqrt_prime_power_p_is_zero() {
1036 let n = BigUint::one();
1037 let p: BigUint = BigUint::zero();
1038 assert_eq!(sqrt_prime_power(&n, &p), None);
1039 }
1040
1041 #[test]
1042 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1043 fn test_sqrt_prime_power_non_prime() {
1044 let p: BigUint = BigUint::from_bytes_be(&[
1045 69, 15, 232, 82, 215, 167, 38, 143, 173, 94, 133, 111, 1, 2, 182, 229, 110, 113, 76, 0,
1046 47, 110, 148, 109, 6, 133, 27, 190, 158, 197, 168, 219, 165, 254, 81, 53, 25, 34,
1047 ]);
1048 let n = BigUint::from_bytes_be(&[
1049 9, 13, 22, 191, 87, 62, 157, 83, 157, 85, 93, 105, 230, 187, 32, 101, 51, 181, 49, 202,
1050 203, 195, 76, 193, 149, 78, 109, 146, 240, 126, 182, 115, 161, 238, 30, 118, 157, 252,
1051 ]);
1052
1053 assert_eq!(sqrt_prime_power(&n, &p), None);
1054 }
1055
1056 #[test]
1057 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1058 fn test_sqrt_prime_power_none() {
1059 let n: BigUint = 10_u32.into();
1060 let p: BigUint = 602_u32.into();
1061 assert_eq!(sqrt_prime_power(&n, &p), None);
1062 }
1063
1064 #[test]
1065 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1066 fn test_sqrt_prime_power_prime_two() {
1067 let n: BigUint = 25_u32.into();
1068 let p: BigUint = 2_u32.into();
1069 assert_eq!(sqrt_prime_power(&n, &p), Some(BigUint::one()));
1070 }
1071
1072 #[test]
1073 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1074 fn test_sqrt_prime_power_prime_mod_8_is_5_sign_not_one() {
1075 let n: BigUint = 676_u32.into();
1076 let p: BigUint = 9956234341095173_u64.into();
1077 assert_eq!(
1078 sqrt_prime_power(&n, &p),
1079 Some(BigUint::from(9956234341095147_u64))
1080 );
1081 }
1082
1083 #[test]
1084 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1085 fn test_sqrt_prime_power_prime_mod_8_is_5_sign_is_one() {
1086 let n: BigUint = 130283432663_u64.into();
1087 let p: BigUint = 743900351477_u64.into();
1088 assert_eq!(
1089 sqrt_prime_power(&n, &p),
1090 Some(BigUint::from(123538694848_u64))
1091 );
1092 }
1093
1094 #[test]
1095 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1096 fn test_legendre_symbol_zero() {
1097 assert!(legendre_symbol(&BigUint::zero(), &BigUint::one()).is_zero())
1098 }
1099
1100 #[test]
1101 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1102 fn test_is_quad_residue_prime_zero() {
1103 assert_eq!(
1104 is_quad_residue(&BigUint::one(), &BigUint::zero()),
1105 Err(MathError::IsQuadResidueZeroPrime)
1106 )
1107 }
1108
1109 #[test]
1110 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1111 fn test_is_quad_residue_prime_a_one_true() {
1112 assert_eq!(is_quad_residue(&BigUint::one(), &BigUint::one()), Ok(true))
1113 }
1114
1115 #[test]
1116 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1117 fn mul_inv_0_is_0() {
1118 let p = &(*CAIRO_PRIME).clone().into();
1119 let x = &BigInt::zero();
1120 let x_inv = mul_inv(x, p);
1121
1122 assert_eq!(x_inv, BigInt::zero());
1123 }
1124
1125 #[test]
1126 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1127 fn igcdex_1_1() {
1128 assert_eq!(
1129 igcdex(&BigInt::one(), &BigInt::one()),
1130 (BigInt::zero(), BigInt::one(), BigInt::one())
1131 )
1132 }
1133
1134 #[test]
1135 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1136 fn igcdex_0_0() {
1137 assert_eq!(
1138 igcdex(&BigInt::zero(), &BigInt::zero()),
1139 (BigInt::zero(), BigInt::one(), BigInt::zero())
1140 )
1141 }
1142
1143 #[test]
1144 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1145 fn igcdex_1_0() {
1146 assert_eq!(
1147 igcdex(&BigInt::one(), &BigInt::zero()),
1148 (BigInt::one(), BigInt::zero(), BigInt::one())
1149 )
1150 }
1151
1152 #[test]
1153 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1154 fn igcdex_4_6() {
1155 assert_eq!(
1156 igcdex(&BigInt::from(4), &BigInt::from(6)),
1157 (BigInt::from(-1), BigInt::one(), BigInt::from(2))
1158 )
1159 }
1160
1161 #[test]
1162 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1163 fn qm31_packed_reduced_read_coordinates_over_144_bits() {
1164 let mut felt_bytes = [0u8; 32];
1165 felt_bytes[18] = 1;
1166 let felt = Felt252::from_bytes_le(&felt_bytes);
1167 assert_matches!(
1168 qm31_packed_reduced_read_coordinates(felt),
1169 Err(MathError::QM31UnreducedError(bx)) if *bx == felt
1170 );
1171 }
1172
1173 #[test]
1174 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1175 fn qm31_packed_reduced_read_coordinates_unreduced() {
1176 let mut felt_bytes = [0u8; 32];
1177 felt_bytes[0] = 0xff;
1178 felt_bytes[1] = 0xff;
1179 felt_bytes[2] = 0xff;
1180 felt_bytes[3] = (1 << 7) - 1;
1181 let felt = Felt252::from_bytes_le(&felt_bytes);
1182 assert_matches!(
1183 qm31_packed_reduced_read_coordinates(felt),
1184 Err(MathError::QM31UnreducedError(bx)) if *bx == felt
1185 );
1186 }
1187
1188 #[test]
1189 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1190 fn test_qm31_packed_reduced_add() {
1191 let x_coordinates = [1414213562, 1732050807, 1618033988, 1234567890];
1192 let y_coordinates = [1234567890, 1414213562, 1732050807, 1618033988];
1193 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1194 let y = qm31_coordinates_to_packed_reduced(y_coordinates);
1195 let res = qm31_packed_reduced_add(x, y).unwrap();
1196 let res_coordinates = qm31_packed_reduced_read_coordinates(res);
1197 assert_eq!(
1198 res_coordinates,
1199 Ok([
1200 (1414213562 + 1234567890) % STWO_PRIME,
1201 (1732050807 + 1414213562) % STWO_PRIME,
1202 (1618033988 + 1732050807) % STWO_PRIME,
1203 (1234567890 + 1618033988) % STWO_PRIME,
1204 ])
1205 );
1206 }
1207
1208 #[test]
1209 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1210 fn test_qm31_packed_reduced_neg() {
1211 let x_coordinates = [1749652895, 834624081, 1930174752, 2063872165];
1212 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1213 let res = qm31_packed_reduced_neg(x).unwrap();
1214 let res_coordinates = qm31_packed_reduced_read_coordinates(res);
1215 assert_eq!(
1216 res_coordinates,
1217 Ok([
1218 STWO_PRIME - x_coordinates[0],
1219 STWO_PRIME - x_coordinates[1],
1220 STWO_PRIME - x_coordinates[2],
1221 STWO_PRIME - x_coordinates[3]
1222 ])
1223 );
1224 }
1225
1226 #[test]
1227 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1228 fn test_qm31_packed_reduced_sub() {
1229 let x_coordinates = [
1230 (1414213562 + 1234567890) % STWO_PRIME,
1231 (1732050807 + 1414213562) % STWO_PRIME,
1232 (1618033988 + 1732050807) % STWO_PRIME,
1233 (1234567890 + 1618033988) % STWO_PRIME,
1234 ];
1235 let y_coordinates = [1414213562, 1732050807, 1618033988, 1234567890];
1236 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1237 let y = qm31_coordinates_to_packed_reduced(y_coordinates);
1238 let res = qm31_packed_reduced_sub(x, y).unwrap();
1239 let res_coordinates = qm31_packed_reduced_read_coordinates(res);
1240 assert_eq!(
1241 res_coordinates,
1242 Ok([1234567890, 1414213562, 1732050807, 1618033988])
1243 );
1244 }
1245
1246 #[test]
1247 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1248 fn test_qm31_packed_reduced_mul() {
1249 let x_coordinates = [1414213562, 1732050807, 1618033988, 1234567890];
1250 let y_coordinates = [1259921049, 1442249570, 1847759065, 2094551481];
1251 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1252 let y = qm31_coordinates_to_packed_reduced(y_coordinates);
1253 let res = qm31_packed_reduced_mul(x, y).unwrap();
1254 let res_coordinates = qm31_packed_reduced_read_coordinates(res);
1255 assert_eq!(
1256 res_coordinates,
1257 Ok([947980980, 1510986506, 623360030, 1260310989])
1258 );
1259 }
1260
1261 #[test]
1262 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1263 fn test_qm31_packed_reduced_inv() {
1264 let x_coordinates = [1259921049, 1442249570, 1847759065, 2094551481];
1265 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1266 let res = qm31_packed_reduced_inv(x).unwrap();
1267 assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1)));
1268
1269 let x_coordinates = [1, 2, 3, 4];
1270 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1271 let res = qm31_packed_reduced_inv(x).unwrap();
1272 assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1)));
1273
1274 let x_coordinates = [1749652895, 834624081, 1930174752, 2063872165];
1275 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1276 let res = qm31_packed_reduced_inv(x).unwrap();
1277 assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1)));
1278 }
1279
1280 #[test]
1282 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1283 fn test_qm31_packed_reduced_inv_extensive() {
1284 let mut rng = SmallRng::seed_from_u64(11480028852697973135);
1285 #[derive(Clone, Copy)]
1286 enum Configuration {
1287 Zero,
1288 One,
1289 MinusOne,
1290 Random,
1291 }
1292 let configurations = [
1293 Configuration::Zero,
1294 Configuration::One,
1295 Configuration::MinusOne,
1296 Configuration::Random,
1297 ];
1298 let mut cartesian_product = vec![];
1299 for &a in &configurations {
1300 for &b in &configurations {
1301 for &c in &configurations {
1302 for &d in &configurations {
1303 cartesian_product.push([a, b, c, d]);
1304 }
1305 }
1306 }
1307 }
1308
1309 for test_case in cartesian_product {
1310 let x_coordinates: [u64; 4] = test_case
1311 .iter()
1312 .map(|&x| match x {
1313 Configuration::Zero => 0,
1314 Configuration::One => 1,
1315 Configuration::MinusOne => STWO_PRIME - 1,
1316 Configuration::Random => rng.gen_range(0..STWO_PRIME),
1317 })
1318 .collect::<Vec<u64>>()
1319 .try_into()
1320 .unwrap();
1321 if x_coordinates == [0, 0, 0, 0] {
1322 continue;
1323 }
1324 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1325 let res = qm31_packed_reduced_inv(x).unwrap();
1326 assert_eq!(qm31_packed_reduced_mul(x, res), Ok(Felt252::from(1)));
1327 }
1328 }
1329
1330 #[test]
1331 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1332 fn test_qm31_packed_reduced_div() {
1333 let x_coordinates = [1259921049, 1442249570, 1847759065, 2094551481];
1334 let y_coordinates = [1414213562, 1732050807, 1618033988, 1234567890];
1335 let xy_coordinates = [947980980, 1510986506, 623360030, 1260310989];
1336 let x = qm31_coordinates_to_packed_reduced(x_coordinates);
1337 let y = qm31_coordinates_to_packed_reduced(y_coordinates);
1338 let xy = qm31_coordinates_to_packed_reduced(xy_coordinates);
1339
1340 let res = qm31_packed_reduced_div(xy, y).unwrap();
1341 assert_eq!(res, x);
1342
1343 let res = qm31_packed_reduced_div(xy, x).unwrap();
1344 assert_eq!(res, y);
1345 }
1346
1347 #[cfg(feature = "std")]
1348 proptest! {
1349 #[test]
1350 fn pow2_const_in_range_returns_power_of_2(x in 0..=251u32) {
1351 prop_assert_eq!(pow2_const(x), Felt252::TWO.pow(x));
1352 }
1353
1354 #[test]
1355 fn pow2_const_oob_returns_1(x in 252u32..) {
1356 prop_assert_eq!(pow2_const(x), Felt252::ONE);
1357 }
1358
1359 #[test]
1360 fn pow2_const_nz_in_range_returns_power_of_2(x in 0..=251u32) {
1361 prop_assert_eq!(Felt252::from(pow2_const_nz(x)), Felt252::TWO.pow(x));
1362 }
1363
1364 #[test]
1365 fn pow2_const_nz_oob_returns_1(x in 252u32..) {
1366 prop_assert_eq!(Felt252::from(pow2_const_nz(x)), Felt252::ONE);
1367 }
1368
1369 #[test]
1370 fn sqrt_prime_power_using_random_prime(ref x in any::<[u8; 38]>(), ref y in any::<u64>()) {
1372 let mut rng = SmallRng::seed_from_u64(*y);
1373 let x = &BigUint::from_bytes_be(x);
1374 let p : &BigUint = &RandPrime::gen_prime(&mut rng, 384, None);
1376 let x_sq = x * x;
1377 if let Some(sqrt) = sqrt_prime_power(&x_sq, p) {
1378 if &sqrt != x {
1379 prop_assert_eq!(&(p - sqrt), x);
1380 } else {
1381 prop_assert_eq!(&sqrt, x);
1382 }
1383 }
1384 }
1385
1386 #[test]
1387 fn mul_inv_x_by_x_is_1(ref x in any::<[u8; 32]>()) {
1388 let p = &(*CAIRO_PRIME).clone().into();
1389 let pos_x = &BigInt::from_bytes_be(Sign::Plus, x);
1390 let neg_x = &BigInt::from_bytes_be(Sign::Minus, x);
1391 let pos_x_inv = mul_inv(pos_x, p);
1392 let neg_x_inv = mul_inv(neg_x, p);
1393
1394 prop_assert_eq!((pos_x * pos_x_inv).mod_floor(p), BigInt::one());
1395 prop_assert_eq!((neg_x * neg_x_inv).mod_floor(p), BigInt::one());
1396 }
1397 }
1398}