1use crate::ffi;
26use crate::libc_types::c_int;
27use foreign_types::{ForeignType, ForeignTypeRef};
28use std::cmp::Ordering;
29use std::ffi::CString;
30use std::ops::{Add, Deref, Div, Mul, Neg, Rem, Shl, Shr, Sub};
31use std::{fmt, ptr};
32
33use crate::asn1::Asn1Integer;
34use crate::error::ErrorStack;
35use crate::ffi::BN_is_negative;
36use crate::string::OpensslString;
37use crate::{cvt, cvt_n, cvt_p};
38use openssl_macros::corresponds;
39
40pub struct MsbOption(c_int);
42
43impl MsbOption {
44 pub const MAYBE_ZERO: MsbOption = MsbOption(-1);
46
47 pub const ONE: MsbOption = MsbOption(0);
49
50 pub const TWO_ONES: MsbOption = MsbOption(1);
55}
56
57foreign_type_and_impl_send_sync! {
58 type CType = ffi::BN_CTX;
59 fn drop = ffi::BN_CTX_free;
60
61 pub struct BigNumContext;
69}
70
71impl BigNumContext {
72 #[corresponds(BN_CTX_new)]
74 pub fn new() -> Result<BigNumContext, ErrorStack> {
75 unsafe {
76 ffi::init();
77 cvt_p(ffi::BN_CTX_new()).map(|p| BigNumContext::from_ptr(p))
78 }
79 }
80}
81
82foreign_type_and_impl_send_sync! {
83 type CType = ffi::BIGNUM;
84 fn drop = ffi::BN_free;
85
86 pub struct BigNum;
110}
111
112impl BigNumRef {
113 #[corresponds(BN_clear)]
117 pub fn clear(&mut self) {
118 unsafe { ffi::BN_clear(self.as_ptr()) }
119 }
120
121 #[corresponds(BN_add_word)]
123 pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> {
124 unsafe { cvt(ffi::BN_add_word(self.as_ptr(), ffi::BN_ULONG::from(w))) }
125 }
126
127 #[corresponds(BN_sub_word)]
129 pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> {
130 unsafe { cvt(ffi::BN_sub_word(self.as_ptr(), ffi::BN_ULONG::from(w))) }
131 }
132
133 #[corresponds(BN_mul_word)]
135 pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> {
136 unsafe { cvt(ffi::BN_mul_word(self.as_ptr(), ffi::BN_ULONG::from(w))) }
137 }
138
139 #[corresponds(BN_div_word)]
141 #[allow(clippy::useless_conversion)]
142 pub fn div_word(&mut self, w: u32) -> Result<u64, ErrorStack> {
143 unsafe {
144 let r = ffi::BN_div_word(self.as_ptr(), w.into());
145 if r == ffi::BN_ULONG::MAX {
146 Err(ErrorStack::get())
147 } else {
148 Ok(r.into())
149 }
150 }
151 }
152
153 #[corresponds(BN_mod_word)]
155 #[allow(clippy::useless_conversion)]
156 pub fn mod_word(&self, w: u32) -> Result<u64, ErrorStack> {
157 unsafe {
158 let r = ffi::BN_mod_word(self.as_ptr(), w.into());
159 if r == ffi::BN_ULONG::MAX {
160 Err(ErrorStack::get())
161 } else {
162 Ok(r.into())
163 }
164 }
165 }
166
167 #[corresponds(BN_rand_range)]
170 pub fn rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> {
171 unsafe { cvt(ffi::BN_rand_range(rnd.as_ptr(), self.as_ptr())) }
172 }
173
174 #[corresponds(BN_pseudo_rand_range)]
176 pub fn pseudo_rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> {
177 unsafe { cvt(ffi::BN_pseudo_rand_range(rnd.as_ptr(), self.as_ptr())) }
178 }
179
180 #[corresponds(BN_set_bit)]
184 #[allow(clippy::useless_conversion)]
185 pub fn set_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
186 unsafe { cvt(ffi::BN_clear_bit(self.as_ptr(), n.into())) }
187 }
188
189 #[corresponds(BN_clear_bit)]
193 #[allow(clippy::useless_conversion)]
194 pub fn clear_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
195 unsafe { cvt(ffi::BN_clear_bit(self.as_ptr(), n.into())) }
196 }
197
198 #[corresponds(BN_is_bit_set)]
200 #[allow(clippy::useless_conversion)]
201 #[must_use]
202 pub fn is_bit_set(&self, n: i32) -> bool {
203 unsafe { ffi::BN_is_bit_set(self.as_ptr(), n.into()) == 1 }
204 }
205
206 #[corresponds(BN_mask_bits)]
210 #[allow(clippy::useless_conversion)]
211 pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> {
212 unsafe { cvt(ffi::BN_mask_bits(self.as_ptr(), n.into())) }
213 }
214
215 #[corresponds(BN_lshift1)]
217 pub fn lshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> {
218 unsafe { cvt(ffi::BN_lshift1(self.as_ptr(), a.as_ptr())) }
219 }
220
221 #[corresponds(BN_rshift1)]
223 pub fn rshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> {
224 unsafe { cvt(ffi::BN_rshift1(self.as_ptr(), a.as_ptr())) }
225 }
226
227 #[corresponds(BN_add)]
231 pub fn checked_add(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> {
232 unsafe { cvt(ffi::BN_add(self.as_ptr(), a.as_ptr(), b.as_ptr())) }
233 }
234
235 #[corresponds(BN_sub)]
239 pub fn checked_sub(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> {
240 unsafe { cvt(ffi::BN_sub(self.as_ptr(), a.as_ptr(), b.as_ptr())) }
241 }
242
243 #[corresponds(BN_lshift)]
245 #[allow(clippy::useless_conversion)]
246 pub fn lshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> {
247 unsafe { cvt(ffi::BN_lshift(self.as_ptr(), a.as_ptr(), n.into())) }
248 }
249
250 #[corresponds(BN_rshift)]
252 #[allow(clippy::useless_conversion)]
253 pub fn rshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> {
254 unsafe { cvt(ffi::BN_rshift(self.as_ptr(), a.as_ptr(), n.into())) }
255 }
256
257 #[corresponds(BN_dup)]
259 pub fn to_owned(&self) -> Result<BigNum, ErrorStack> {
260 unsafe { cvt_p(ffi::BN_dup(self.as_ptr())).map(|b| BigNum::from_ptr(b)) }
261 }
262
263 #[corresponds(BN_set_negative)]
266 pub fn set_negative(&mut self, negative: bool) {
267 unsafe { ffi::BN_set_negative(self.as_ptr(), c_int::from(negative)) }
268 }
269
270 #[corresponds(BN_ucmp)]
283 #[must_use]
284 pub fn ucmp(&self, oth: &BigNumRef) -> Ordering {
285 unsafe { ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
286 }
287
288 #[corresponds(BN_is_negative)]
290 #[must_use]
291 pub fn is_negative(&self) -> bool {
292 unsafe { BN_is_negative(self.as_ptr()) == 1 }
293 }
294
295 #[corresponds(BN_num_bits)]
297 #[must_use]
298 pub fn num_bits(&self) -> i32 {
299 unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 }
300 }
301
302 #[must_use]
304 pub fn num_bytes(&self) -> i32 {
305 (self.num_bits() + 7) / 8
306 }
307
308 #[corresponds(BN_rand)]
333 #[allow(clippy::useless_conversion)]
334 pub fn rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> {
335 unsafe {
336 cvt(ffi::BN_rand(
337 self.as_ptr(),
338 bits.into(),
339 msb.0,
340 c_int::from(odd),
341 ))
342 }
343 }
344
345 #[corresponds(BN_pseudo_rand)]
347 #[allow(clippy::useless_conversion)]
348 pub fn pseudo_rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> {
349 unsafe {
350 cvt(ffi::BN_pseudo_rand(
351 self.as_ptr(),
352 bits.into(),
353 msb.0,
354 c_int::from(odd),
355 ))
356 }
357 }
358
359 #[corresponds(BN_generate_prime_ex)]
383 pub fn generate_prime(
384 &mut self,
385 bits: i32,
386 safe: bool,
387 add: Option<&BigNumRef>,
388 rem: Option<&BigNumRef>,
389 ) -> Result<(), ErrorStack> {
390 unsafe {
391 cvt(ffi::BN_generate_prime_ex(
392 self.as_ptr(),
393 c_int::from(bits),
394 c_int::from(safe),
395 add.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()),
396 rem.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()),
397 ptr::null_mut(),
398 ))
399 }
400 }
401
402 #[corresponds(BN_mul)]
407 pub fn checked_mul(
408 &mut self,
409 a: &BigNumRef,
410 b: &BigNumRef,
411 ctx: &mut BigNumContextRef,
412 ) -> Result<(), ErrorStack> {
413 unsafe {
414 cvt(ffi::BN_mul(
415 self.as_ptr(),
416 a.as_ptr(),
417 b.as_ptr(),
418 ctx.as_ptr(),
419 ))
420 }
421 }
422
423 #[corresponds(BN_div)]
428 pub fn checked_div(
429 &mut self,
430 a: &BigNumRef,
431 b: &BigNumRef,
432 ctx: &mut BigNumContextRef,
433 ) -> Result<(), ErrorStack> {
434 unsafe {
435 cvt(ffi::BN_div(
436 self.as_ptr(),
437 ptr::null_mut(),
438 a.as_ptr(),
439 b.as_ptr(),
440 ctx.as_ptr(),
441 ))
442 }
443 }
444
445 #[corresponds(BN_div)]
447 pub fn checked_rem(
448 &mut self,
449 a: &BigNumRef,
450 b: &BigNumRef,
451 ctx: &mut BigNumContextRef,
452 ) -> Result<(), ErrorStack> {
453 unsafe {
454 cvt(ffi::BN_div(
455 ptr::null_mut(),
456 self.as_ptr(),
457 a.as_ptr(),
458 b.as_ptr(),
459 ctx.as_ptr(),
460 ))
461 }
462 }
463
464 #[corresponds(BN_div)]
466 pub fn div_rem(
467 &mut self,
468 rem: &mut BigNumRef,
469 a: &BigNumRef,
470 b: &BigNumRef,
471 ctx: &mut BigNumContextRef,
472 ) -> Result<(), ErrorStack> {
473 unsafe {
474 cvt(ffi::BN_div(
475 self.as_ptr(),
476 rem.as_ptr(),
477 a.as_ptr(),
478 b.as_ptr(),
479 ctx.as_ptr(),
480 ))
481 }
482 }
483
484 #[corresponds(BN_sqr)]
486 pub fn sqr(&mut self, a: &BigNumRef, ctx: &mut BigNumContextRef) -> Result<(), ErrorStack> {
487 unsafe { cvt(ffi::BN_sqr(self.as_ptr(), a.as_ptr(), ctx.as_ptr())) }
488 }
489
490 #[corresponds(BN_nnmod)]
493 pub fn nnmod(
494 &mut self,
495 a: &BigNumRef,
496 m: &BigNumRef,
497 ctx: &mut BigNumContextRef,
498 ) -> Result<(), ErrorStack> {
499 unsafe {
500 cvt(ffi::BN_nnmod(
501 self.as_ptr(),
502 a.as_ptr(),
503 m.as_ptr(),
504 ctx.as_ptr(),
505 ))
506 }
507 }
508
509 #[corresponds(BN_mod_add)]
511 pub fn mod_add(
512 &mut self,
513 a: &BigNumRef,
514 b: &BigNumRef,
515 m: &BigNumRef,
516 ctx: &mut BigNumContextRef,
517 ) -> Result<(), ErrorStack> {
518 unsafe {
519 cvt(ffi::BN_mod_add(
520 self.as_ptr(),
521 a.as_ptr(),
522 b.as_ptr(),
523 m.as_ptr(),
524 ctx.as_ptr(),
525 ))
526 }
527 }
528
529 #[corresponds(BN_mod_sub)]
531 pub fn mod_sub(
532 &mut self,
533 a: &BigNumRef,
534 b: &BigNumRef,
535 m: &BigNumRef,
536 ctx: &mut BigNumContextRef,
537 ) -> Result<(), ErrorStack> {
538 unsafe {
539 cvt(ffi::BN_mod_sub(
540 self.as_ptr(),
541 a.as_ptr(),
542 b.as_ptr(),
543 m.as_ptr(),
544 ctx.as_ptr(),
545 ))
546 }
547 }
548
549 #[corresponds(BN_mod_mul)]
551 pub fn mod_mul(
552 &mut self,
553 a: &BigNumRef,
554 b: &BigNumRef,
555 m: &BigNumRef,
556 ctx: &mut BigNumContextRef,
557 ) -> Result<(), ErrorStack> {
558 unsafe {
559 cvt(ffi::BN_mod_mul(
560 self.as_ptr(),
561 a.as_ptr(),
562 b.as_ptr(),
563 m.as_ptr(),
564 ctx.as_ptr(),
565 ))
566 }
567 }
568
569 #[corresponds(BN_mod_sqr)]
571 pub fn mod_sqr(
572 &mut self,
573 a: &BigNumRef,
574 m: &BigNumRef,
575 ctx: &mut BigNumContextRef,
576 ) -> Result<(), ErrorStack> {
577 unsafe {
578 cvt(ffi::BN_mod_sqr(
579 self.as_ptr(),
580 a.as_ptr(),
581 m.as_ptr(),
582 ctx.as_ptr(),
583 ))
584 }
585 }
586
587 #[corresponds(BN_exp)]
589 pub fn exp(
590 &mut self,
591 a: &BigNumRef,
592 p: &BigNumRef,
593 ctx: &mut BigNumContextRef,
594 ) -> Result<(), ErrorStack> {
595 unsafe {
596 cvt(ffi::BN_exp(
597 self.as_ptr(),
598 a.as_ptr(),
599 p.as_ptr(),
600 ctx.as_ptr(),
601 ))
602 }
603 }
604
605 #[corresponds(BN_mod_exp)]
607 pub fn mod_exp(
608 &mut self,
609 a: &BigNumRef,
610 p: &BigNumRef,
611 m: &BigNumRef,
612 ctx: &mut BigNumContextRef,
613 ) -> Result<(), ErrorStack> {
614 unsafe {
615 cvt(ffi::BN_mod_exp(
616 self.as_ptr(),
617 a.as_ptr(),
618 p.as_ptr(),
619 m.as_ptr(),
620 ctx.as_ptr(),
621 ))
622 }
623 }
624
625 #[corresponds(BN_mod_inverse)]
627 pub fn mod_inverse(
628 &mut self,
629 a: &BigNumRef,
630 n: &BigNumRef,
631 ctx: &mut BigNumContextRef,
632 ) -> Result<(), ErrorStack> {
633 unsafe {
634 cvt_p(ffi::BN_mod_inverse(
635 self.as_ptr(),
636 a.as_ptr(),
637 n.as_ptr(),
638 ctx.as_ptr(),
639 ))
640 .map(|_| ())
641 }
642 }
643
644 #[corresponds(BN_gcd)]
646 pub fn gcd(
647 &mut self,
648 a: &BigNumRef,
649 b: &BigNumRef,
650 ctx: &mut BigNumContextRef,
651 ) -> Result<(), ErrorStack> {
652 unsafe {
653 cvt(ffi::BN_gcd(
654 self.as_ptr(),
655 a.as_ptr(),
656 b.as_ptr(),
657 ctx.as_ptr(),
658 ))
659 }
660 }
661
662 #[corresponds(BN_is_prime_ex)]
670 #[allow(clippy::useless_conversion)]
671 pub fn is_prime(&self, checks: i32, ctx: &mut BigNumContextRef) -> Result<bool, ErrorStack> {
672 unsafe {
673 cvt_n(ffi::BN_is_prime_ex(
674 self.as_ptr(),
675 checks.into(),
676 ctx.as_ptr(),
677 ptr::null_mut(),
678 ))
679 .map(|r| r != 0)
680 }
681 }
682
683 #[corresponds(BN_is_prime_fasttest_ex)]
693 #[allow(clippy::useless_conversion)]
694 pub fn is_prime_fasttest(
695 &self,
696 checks: i32,
697 ctx: &mut BigNumContextRef,
698 do_trial_division: bool,
699 ) -> Result<bool, ErrorStack> {
700 unsafe {
701 cvt_n(ffi::BN_is_prime_fasttest_ex(
702 self.as_ptr(),
703 checks.into(),
704 ctx.as_ptr(),
705 c_int::from(do_trial_division),
706 ptr::null_mut(),
707 ))
708 .map(|r| r != 0)
709 }
710 }
711
712 #[corresponds(BN_bn2bin)]
725 #[must_use]
726 pub fn to_vec(&self) -> Vec<u8> {
727 let size = self.num_bytes() as usize;
728 let mut v = Vec::with_capacity(size);
729 unsafe {
730 ffi::BN_bn2bin(self.as_ptr(), v.as_mut_ptr());
731 v.set_len(size);
732 }
733 v
734 }
735
736 pub fn to_vec_padded(&self, pad_to: usize) -> Result<Vec<u8>, ErrorStack> {
758 let mut v = Vec::with_capacity(pad_to);
759 unsafe {
760 cvt(ffi::BN_bn2bin_padded(v.as_mut_ptr(), pad_to, self.as_ptr()))?;
761 v.set_len(pad_to);
762 }
763 Ok(v)
764 }
765
766 #[corresponds(BN_bn2dec)]
775 pub fn to_dec_str(&self) -> Result<OpensslString, ErrorStack> {
776 unsafe {
777 let buf = cvt_p(ffi::BN_bn2dec(self.as_ptr()))?;
778 Ok(OpensslString::from_ptr(buf))
779 }
780 }
781
782 #[corresponds(BN_bn2hex)]
791 pub fn to_hex_str(&self) -> Result<OpensslString, ErrorStack> {
792 unsafe {
793 let buf = cvt_p(ffi::BN_bn2hex(self.as_ptr()))?;
794 Ok(OpensslString::from_ptr(buf))
795 }
796 }
797
798 #[corresponds(BN_to_ASN1_INTEGER)]
800 pub fn to_asn1_integer(&self) -> Result<Asn1Integer, ErrorStack> {
801 unsafe {
802 cvt_p(ffi::BN_to_ASN1_INTEGER(self.as_ptr(), ptr::null_mut()))
803 .map(|p| Asn1Integer::from_ptr(p))
804 }
805 }
806}
807
808impl BigNum {
809 #[corresponds(BN_new)]
811 pub fn new() -> Result<BigNum, ErrorStack> {
812 unsafe {
813 ffi::init();
814 let v = cvt_p(ffi::BN_new())?;
815 Ok(BigNum::from_ptr(v))
816 }
817 }
818
819 #[corresponds(BN_set_word)]
821 pub fn from_u32(n: u32) -> Result<BigNum, ErrorStack> {
822 BigNum::new().and_then(|v| unsafe {
823 cvt(ffi::BN_set_word(v.as_ptr(), ffi::BN_ULONG::from(n))).map(|_| v)
824 })
825 }
826
827 #[corresponds(BN_dec2bn)]
829 pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
830 unsafe {
831 ffi::init();
832 let c_str = CString::new(s.as_bytes()).map_err(ErrorStack::internal_error)?;
833 let mut bn = ptr::null_mut();
834 cvt(ffi::BN_dec2bn(&mut bn, c_str.as_ptr()))?;
835 Ok(BigNum::from_ptr(bn))
836 }
837 }
838
839 #[corresponds(BN_hex2bn)]
841 pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
842 unsafe {
843 ffi::init();
844 let c_str = CString::new(s.as_bytes()).unwrap();
845 let mut bn = ptr::null_mut();
846 cvt(ffi::BN_hex2bn(&mut bn, c_str.as_ptr()))?;
847 Ok(BigNum::from_ptr(bn))
848 }
849 }
850
851 #[corresponds(BN_bin2bn)]
864 pub fn from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
865 unsafe {
866 ffi::init();
867 assert!(n.len() <= c_int::MAX as usize);
868 cvt_p(ffi::BN_bin2bn(n.as_ptr(), n.len(), ptr::null_mut())).map(|p| BigNum::from_ptr(p))
869 }
870 }
871}
872
873impl fmt::Debug for BigNumRef {
874 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
875 match self.to_dec_str() {
876 Ok(s) => f.write_str(&s),
877 Err(e) => Err(e.into()),
878 }
879 }
880}
881
882impl fmt::Debug for BigNum {
883 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
884 match self.to_dec_str() {
885 Ok(s) => f.write_str(&s),
886 Err(e) => Err(e.into()),
887 }
888 }
889}
890
891impl fmt::Display for BigNumRef {
892 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
893 match self.to_dec_str() {
894 Ok(s) => f.write_str(&s),
895 Err(e) => Err(e.into()),
896 }
897 }
898}
899
900impl fmt::Display for BigNum {
901 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
902 match self.to_dec_str() {
903 Ok(s) => f.write_str(&s),
904 Err(e) => Err(e.into()),
905 }
906 }
907}
908
909impl PartialEq<BigNumRef> for BigNumRef {
910 fn eq(&self, oth: &BigNumRef) -> bool {
911 self.cmp(oth) == Ordering::Equal
912 }
913}
914
915impl PartialEq<BigNum> for BigNumRef {
916 fn eq(&self, oth: &BigNum) -> bool {
917 self.eq(&**oth)
918 }
919}
920
921impl Eq for BigNumRef {}
922
923impl PartialEq for BigNum {
924 fn eq(&self, oth: &BigNum) -> bool {
925 self.deref().eq(oth)
926 }
927}
928
929impl PartialEq<BigNumRef> for BigNum {
930 fn eq(&self, oth: &BigNumRef) -> bool {
931 self.deref().eq(oth)
932 }
933}
934
935impl Eq for BigNum {}
936
937impl PartialOrd<BigNumRef> for BigNumRef {
938 fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
939 Some(self.cmp(oth))
940 }
941}
942
943impl PartialOrd<BigNum> for BigNumRef {
944 fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
945 Some(self.cmp(&**oth))
946 }
947}
948
949impl Ord for BigNumRef {
950 fn cmp(&self, oth: &BigNumRef) -> Ordering {
951 unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
952 }
953}
954
955impl PartialOrd for BigNum {
956 fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
957 Some(self.cmp(oth))
958 }
959}
960
961impl PartialOrd<BigNumRef> for BigNum {
962 fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
963 self.deref().partial_cmp(oth)
964 }
965}
966
967impl Ord for BigNum {
968 fn cmp(&self, oth: &BigNum) -> Ordering {
969 self.deref().cmp(&**oth)
970 }
971}
972
973macro_rules! delegate {
974 ($t:ident, $m:ident) => {
975 impl<'a, 'b> $t<&'b BigNum> for &'a BigNumRef {
976 type Output = BigNum;
977
978 fn $m(self, oth: &BigNum) -> BigNum {
979 $t::$m(self, oth.deref())
980 }
981 }
982
983 impl<'a, 'b> $t<&'b BigNumRef> for &'a BigNum {
984 type Output = BigNum;
985
986 fn $m(self, oth: &BigNumRef) -> BigNum {
987 $t::$m(self.deref(), oth)
988 }
989 }
990
991 impl<'a, 'b> $t<&'b BigNum> for &'a BigNum {
992 type Output = BigNum;
993
994 fn $m(self, oth: &BigNum) -> BigNum {
995 $t::$m(self.deref(), oth.deref())
996 }
997 }
998 };
999}
1000
1001impl Add<&BigNumRef> for &BigNumRef {
1002 type Output = BigNum;
1003
1004 fn add(self, oth: &BigNumRef) -> BigNum {
1005 let mut r = BigNum::new().unwrap();
1006 r.checked_add(self, oth).unwrap();
1007 r
1008 }
1009}
1010
1011delegate!(Add, add);
1012
1013impl Sub<&BigNumRef> for &BigNumRef {
1014 type Output = BigNum;
1015
1016 fn sub(self, oth: &BigNumRef) -> BigNum {
1017 let mut r = BigNum::new().unwrap();
1018 r.checked_sub(self, oth).unwrap();
1019 r
1020 }
1021}
1022
1023delegate!(Sub, sub);
1024
1025impl Mul<&BigNumRef> for &BigNumRef {
1026 type Output = BigNum;
1027
1028 fn mul(self, oth: &BigNumRef) -> BigNum {
1029 let mut ctx = BigNumContext::new().unwrap();
1030 let mut r = BigNum::new().unwrap();
1031 r.checked_mul(self, oth, &mut ctx).unwrap();
1032 r
1033 }
1034}
1035
1036delegate!(Mul, mul);
1037
1038impl<'b> Div<&'b BigNumRef> for &BigNumRef {
1039 type Output = BigNum;
1040
1041 fn div(self, oth: &'b BigNumRef) -> BigNum {
1042 let mut ctx = BigNumContext::new().unwrap();
1043 let mut r = BigNum::new().unwrap();
1044 r.checked_div(self, oth, &mut ctx).unwrap();
1045 r
1046 }
1047}
1048
1049delegate!(Div, div);
1050
1051impl<'b> Rem<&'b BigNumRef> for &BigNumRef {
1052 type Output = BigNum;
1053
1054 fn rem(self, oth: &'b BigNumRef) -> BigNum {
1055 let mut ctx = BigNumContext::new().unwrap();
1056 let mut r = BigNum::new().unwrap();
1057 r.checked_rem(self, oth, &mut ctx).unwrap();
1058 r
1059 }
1060}
1061
1062delegate!(Rem, rem);
1063
1064impl Shl<i32> for &BigNumRef {
1065 type Output = BigNum;
1066
1067 fn shl(self, n: i32) -> BigNum {
1068 let mut r = BigNum::new().unwrap();
1069 r.lshift(self, n).unwrap();
1070 r
1071 }
1072}
1073
1074impl Shl<i32> for &BigNum {
1075 type Output = BigNum;
1076
1077 fn shl(self, n: i32) -> BigNum {
1078 self.deref().shl(n)
1079 }
1080}
1081
1082impl Shr<i32> for &BigNumRef {
1083 type Output = BigNum;
1084
1085 fn shr(self, n: i32) -> BigNum {
1086 let mut r = BigNum::new().unwrap();
1087 r.rshift(self, n).unwrap();
1088 r
1089 }
1090}
1091
1092impl Shr<i32> for &BigNum {
1093 type Output = BigNum;
1094
1095 fn shr(self, n: i32) -> BigNum {
1096 self.deref().shr(n)
1097 }
1098}
1099
1100impl Neg for &BigNumRef {
1101 type Output = BigNum;
1102
1103 fn neg(self) -> BigNum {
1104 self.to_owned().unwrap().neg()
1105 }
1106}
1107
1108impl Neg for &BigNum {
1109 type Output = BigNum;
1110
1111 fn neg(self) -> BigNum {
1112 self.deref().neg()
1113 }
1114}
1115
1116impl Neg for BigNum {
1117 type Output = BigNum;
1118
1119 fn neg(mut self) -> BigNum {
1120 let negative = self.is_negative();
1121 self.set_negative(!negative);
1122 self
1123 }
1124}
1125
1126#[cfg(test)]
1127mod tests {
1128 use crate::bn::{BigNum, BigNumContext};
1129
1130 #[test]
1131 fn test_to_from_slice() {
1132 let v0 = BigNum::from_u32(10_203_004).unwrap();
1133 let vec = v0.to_vec();
1134 let v1 = BigNum::from_slice(&vec).unwrap();
1135
1136 assert_eq!(v0, v1);
1137 }
1138
1139 #[test]
1140 fn test_negation() {
1141 let a = BigNum::from_u32(909_829_283).unwrap();
1142
1143 assert!(!a.is_negative());
1144 assert!((-a).is_negative());
1145 }
1146
1147 #[test]
1148 fn test_shift() {
1149 let a = BigNum::from_u32(909_829_283).unwrap();
1150
1151 assert_eq!(a, &(&a << 1) >> 1);
1152 }
1153
1154 #[test]
1155 fn test_rand_range() {
1156 let range = BigNum::from_u32(909_829_283).unwrap();
1157 let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap();
1158 range.rand_range(&mut result).unwrap();
1159 assert!(result >= BigNum::from_u32(0).unwrap() && result < range);
1160 }
1161
1162 #[test]
1163 fn test_pseudo_rand_range() {
1164 let range = BigNum::from_u32(909_829_283).unwrap();
1165 let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap();
1166 range.pseudo_rand_range(&mut result).unwrap();
1167 assert!(result >= BigNum::from_u32(0).unwrap() && result < range);
1168 }
1169
1170 #[test]
1171 fn test_prime_numbers() {
1172 let a = BigNum::from_u32(19_029_017).unwrap();
1173 let mut p = BigNum::new().unwrap();
1174 p.generate_prime(128, true, None, Some(&a)).unwrap();
1175
1176 let mut ctx = BigNumContext::new().unwrap();
1177 assert!(p.is_prime(100, &mut ctx).unwrap());
1178 assert!(p.is_prime_fasttest(100, &mut ctx, true).unwrap());
1179 }
1180}