1#![allow(clippy::needless_range_loop)]
10
11use core::cmp::Ordering;
53
54#[derive(Clone, Debug)]
56pub struct BigInt {
57 pub limbs: Vec<u64>,
59}
60
61impl BigInt {
66 pub fn zero() -> Self {
68 Self { limbs: vec![0] }
69 }
70
71 pub fn from_u64(v: u64) -> Self {
73 Self { limbs: vec![v] }
74 }
75
76 pub fn from_be_bytes(bytes: &[u8]) -> Self {
78 if bytes.is_empty() {
79 return Self::zero();
80 }
81 let padded_len = bytes.len().div_ceil(8) * 8;
83 let mut padded = vec![0u8; padded_len];
84 padded[padded_len - bytes.len()..].copy_from_slice(bytes);
85
86 let n_limbs = padded_len / 8;
87 let mut limbs = Vec::with_capacity(n_limbs);
88 for i in (0..n_limbs).rev() {
89 let off = i * 8;
90 let limb = u64::from_be_bytes([
91 padded[off],
92 padded[off + 1],
93 padded[off + 2],
94 padded[off + 3],
95 padded[off + 4],
96 padded[off + 5],
97 padded[off + 6],
98 padded[off + 7],
99 ]);
100 limbs.push(limb);
101 }
102 let mut r = Self { limbs };
103 r.trim();
104 r
105 }
106
107 pub fn to_be_bytes(&self, min_len: usize) -> Vec<u8> {
109 let n = self.limbs.len();
110 let byte_len = n * 8;
111 let mut buf = vec![0u8; byte_len];
112 for (i, &limb) in self.limbs.iter().enumerate() {
113 let off = byte_len - (i + 1) * 8;
114 buf[off..off + 8].copy_from_slice(&limb.to_be_bytes());
115 }
116 let start = buf.iter().position(|&b| b != 0).unwrap_or(buf.len());
118 let significant = &buf[start..];
119 if significant.len() >= min_len {
120 significant.to_vec()
121 } else {
122 let mut out = vec![0u8; min_len];
123 out[min_len - significant.len()..].copy_from_slice(significant);
124 out
125 }
126 }
127
128 pub fn bit_len(&self) -> usize {
130 let n = self.limbs.len();
131 if n == 0 {
132 return 0;
133 }
134 let top = self.limbs[n - 1];
135 if top == 0 && n == 1 {
136 return 0;
137 }
138 (n - 1) * 64 + (64 - top.leading_zeros() as usize)
139 }
140
141 pub fn bit(&self, i: usize) -> bool {
143 let limb_idx = i / 64;
144 let bit_idx = i % 64;
145 if limb_idx >= self.limbs.len() {
146 false
147 } else {
148 (self.limbs[limb_idx] >> bit_idx) & 1 == 1
149 }
150 }
151
152 pub fn set_bit(&mut self, i: usize) {
154 let limb_idx = i / 64;
155 let bit_idx = i % 64;
156 while self.limbs.len() <= limb_idx {
157 self.limbs.push(0);
158 }
159 self.limbs[limb_idx] |= 1u64 << bit_idx;
160 }
161
162 pub fn is_zero(&self) -> bool {
164 self.limbs.iter().all(|&l| l == 0)
165 }
166
167 pub fn is_even(&self) -> bool {
169 self.limbs.first().is_none_or(|&l| l & 1 == 0)
170 }
171
172 pub fn is_odd(&self) -> bool {
174 !self.is_even()
175 }
176
177 fn trim(&mut self) {
179 while self.limbs.len() > 1 && *self.limbs.last().unwrap() == 0 {
180 self.limbs.pop();
181 }
182 }
183
184 pub fn byte_len(&self) -> usize {
186 self.bit_len().div_ceil(8)
187 }
188
189 pub fn random(bits: usize, rng: &mut dyn FnMut(&mut [u8])) -> Self {
191 let byte_len = bits.div_ceil(8);
192 let mut buf = vec![0u8; byte_len];
193 rng(&mut buf);
194 let top_bit = (bits - 1) % 8;
196 if top_bit < 7 {
198 buf[0] &= (1u8 << (top_bit + 1)) - 1;
199 }
200 buf[0] |= 1u8 << top_bit; Self::from_be_bytes(&buf)
202 }
203
204 pub fn random_odd(bits: usize, rng: &mut dyn FnMut(&mut [u8])) -> Self {
206 let mut n = Self::random(bits, rng);
207 n.limbs[0] |= 1; n
209 }
210}
211
212impl PartialEq for BigInt {
217 fn eq(&self, other: &Self) -> bool {
218 self.cmp_to(other) == Ordering::Equal
219 }
220}
221impl Eq for BigInt {}
222
223impl PartialOrd for BigInt {
224 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
225 Some(self.cmp(other))
226 }
227}
228
229impl Ord for BigInt {
230 fn cmp(&self, other: &Self) -> Ordering {
231 self.cmp_to(other)
232 }
233}
234
235impl BigInt {
236 pub fn cmp_to(&self, other: &Self) -> Ordering {
241 let a_len = self.limbs.len();
242 let b_len = other.limbs.len();
243 let max_len = a_len.max(b_len);
244 for i in (0..max_len).rev() {
245 let a = if i < a_len { self.limbs[i] } else { 0 };
246 let b = if i < b_len { other.limbs[i] } else { 0 };
247 match a.cmp(&b) {
248 Ordering::Equal => continue,
249 ord => return ord,
250 }
251 }
252 Ordering::Equal
253 }
254}
255
256impl BigInt {
261 pub fn add(&self, other: &BigInt) -> BigInt {
263 let max_len = self.limbs.len().max(other.limbs.len());
264 let mut result = Vec::with_capacity(max_len + 1);
265 let mut carry: u64 = 0;
266 for i in 0..max_len {
267 let a = if i < self.limbs.len() { self.limbs[i] } else { 0 };
268 let b = if i < other.limbs.len() { other.limbs[i] } else { 0 };
269 let (sum1, c1) = a.overflowing_add(b);
270 let (sum2, c2) = sum1.overflowing_add(carry);
271 result.push(sum2);
272 carry = (c1 as u64) + (c2 as u64);
273 }
274 if carry > 0 {
275 result.push(carry);
276 }
277 let mut r = BigInt { limbs: result };
278 r.trim();
279 r
280 }
281
282 pub fn add_u64(&self, v: u64) -> BigInt {
284 self.add(&BigInt::from_u64(v))
285 }
286}
287
288impl BigInt {
293 pub fn sub(&self, other: &BigInt) -> BigInt {
295 debug_assert!(self >= other, "BigInt::sub: underflow");
296 let mut result = Vec::with_capacity(self.limbs.len());
297 let mut borrow: u64 = 0;
298 for i in 0..self.limbs.len() {
299 let a = self.limbs[i];
300 let b = if i < other.limbs.len() { other.limbs[i] } else { 0 };
301 let (diff1, b1) = a.overflowing_sub(b);
302 let (diff2, b2) = diff1.overflowing_sub(borrow);
303 result.push(diff2);
304 borrow = (b1 as u64) + (b2 as u64);
305 }
306 let mut r = BigInt { limbs: result };
307 r.trim();
308 r
309 }
310
311 pub fn sub_one(&self) -> BigInt {
313 self.sub(&BigInt::from_u64(1))
314 }
315}
316
317impl BigInt {
322 pub fn mul(&self, other: &BigInt) -> BigInt {
324 let n = self.limbs.len();
325 let m = other.limbs.len();
326 let mut result = vec![0u64; n + m];
327 for i in 0..n {
328 let mut carry: u64 = 0;
329 for j in 0..m {
330 let (lo, hi) = mul_u64(self.limbs[i], other.limbs[j]);
331 let (s1, c1) = result[i + j].overflowing_add(lo);
332 let (s2, c2) = s1.overflowing_add(carry);
333 result[i + j] = s2;
334 carry = hi + (c1 as u64) + (c2 as u64);
335 }
336 result[i + m] = carry;
337 }
338 let mut r = BigInt { limbs: result };
339 r.trim();
340 r
341 }
342}
343
344#[inline]
346fn mul_u64(a: u64, b: u64) -> (u64, u64) {
347 let full = (a as u128) * (b as u128);
348 (full as u64, (full >> 64) as u64)
349}
350
351impl BigInt {
356 pub fn div_rem(&self, divisor: &BigInt) -> (BigInt, BigInt) {
359 assert!(!divisor.is_zero(), "BigInt: division by zero");
360 if self < divisor {
361 return (BigInt::zero(), self.clone());
362 }
363 if divisor.limbs.len() == 1 {
364 return self.div_rem_u64(divisor.limbs[0]);
365 }
366 self.div_rem_knuth(divisor)
367 }
368
369 fn div_rem_u64(&self, d: u64) -> (BigInt, BigInt) {
371 let mut rem: u128 = 0;
372 let mut quotient = vec![0u64; self.limbs.len()];
373 for i in (0..self.limbs.len()).rev() {
374 rem = (rem << 64) | (self.limbs[i] as u128);
375 quotient[i] = (rem / d as u128) as u64;
376 rem %= d as u128;
377 }
378 let mut q = BigInt { limbs: quotient };
379 q.trim();
380 (q, BigInt::from_u64(rem as u64))
381 }
382
383 fn div_rem_knuth(&self, divisor: &BigInt) -> (BigInt, BigInt) {
385 let shift = divisor.limbs.last().unwrap().leading_zeros() as usize;
387 let a = self.shl(shift);
388 let b = divisor.shl(shift);
389
390 let n = b.limbs.len();
391 let m = a.limbs.len() - n;
392
393 let mut q_limbs = vec![0u64; m + 1];
394 let mut u = a.limbs.clone();
396 if u.len() <= n + m {
397 u.resize(n + m + 1, 0);
398 }
399
400 let b_top = *b.limbs.last().unwrap() as u128;
401
402 for j in (0..=m).rev() {
403 let u_hi = ((u[j + n] as u128) << 64) | (u[j + n - 1] as u128);
405 let mut q_hat = u_hi / b_top;
406 let mut r_hat = u_hi % b_top;
407
408 if n >= 2 {
410 let b_second = b.limbs[n - 2] as u128;
411 while q_hat >= (1u128 << 64) || q_hat * b_second > (r_hat << 64) | (u[j + n - 2] as u128) {
412 q_hat -= 1;
413 r_hat += b_top;
414 if r_hat >= (1u128 << 64) {
415 break;
416 }
417 }
418 }
419
420 let mut borrow: i128 = 0;
422 for i in 0..n {
423 let prod = q_hat * (b.limbs[i] as u128);
424 let diff = (u[j + i] as i128) - borrow - (prod as u64 as i128);
425 u[j + i] = diff as u64;
426 borrow = (prod >> 64) as i128 - (diff >> 64);
427 }
428 let diff = (u[j + n] as i128) - borrow;
429 u[j + n] = diff as u64;
430
431 q_limbs[j] = q_hat as u64;
432
433 if diff < 0 {
435 q_limbs[j] -= 1;
436 let mut carry: u64 = 0;
437 for i in 0..n {
438 let (s1, c1) = u[j + i].overflowing_add(b.limbs[i]);
439 let (s2, c2) = s1.overflowing_add(carry);
440 u[j + i] = s2;
441 carry = (c1 as u64) + (c2 as u64);
442 }
443 u[j + n] = u[j + n].wrapping_add(carry);
444 }
445 }
446
447 let mut q = BigInt { limbs: q_limbs };
448 q.trim();
449 u.truncate(n);
451 let mut r = BigInt { limbs: u };
452 r.trim();
453 r = r.shr(shift);
454 (q, r)
455 }
456
457 pub fn shl(&self, bits: usize) -> BigInt {
459 if bits == 0 {
460 return self.clone();
461 }
462 let limb_shift = bits / 64;
463 let bit_shift = bits % 64;
464 let mut result = vec![0u64; self.limbs.len() + limb_shift + 1];
465 let mut carry: u64 = 0;
466 for i in 0..self.limbs.len() {
467 if bit_shift == 0 {
468 result[i + limb_shift] = self.limbs[i];
469 } else {
470 result[i + limb_shift] = (self.limbs[i] << bit_shift) | carry;
471 carry = self.limbs[i] >> (64 - bit_shift);
472 }
473 }
474 if carry != 0 {
475 result[self.limbs.len() + limb_shift] = carry;
476 }
477 let mut r = BigInt { limbs: result };
478 r.trim();
479 r
480 }
481
482 pub fn shr(&self, bits: usize) -> BigInt {
484 if bits == 0 {
485 return self.clone();
486 }
487 let limb_shift = bits / 64;
488 let bit_shift = bits % 64;
489 if limb_shift >= self.limbs.len() {
490 return BigInt::zero();
491 }
492 let new_len = self.limbs.len() - limb_shift;
493 let mut result = vec![0u64; new_len];
494 for i in 0..new_len {
495 let src = i + limb_shift;
496 result[i] = if bit_shift == 0 {
497 self.limbs[src]
498 } else {
499 let lo = self.limbs[src] >> bit_shift;
500 let hi = if src + 1 < self.limbs.len() {
501 self.limbs[src + 1] << (64 - bit_shift)
502 } else {
503 0
504 };
505 lo | hi
506 };
507 }
508 let mut r = BigInt { limbs: result };
509 r.trim();
510 r
511 }
512
513 pub fn rem(&self, modulus: &BigInt) -> BigInt {
515 self.div_rem(modulus).1
516 }
517}
518
519pub struct MontParams {
525 pub n: BigInt,
527 pub n_limbs: usize,
529 pub n_inv_neg: u64,
531 pub r_mod_n: BigInt,
534 pub r2_mod_n: BigInt,
536}
537
538impl MontParams {
539 pub fn new(n: &BigInt) -> Self {
541 let n_limbs = n.limbs.len();
542
543 debug_assert!(n.is_odd(), "Montgomery requires odd modulus");
546 let n0 = n.limbs[0];
547 let n_inv_neg = mod_inv_u64_neg(n0);
548
549 let mut r_val = BigInt::zero();
552 r_val.set_bit(64 * n_limbs);
553 let r_mod_n = r_val.rem(n);
554
555 let r2_val = r_val.mul(&r_val);
556 let r2_mod_n = r2_val.rem(n);
557
558 MontParams {
559 n: n.clone(),
560 n_limbs,
561 n_inv_neg,
562 r_mod_n,
563 r2_mod_n,
564 }
565 }
566
567 pub fn to_mont(&self, a: &BigInt) -> BigInt {
569 self.mont_mul(a, &self.r2_mod_n)
570 }
571
572 pub fn from_mont(&self, a: &BigInt) -> BigInt {
574 self.mont_mul(a, &BigInt::from_u64(1))
575 }
576
577 pub fn mont_mul(&self, a: &BigInt, b: &BigInt) -> BigInt {
580 let n = self.n_limbs;
581 let mut t = vec![0u64; n + 2];
583
584 for i in 0..n {
585 let bi = if i < b.limbs.len() { b.limbs[i] } else { 0 };
586 let mut carry: u64 = 0;
588 for j in 0..n {
589 let aj = if j < a.limbs.len() { a.limbs[j] } else { 0 };
590 let (lo, hi) = mul_u64(aj, bi);
591 let (s1, c1) = t[j].overflowing_add(lo);
592 let (s2, c2) = s1.overflowing_add(carry);
593 t[j] = s2;
594 carry = hi + (c1 as u64) + (c2 as u64);
595 }
596 let (s, c) = t[n].overflowing_add(carry);
597 t[n] = s;
598 t[n + 1] = c as u64;
599
600 let m = t[0].wrapping_mul(self.n_inv_neg);
602
603 let mut carry: u64 = 0;
605 {
606 let (lo, hi) = mul_u64(m, self.n.limbs[0]);
607 let (s1, c1) = t[0].overflowing_add(lo);
608 let (_s2, c2) = s1.overflowing_add(carry);
609 carry = hi + (c1 as u64) + (c2 as u64);
611 }
612 for j in 1..n {
613 let nj = self.n.limbs[j];
614 let (lo, hi) = mul_u64(m, nj);
615 let (s1, c1) = t[j].overflowing_add(lo);
616 let (s2, c2) = s1.overflowing_add(carry);
617 t[j - 1] = s2;
618 carry = hi + (c1 as u64) + (c2 as u64);
619 }
620 let (s1, c1) = t[n].overflowing_add(carry);
621 t[n - 1] = s1;
622 t[n] = t[n + 1] + (c1 as u64);
623 t[n + 1] = 0;
624 }
625
626 t.truncate(n + 1);
628 let mut result = BigInt { limbs: t };
629 result.trim();
630 if result >= self.n {
631 result = result.sub(&self.n);
632 }
633 result.trim();
634 result
635 }
636
637 pub fn mod_exp(&self, base: &BigInt, exp: &BigInt) -> BigInt {
648 let base_mont = self.to_mont(base);
649 let bits = exp.bit_len();
650 if bits == 0 {
651 return BigInt::from_u64(1);
652 }
653
654 let mut r0 = self.r_mod_n.clone(); let mut r1 = base_mont.clone();
659
660 for i in (0..bits).rev() {
661 if exp.bit(i) {
662 r0 = self.mont_mul(&r0, &r1);
663 r1 = self.mont_mul(&r1, &r1);
664 } else {
665 r1 = self.mont_mul(&r0, &r1);
666 r0 = self.mont_mul(&r0, &r0);
667 }
668 }
669
670 self.from_mont(&r0)
671 }
672}
673
674fn mod_inv_u64_neg(n0: u64) -> u64 {
676 let mut x: u64 = 1; for _ in 0..6 {
680 x = x.wrapping_mul(2u64.wrapping_sub(n0.wrapping_mul(x)));
682 }
683 x.wrapping_neg()
685}
686
687impl BigInt {
692 pub fn mod_exp(&self, exp: &BigInt, modulus: &BigInt) -> BigInt {
696 let params = MontParams::new(modulus);
697 params.mod_exp(self, exp)
698 }
699
700 pub fn mod_inv(&self, modulus: &BigInt) -> Option<BigInt> {
703 let (g, x, _neg) = extended_gcd(self, modulus);
705 if g != BigInt::from_u64(1) {
706 return None;
707 }
708 Some(x)
709 }
710}
711
712fn extended_gcd(a: &BigInt, b: &BigInt) -> (BigInt, BigInt, bool) {
715 if a.is_zero() {
719 return (b.clone(), BigInt::zero(), false);
720 }
721
722 let mut old_r = a.clone();
724 let mut r = b.clone();
725 let mut old_s = BigInt::from_u64(1);
726 let mut s = BigInt::zero();
727 let mut old_s_neg = false; let mut s_neg = false; while !r.is_zero() {
731 let (q, remainder) = old_r.div_rem(&r);
732
733 old_r = r;
734 r = remainder;
735
736 let qs = q.mul(&s);
738 let (new_s, new_s_neg) = signed_sub(&old_s, old_s_neg, &qs, s_neg);
740 old_s = s;
741 old_s_neg = s_neg;
742 s = new_s;
743 s_neg = new_s_neg;
744 }
745
746 let x = if old_s_neg { b.sub(&old_s.rem(b)) } else { old_s.rem(b) };
748
749 (old_r, x, false)
750}
751
752fn signed_sub(a: &BigInt, a_neg: bool, b: &BigInt, b_neg: bool) -> (BigInt, bool) {
754 if a_neg == b_neg {
757 if a >= b { (a.sub(b), a_neg) } else { (b.sub(a), !a_neg) }
759 } else {
760 (a.add(b), a_neg)
762 }
763}
764
765impl BigInt {
770 pub fn is_probably_prime(&self, rounds: usize, rng: &mut dyn FnMut(&mut [u8])) -> bool {
773 if self.limbs.len() == 1 {
775 let v = self.limbs[0];
776 if v < 2 {
777 return false;
778 }
779 if v == 2 || v == 3 {
780 return true;
781 }
782 if v % 2 == 0 {
783 return false;
784 }
785 }
786 if self.is_even() {
787 return false;
788 }
789
790 let one = BigInt::from_u64(1);
791 let two = BigInt::from_u64(2);
792 let n_minus_1 = self.sub(&one);
793 let n_minus_2 = self.sub(&two);
794
795 let mut d = n_minus_1.clone();
797 let mut s: usize = 0;
798 while d.is_even() {
799 d = d.shr(1);
800 s += 1;
801 }
802
803 let mont = MontParams::new(self);
804
805 'next_round: for _ in 0..rounds {
806 let a = loop {
808 let candidate = BigInt::random(self.bit_len(), rng);
809 if candidate >= two && candidate <= n_minus_2 {
810 break candidate;
811 }
812 };
813
814 let mut x = mont.mod_exp(&a, &d);
815
816 if x == one || x == n_minus_1 {
817 continue 'next_round;
818 }
819
820 for _ in 0..s - 1 {
821 x = mont.mod_exp(&x, &two);
822 if x == n_minus_1 {
823 continue 'next_round;
824 }
825 }
826
827 return false; }
829
830 true }
832
833 pub fn random_prime(bits: usize, rng: &mut dyn FnMut(&mut [u8])) -> BigInt {
835 loop {
836 let candidate = BigInt::random_odd(bits, rng);
837 let small_primes: &[u64] = &[
839 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
840 107, 109, 113,
841 ];
842 let mut skip = false;
843 for &p in small_primes {
844 let (_, rem) = candidate.div_rem(&BigInt::from_u64(p));
845 if rem.is_zero() {
846 if candidate == BigInt::from_u64(p) {
847 return candidate;
848 }
849 skip = true;
850 break;
851 }
852 }
853 if skip {
854 continue;
855 }
856
857 let rounds = if bits >= 1024 { 4 } else { 8 };
859 if candidate.is_probably_prime(rounds, rng) {
860 return candidate;
861 }
862 }
863 }
864}
865
866#[cfg(test)]
871mod tests {
872 use super::*;
873
874 #[test]
875 fn test_add_sub() {
876 let a = BigInt::from_u64(u64::MAX);
877 let b = BigInt::from_u64(1);
878 let c = a.add(&b);
879 assert_eq!(c.limbs.len(), 2);
880 assert_eq!(c.limbs[0], 0);
881 assert_eq!(c.limbs[1], 1);
882 let d = c.sub(&b);
883 assert_eq!(d, a);
884 }
885
886 #[test]
887 fn test_mul() {
888 let a = BigInt::from_u64(0xFFFFFFFF);
889 let b = BigInt::from_u64(0xFFFFFFFF);
890 let c = a.mul(&b);
891 assert_eq!(c.limbs[0], 0xFFFFFFFE00000001);
893 }
894
895 #[test]
896 fn test_div_rem() {
897 let a = BigInt::from_u64(100);
898 let b = BigInt::from_u64(7);
899 let (q, r) = a.div_rem(&b);
900 assert_eq!(q, BigInt::from_u64(14));
901 assert_eq!(r, BigInt::from_u64(2));
902 }
903
904 #[test]
905 fn test_mod_exp() {
906 let base = BigInt::from_u64(3);
908 let exp = BigInt::from_u64(10);
909 let modulus = BigInt::from_u64(7);
910 let result = base.mod_exp(&exp, &modulus);
911 assert_eq!(result, BigInt::from_u64(4));
912 }
913
914 #[test]
915 fn test_mod_inv() {
916 let a = BigInt::from_u64(3);
918 let m = BigInt::from_u64(7);
919 let inv = a.mod_inv(&m).unwrap();
920 assert_eq!(inv, BigInt::from_u64(5));
921 }
922
923 #[test]
924 fn test_from_be_bytes_roundtrip() {
925 let bytes = vec![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
926 let n = BigInt::from_be_bytes(&bytes);
927 let out = n.to_be_bytes(8);
928 assert_eq!(out, bytes);
929 }
930
931 #[test]
932 fn test_bit_ops() {
933 let mut n = BigInt::zero();
934 n.set_bit(65);
935 assert!(n.bit(65));
936 assert!(!n.bit(64));
937 assert_eq!(n.bit_len(), 66);
938 }
939
940 fn test_rng() -> impl FnMut(&mut [u8]) {
941 let mut state: u64 = 0xdeadbeefcafebabe;
942 move |buf: &mut [u8]| {
943 for b in buf.iter_mut() {
944 state = state
945 .wrapping_mul(6364136223846793005)
946 .wrapping_add(1442695040888963407);
947 *b = (state >> 33) as u8;
948 }
949 }
950 }
951
952 #[test]
953 fn test_primality() {
954 let mut rng = test_rng();
955 assert!(BigInt::from_u64(7).is_probably_prime(10, &mut rng));
957 assert!(!BigInt::from_u64(15).is_probably_prime(10, &mut rng));
959 assert!(BigInt::from_u64(104729).is_probably_prime(10, &mut rng));
961 }
962}