1use super::int::BigInt;
42use super::uint::BigUint;
43use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, Shr};
44use oxinum_core::Sign;
45
46fn to_twos_complement(n: &BigInt, nlimbs: usize) -> Vec<u64> {
57 let mag = n.magnitude().as_limbs();
58 let mut out = vec![0u64; nlimbs];
59 let copy_len = mag.len().min(nlimbs);
61 out[..copy_len].copy_from_slice(&mag[..copy_len]);
62
63 if n.is_negative() {
64 for limb in out.iter_mut() {
66 *limb = !*limb;
67 }
68 let mut carry: u64 = 1;
70 for limb in out.iter_mut() {
71 let (v, c) = limb.overflowing_add(carry);
72 *limb = v;
73 carry = c as u64;
74 if carry == 0 {
75 break;
76 }
77 }
78 }
83 out
84}
85
86fn from_twos_complement(limbs: &[u64]) -> BigInt {
92 if limbs.is_empty() {
93 return BigInt::zero();
94 }
95 let top = limbs[limbs.len() - 1];
96 if top >> 63 == 0 {
97 BigInt::from_parts(Sign::Positive, BigUint::from_le_limbs(limbs))
99 } else {
100 let mut neg: Vec<u64> = limbs.to_vec();
102 for v in neg.iter_mut() {
103 *v = !*v;
104 }
105 let mut carry: u64 = 1;
106 for v in neg.iter_mut() {
107 let (nv, c) = v.overflowing_add(carry);
108 *v = nv;
109 carry = c as u64;
110 if carry == 0 {
111 break;
112 }
113 }
114 BigInt::from_parts(Sign::Negative, BigUint::from_le_limbs(&neg))
115 }
116}
117
118#[inline]
124fn bigint_binop<F>(lhs: &BigInt, rhs: &BigInt, op: F) -> BigInt
125where
126 F: Fn(u64, u64) -> u64,
127{
128 let llen = lhs.magnitude().as_limbs().len();
129 let rlen = rhs.magnitude().as_limbs().len();
130 let nlimbs = llen.max(rlen) + 1;
132 let ltc = to_twos_complement(lhs, nlimbs);
133 let rtc = to_twos_complement(rhs, nlimbs);
134 let result: Vec<u64> = ltc
135 .iter()
136 .zip(rtc.iter())
137 .map(|(&a, &b)| op(a, b))
138 .collect();
139 from_twos_complement(&result)
140}
141
142impl BitAnd<&BigInt> for &BigInt {
147 type Output = BigInt;
148 #[inline]
149 fn bitand(self, rhs: &BigInt) -> BigInt {
150 bigint_binop(self, rhs, |a, b| a & b)
151 }
152}
153
154impl BitAnd<BigInt> for BigInt {
155 type Output = BigInt;
156 #[inline]
157 fn bitand(self, rhs: BigInt) -> BigInt {
158 bigint_binop(&self, &rhs, |a, b| a & b)
159 }
160}
161
162impl BitAnd<&BigInt> for BigInt {
163 type Output = BigInt;
164 #[inline]
165 fn bitand(self, rhs: &BigInt) -> BigInt {
166 bigint_binop(&self, rhs, |a, b| a & b)
167 }
168}
169
170impl BitAnd<BigInt> for &BigInt {
171 type Output = BigInt;
172 #[inline]
173 fn bitand(self, rhs: BigInt) -> BigInt {
174 bigint_binop(self, &rhs, |a, b| a & b)
175 }
176}
177
178impl BitOr<&BigInt> for &BigInt {
183 type Output = BigInt;
184 #[inline]
185 fn bitor(self, rhs: &BigInt) -> BigInt {
186 bigint_binop(self, rhs, |a, b| a | b)
187 }
188}
189
190impl BitOr<BigInt> for BigInt {
191 type Output = BigInt;
192 #[inline]
193 fn bitor(self, rhs: BigInt) -> BigInt {
194 bigint_binop(&self, &rhs, |a, b| a | b)
195 }
196}
197
198impl BitOr<&BigInt> for BigInt {
199 type Output = BigInt;
200 #[inline]
201 fn bitor(self, rhs: &BigInt) -> BigInt {
202 bigint_binop(&self, rhs, |a, b| a | b)
203 }
204}
205
206impl BitOr<BigInt> for &BigInt {
207 type Output = BigInt;
208 #[inline]
209 fn bitor(self, rhs: BigInt) -> BigInt {
210 bigint_binop(self, &rhs, |a, b| a | b)
211 }
212}
213
214impl BitXor<&BigInt> for &BigInt {
219 type Output = BigInt;
220 #[inline]
221 fn bitxor(self, rhs: &BigInt) -> BigInt {
222 bigint_binop(self, rhs, |a, b| a ^ b)
223 }
224}
225
226impl BitXor<BigInt> for BigInt {
227 type Output = BigInt;
228 #[inline]
229 fn bitxor(self, rhs: BigInt) -> BigInt {
230 bigint_binop(&self, &rhs, |a, b| a ^ b)
231 }
232}
233
234impl BitXor<&BigInt> for BigInt {
235 type Output = BigInt;
236 #[inline]
237 fn bitxor(self, rhs: &BigInt) -> BigInt {
238 bigint_binop(&self, rhs, |a, b| a ^ b)
239 }
240}
241
242impl BitXor<BigInt> for &BigInt {
243 type Output = BigInt;
244 #[inline]
245 fn bitxor(self, rhs: BigInt) -> BigInt {
246 bigint_binop(self, &rhs, |a, b| a ^ b)
247 }
248}
249
250impl Not for BigInt {
255 type Output = BigInt;
256
257 fn not(self) -> BigInt {
258 if self.is_negative() {
259 let m = self.magnitude().clone();
261 let one = BigUint::one();
262 match m.checked_sub(&one) {
263 Some(result) => BigInt::from_parts(Sign::Positive, result),
264 None => BigInt::zero(),
266 }
267 } else {
268 let mag_plus_one = self.magnitude() + &BigUint::one();
270 BigInt::from_parts(Sign::Negative, mag_plus_one)
271 }
272 }
273}
274
275impl Not for &BigInt {
276 type Output = BigInt;
277
278 #[inline]
279 fn not(self) -> BigInt {
280 self.clone().not()
281 }
282}
283
284impl Shl<u64> for BigInt {
289 type Output = BigInt;
290
291 fn shl(self, k: u64) -> BigInt {
292 if self.is_zero() || k == 0 {
293 return self;
294 }
295 let sign = self.sign();
296 let shifted_mag = self.magnitude().shl_bits(k);
297 BigInt::from_parts(sign, shifted_mag)
298 }
299}
300
301impl Shl<u64> for &BigInt {
302 type Output = BigInt;
303
304 #[inline]
305 fn shl(self, k: u64) -> BigInt {
306 self.clone().shl(k)
307 }
308}
309
310impl Shr<u64> for BigInt {
318 type Output = BigInt;
319
320 fn shr(self, k: u64) -> BigInt {
321 if k == 0 {
322 return self;
323 }
324 if self.is_negative() {
325 let m = self.magnitude().clone();
326 let m_minus_one = m.checked_sub(&BigUint::one()).unwrap_or_else(BigUint::zero);
328 let shifted = m_minus_one.shr_bits(k);
329 let mag = &shifted + &BigUint::one();
331 BigInt::from_parts(Sign::Negative, mag)
332 } else {
333 BigInt::from_parts(Sign::Positive, self.magnitude().shr_bits(k))
335 }
336 }
337}
338
339impl Shr<u64> for &BigInt {
340 type Output = BigInt;
341
342 #[inline]
343 fn shr(self, k: u64) -> BigInt {
344 self.clone().shr(k)
345 }
346}
347
348#[cfg(test)]
353mod tests {
354 use super::*;
355
356 fn bi(v: i64) -> BigInt {
357 BigInt::from(v)
358 }
359
360 fn bu(v: u64) -> BigUint {
361 BigUint::from_u64(v)
362 }
363
364 #[test]
365 fn not_basic() {
366 assert_eq!(!bi(0), bi(-1));
367 assert_eq!(!bi(5), bi(-6));
368 assert_eq!(!bi(-1), bi(0));
369 assert_eq!(!bi(-6), bi(5));
370 }
371
372 #[test]
373 fn not_double_negation() {
374 for v in [-1000i64, -1, 0, 1, 1000] {
375 let n = bi(v);
376 assert_eq!(!!n.clone(), n, "!!n == n failed for {v}");
377 }
378 }
379
380 #[test]
381 fn and_neg_one_with_ff() {
382 let neg1 = bi(-1);
384 let ff = bi(0xFF);
385 assert_eq!(&neg1 & &ff, ff);
386 }
387
388 #[test]
389 fn or_neg_one_is_neg_one() {
390 let neg1 = bi(-1);
391 let ff = bi(0xFF);
392 assert_eq!(&neg1 | &ff, neg1);
393 }
394
395 #[test]
396 fn xor_self_is_zero() {
397 let neg1 = bi(-1);
398 assert_eq!(&neg1 ^ &neg1, BigInt::zero());
399 let x = bi(-12345);
400 assert_eq!(&x ^ &x, BigInt::zero());
401 }
402
403 #[test]
404 fn shr_negative_floor_div() {
405 assert_eq!(bi(-8) >> 1u64, bi(-4));
406 assert_eq!(bi(-7) >> 1u64, bi(-4));
407 assert_eq!(bi(-1) >> 1u64, bi(-1));
408 assert_eq!(bi(-1) >> 100u64, bi(-1));
409 assert_eq!(bi(7) >> 1u64, bi(3));
410 }
411
412 #[test]
413 fn shl_signed() {
414 assert_eq!(bi(1) << 4u64, bi(16));
415 assert_eq!(bi(-1) << 4u64, bi(-16));
416 assert_eq!(bi(0) << 100u64, BigInt::zero());
417 }
418
419 #[test]
420 fn to_twos_complement_positive() {
421 let n = bi(5);
422 let tc = to_twos_complement(&n, 2);
423 assert_eq!(tc, vec![5, 0]);
424 }
425
426 #[test]
427 fn to_twos_complement_negative_one() {
428 let n = bi(-1);
429 let tc = to_twos_complement(&n, 2);
430 assert_eq!(tc, vec![u64::MAX, u64::MAX]);
432 }
433
434 #[test]
435 fn from_twos_complement_roundtrip() {
436 for v in [-1i128, -2, -128, 0, 1, 127, 1000] {
437 let n = BigInt::from(v);
438 let tc = to_twos_complement(&n, 4);
439 let back = from_twos_complement(&tc);
440 assert_eq!(back, n, "roundtrip failed for {v}");
441 }
442 }
443
444 #[test]
445 fn de_morgan_and_to_or() {
446 let pairs: &[(i64, i64)] = &[
448 (0, 0),
449 (5, 3),
450 (-5, 3),
451 (5, -3),
452 (-5, -3),
453 (-1, 0xFF),
454 (i64::MAX, i64::MIN),
455 ];
456 for &(av, bv) in pairs {
457 let a = bi(av);
458 let b = bi(bv);
459 let lhs = !(&a & &b);
460 let rhs = !a.clone() | !b.clone();
461 assert_eq!(lhs, rhs, "De Morgan failed for ({av}, {bv})");
462 }
463 }
464
465 #[test]
466 fn de_morgan_or_to_and() {
467 let pairs: &[(i64, i64)] = &[(0, 0), (5, 3), (-5, 3), (5, -3), (-5, -3), (-1, 0xFF)];
469 for &(av, bv) in pairs {
470 let a = bi(av);
471 let b = bi(bv);
472 let lhs = !(&a | &b);
473 let rhs = !a.clone() & !b.clone();
474 assert_eq!(lhs, rhs, "De Morgan (or→and) failed for ({av}, {bv})");
475 }
476 }
477
478 #[test]
479 fn i128_cross_val_bitwise_and_shifts() {
480 let vals: &[i128] = &[
481 0,
482 1,
483 -1,
484 127,
485 -128,
486 1000,
487 -1000,
488 i64::MAX as i128,
489 i64::MIN as i128,
490 ];
491 for &i in vals {
492 let a = BigInt::from(i);
493 assert_eq!(!a.clone(), BigInt::from(!i), "!{i} mismatch");
495 for j in 0i128..20 {
497 let b = BigInt::from(j);
498 assert_eq!(&a & &b, BigInt::from(i & j), "{i} & {j} mismatch");
499 assert_eq!(&a | &b, BigInt::from(i | j), "{i} | {j} mismatch");
500 assert_eq!(&a ^ &b, BigInt::from(i ^ j), "{i} ^ {j} mismatch");
501 assert_eq!(
502 a.clone() >> (j as u64),
503 BigInt::from(i >> j),
504 "{i} >> {j} mismatch"
505 );
506 }
507 for &j in vals {
508 assert_eq!(
509 &a & &BigInt::from(j),
510 BigInt::from(i & j),
511 "{i} & {j} mismatch"
512 );
513 assert_eq!(
514 &a | &BigInt::from(j),
515 BigInt::from(i | j),
516 "{i} | {j} mismatch"
517 );
518 assert_eq!(
519 &a ^ &BigInt::from(j),
520 BigInt::from(i ^ j),
521 "{i} ^ {j} mismatch"
522 );
523 }
524 }
525 }
526
527 #[test]
528 fn xor_identity_and_complement() {
529 for v in [-5i64, -1, 0, 1, 5] {
531 let n = bi(v);
532 assert_eq!(&n ^ &BigInt::zero(), n.clone());
533 assert_eq!(&n ^ &n, BigInt::zero());
535 let all_ones = bi(-1);
537 assert_eq!(&n ^ &all_ones, !n.clone());
538 }
539 }
540
541 #[test]
542 fn shr_positive_matches_biguint_shr() {
543 let mag = BigUint::from_u64(1234567890);
544 let n = BigInt::from_parts(Sign::Positive, mag.clone());
545 for k in [0u64, 1, 7, 15, 31, 63, 64, 65] {
546 let expected = BigInt::from_parts(Sign::Positive, mag.shr_bits(k));
547 assert_eq!(n.clone() >> k, expected, "positive shr mismatch for k={k}");
548 }
549 }
550
551 #[test]
552 fn bu_unused() {
553 assert_eq!(bu(42), BigUint::from_u64(42));
556 }
557}
558
559impl BitAndAssign<BigUint> for BigUint {
568 #[inline]
569 fn bitand_assign(&mut self, rhs: BigUint) {
570 *self = &*self & &rhs;
571 }
572}
573
574impl BitAndAssign<&BigUint> for BigUint {
575 #[inline]
576 fn bitand_assign(&mut self, rhs: &BigUint) {
577 *self = &*self & rhs;
578 }
579}
580
581impl BitOrAssign<BigUint> for BigUint {
582 #[inline]
583 fn bitor_assign(&mut self, rhs: BigUint) {
584 *self = &*self | &rhs;
585 }
586}
587
588impl BitOrAssign<&BigUint> for BigUint {
589 #[inline]
590 fn bitor_assign(&mut self, rhs: &BigUint) {
591 *self = &*self | rhs;
592 }
593}
594
595impl BitXorAssign<BigUint> for BigUint {
596 #[inline]
597 fn bitxor_assign(&mut self, rhs: BigUint) {
598 *self = &*self ^ &rhs;
599 }
600}
601
602impl BitXorAssign<&BigUint> for BigUint {
603 #[inline]
604 fn bitxor_assign(&mut self, rhs: &BigUint) {
605 *self = &*self ^ rhs;
606 }
607}
608
609#[cfg(test)]
614mod biguint_bitwise_tests {
615 use super::*;
616
617 fn bu(v: u64) -> BigUint {
618 BigUint::from_u64(v)
619 }
620
621 #[test]
624 fn and_basic() {
625 assert_eq!(&bu(0b1100) & &bu(0b1010), bu(0b1000));
626 assert_eq!(&bu(0xFF) & &bu(0x0F), bu(0x0F));
627 assert_eq!(&bu(0) & &bu(0xFF), bu(0));
628 }
629
630 #[test]
631 fn and_zero_identity() {
632 let x = bu(0xDEAD_BEEF);
633 assert_eq!(&x & &bu(0), bu(0), "a & 0 == 0");
634 }
635
636 #[test]
637 fn and_self_identity() {
638 let x = bu(0xDEAD_BEEF);
639 assert_eq!(&x & &x, x.clone(), "a & a == a");
640 }
641
642 #[test]
643 fn and_unequal_limbs() {
644 let mut limbs_a = vec![0xFFFF_FFFF_FFFF_FFFFu64, 0xFFFF_FFFF_FFFF_FFFFu64];
647 let limbs_b = vec![0xAAAA_AAAA_AAAA_AAAAu64];
648 let a = BigUint::from_le_limbs(&limbs_a);
649 let b = BigUint::from_le_limbs(&limbs_b);
650 let result = &a & &b;
651 assert_eq!(result, BigUint::from_le_limbs(&limbs_b));
652 limbs_a[1] = 0;
654 let a2 = BigUint::from_le_limbs(&limbs_a);
655 let result2 = &a2 & &b;
656 assert_eq!(result2, BigUint::from_le_limbs(&limbs_b));
657 }
658
659 #[test]
660 fn and_assign() {
661 let mut x = bu(0b1111);
662 x &= bu(0b1010);
663 assert_eq!(x, bu(0b1010));
664 }
665
666 #[test]
669 fn or_basic() {
670 assert_eq!(&bu(0b1100) | &bu(0b1010), bu(0b1110));
671 assert_eq!(&bu(0xF0) | &bu(0x0F), bu(0xFF));
672 }
673
674 #[test]
675 fn or_zero_identity() {
676 let x = bu(0xDEAD_BEEF);
677 assert_eq!(&x | &bu(0), x.clone(), "a | 0 == a");
678 }
679
680 #[test]
681 fn or_self_identity() {
682 let x = bu(0xDEAD_BEEF);
683 assert_eq!(&x | &x, x.clone(), "a | a == a");
684 }
685
686 #[test]
687 fn or_unequal_limbs() {
688 let limbs_a = vec![0x1111_1111_1111_1111u64, 0x2222_2222_2222_2222u64];
689 let limbs_b = vec![0x4444_4444_4444_4444u64];
690 let a = BigUint::from_le_limbs(&limbs_a);
691 let b = BigUint::from_le_limbs(&limbs_b);
692 let result = &a | &b;
693 let expected = BigUint::from_le_limbs(&[
695 0x1111_1111_1111_1111u64 | 0x4444_4444_4444_4444u64,
696 0x2222_2222_2222_2222u64,
697 ]);
698 assert_eq!(result, expected);
699 }
700
701 #[test]
702 fn or_assign() {
703 let mut x = bu(0b1010);
704 x |= bu(0b0101);
705 assert_eq!(x, bu(0b1111));
706 }
707
708 #[test]
711 fn xor_basic() {
712 assert_eq!(&bu(0b1100) ^ &bu(0b1010), bu(0b0110));
713 assert_eq!(&bu(0xFF) ^ &bu(0x0F), bu(0xF0));
714 }
715
716 #[test]
717 fn xor_self_is_zero() {
718 let x = bu(0xDEAD_BEEF_CAFE_BABEu64);
719 assert_eq!(&x ^ &x, bu(0), "a ^ a == 0");
720 }
721
722 #[test]
723 fn xor_zero_identity() {
724 let x = bu(0xDEAD_BEEF);
725 assert_eq!(&x ^ &bu(0), x.clone(), "a ^ 0 == a");
726 }
727
728 #[test]
729 fn xor_unequal_limbs() {
730 let limbs_a = vec![0xFFFF_FFFF_FFFF_FFFFu64, 0xFFFF_FFFF_FFFF_FFFFu64];
731 let limbs_b = vec![0xFFFF_FFFF_FFFF_FFFFu64];
732 let a = BigUint::from_le_limbs(&limbs_a);
733 let b = BigUint::from_le_limbs(&limbs_b);
734 let result = &a ^ &b;
735 let expected = BigUint::from_le_limbs(&[0u64, 0xFFFF_FFFF_FFFF_FFFFu64]);
737 assert_eq!(result, expected);
738 }
739
740 #[test]
741 fn xor_double_is_identity() {
742 let a = BigUint::from_le_limbs(&[0xDEAD_BEEF, 0xCAFE_BABE, 0x1234_5678]);
744 let b = BigUint::from_le_limbs(&[0x1111_2222, 0x3333_4444]);
745 let c = &(&a ^ &b) ^ &b;
746 assert_eq!(c, a);
747 }
748
749 #[test]
750 fn xor_normalization() {
751 let big = BigUint::from_le_limbs(&[
753 0xAAAA_BBBB_CCCC_DDDDu64,
754 0xEEEE_FFFF_0000_1111u64,
755 0x2222_3333_4444_5555u64,
756 ]);
757 let result: BigUint = &big ^ &big;
758 assert_eq!(result, BigUint::zero());
759 assert!(result.is_zero());
760 }
761
762 #[test]
763 fn xor_assign() {
764 let mut x = bu(0b1111);
765 x ^= bu(0b1010);
766 assert_eq!(x, bu(0b0101));
767 }
768
769 #[test]
772 fn owned_ops() {
773 let a = bu(0b1110);
774 let b = bu(0b1011);
775 assert_eq!(a.clone() & b.clone(), bu(0b1010));
776 assert_eq!(a.clone() | b.clone(), bu(0b1111));
777 assert_eq!(a.clone() ^ b.clone(), bu(0b0101));
778 }
779}