1use std::{
5 fmt,
6 ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr},
7};
8
9use binius_utils::serialization::{DeserializeBytes, SerializationError, SerializeBytes};
10use bytemuck::{Pod, Zeroable};
11use bytes::{Buf, BufMut};
12
13#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Pod, Zeroable)]
19#[repr(transparent)]
20pub struct Word(pub u64);
21
22impl Word {
23 pub const ZERO: Word = Word(0);
25 pub const ONE: Word = Word(1);
27 pub const ALL_ONE: Word = Word(u64::MAX);
29 pub const MASK_32: Word = Word(0x00000000FFFFFFFF);
31 pub const MSB_ONE: Word = Word(0x8000000000000000);
35}
36
37impl fmt::Debug for Word {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "Word({:#018x})", self.0)
40 }
41}
42
43impl BitAnd for Word {
44 type Output = Self;
45
46 fn bitand(self, rhs: Self) -> Self::Output {
47 Word(self.0 & rhs.0)
48 }
49}
50
51impl BitOr for Word {
52 type Output = Self;
53
54 fn bitor(self, rhs: Self) -> Self::Output {
55 Word(self.0 | rhs.0)
56 }
57}
58
59impl BitXor for Word {
60 type Output = Self;
61
62 fn bitxor(self, rhs: Self) -> Self::Output {
63 Word(self.0 ^ rhs.0)
64 }
65}
66
67impl Shl<u32> for Word {
68 type Output = Self;
69
70 fn shl(self, rhs: u32) -> Self::Output {
71 Word(self.0 << rhs)
72 }
73}
74
75impl Shr<u32> for Word {
76 type Output = Self;
77
78 fn shr(self, rhs: u32) -> Self::Output {
79 Word(self.0 >> rhs)
80 }
81}
82
83impl Not for Word {
84 type Output = Self;
85
86 fn not(self) -> Self::Output {
87 Word(!self.0)
88 }
89}
90
91impl Word {
92 pub const fn from_u64(value: u64) -> Word {
94 Word(value)
95 }
96
97 pub const fn extract_bit(self, i: usize) -> bool {
101 (self.0 >> i) & 1 == 1
102 }
103
104 pub const fn iadd32_cin_cout(self, rhs: Word, cin: Word) -> (Word, Word) {
113 let Word(lhs) = self;
114 let Word(rhs) = rhs;
115 let Word(cin) = cin;
116
117 let cin_lo = (cin >> 31) & 1;
119 let cin_hi = (cin >> 63) & 1;
120
121 let lo_l = lhs as u32;
123 let hi_l = (lhs >> 32) as u32;
124 let lo_r = rhs as u32;
125 let hi_r = (rhs >> 32) as u32;
126
127 let lo_sum = (lo_l as u64) + (lo_r as u64) + cin_lo;
129 let hi_sum = (hi_l as u64) + (hi_r as u64) + cin_hi;
130 let sum = (lo_sum as u32 as u64) | ((hi_sum as u32 as u64) << 32);
131
132 let cout = (lhs & rhs) | ((lhs ^ rhs) & !sum);
133 (Word(sum), Word(cout))
134 }
135
136 pub const fn iadd_cout_32(self, rhs: Word) -> (Word, Word) {
140 self.iadd32_cin_cout(rhs, Word::ZERO)
141 }
142
143 pub fn iadd_cin_cout(self, rhs: Word, cin: Word) -> (Word, Word) {
151 debug_assert!(cin == Word::ZERO || cin == Word::ONE, "cin must be 0 or 1");
152 let Word(lhs) = self;
153 let Word(rhs) = rhs;
154 let Word(cin) = cin;
155 let sum = lhs.wrapping_add(rhs).wrapping_add(cin);
156 let cout = (lhs & rhs) | ((lhs ^ rhs) & !sum);
157 (Word(sum), Word(cout))
158 }
159
160 pub fn isub_bin_bout(self, rhs: Word, bin: Word) -> (Word, Word) {
168 debug_assert!(bin == Word::ZERO || bin == Word::ONE, "bin must be 0 or 1");
169 let Word(lhs) = self;
170 let Word(rhs) = rhs;
171 let Word(bin) = bin;
172 let diff = lhs.wrapping_sub(rhs).wrapping_sub(bin);
173 let bout = (!lhs & rhs) | (!(lhs ^ rhs) & diff);
174 (Word(diff), Word(bout))
175 }
176
177 pub const fn shr_32(self, n: u32) -> Word {
179 let Word(value) = self;
180 let result = (value >> n) & Self::MASK_32.0;
182 Word(result)
183 }
184
185 pub const fn sar(self, n: u32) -> Word {
189 let Word(value) = self;
190 let value = value as i64;
191 let result = value >> n;
192 Word(result as u64)
193 }
194
195 pub const fn rotr(self, n: u32) -> Word {
197 let Word(value) = self;
198 Word(value.rotate_right(n))
199 }
200
201 pub const fn sll32(self, n: u32) -> Word {
206 let Word(value) = self;
207 let n = n & 0x1F; let lo = value as u32;
211 let hi = (value >> 32) as u32;
212
213 let lo_shifted = (lo << n) as u64;
215 let hi_shifted = ((hi << n) as u64) << 32;
216
217 Word(lo_shifted | hi_shifted)
218 }
219
220 pub const fn srl32(self, n: u32) -> Word {
225 let Word(value) = self;
226 let n = n & 0x1F; let lo = value as u32;
230 let hi = (value >> 32) as u32;
231
232 let lo_shifted = (lo >> n) as u64;
234 let hi_shifted = ((hi >> n) as u64) << 32;
235
236 Word(lo_shifted | hi_shifted)
237 }
238
239 pub const fn sra32(self, n: u32) -> Word {
245 let Word(value) = self;
246 let n = n & 0x1F; let lo = value as u32 as i32;
250 let hi = (value >> 32) as u32 as i32;
251
252 let lo_shifted = ((lo >> n) as u32) as u64;
254 let hi_shifted = (((hi >> n) as u32) as u64) << 32;
255
256 Word(lo_shifted | hi_shifted)
257 }
258
259 pub const fn rotr32(self, n: u32) -> Word {
265 let Word(value) = self;
266 let n = n & 0x1F; let lo = value as u32;
270 let hi = (value >> 32) as u32;
271
272 let lo_rotated = lo.rotate_right(n) as u64;
274 let hi_rotated = (hi.rotate_right(n) as u64) << 32;
275
276 Word(lo_rotated | hi_rotated)
277 }
278
279 pub const fn imul(self, rhs: Word) -> (Word, Word) {
284 let Word(lhs) = self;
285 let Word(rhs) = rhs;
286 let result = (lhs as u128) * (rhs as u128);
287
288 let hi = (result >> 64) as u64;
289 let lo = result as u64;
290 (Word(hi), Word(lo))
291 }
292
293 pub const fn smul(self, rhs: Word) -> (Word, Word) {
298 let Word(lhs) = self;
299 let Word(rhs) = rhs;
300 let a = lhs as i64;
302 let b = rhs as i64;
303 let result = (a as i128) * (b as i128);
305 let hi = (result >> 64) as u64;
307 let lo = result as u64;
308 (Word(hi), Word(lo))
309 }
310
311 pub const fn wrapping_add(self, rhs: Word) -> Word {
315 Word(self.0.wrapping_add(rhs.0))
316 }
317
318 pub const fn wrapping_sub(self, rhs: Word) -> Word {
322 Word(self.0.wrapping_sub(rhs.0))
323 }
324
325 pub const fn as_u64(self) -> u64 {
327 self.0
328 }
329
330 pub const fn is_msb_true(self) -> bool {
337 (self.0 & Self::MSB_ONE.0) != 0
338 }
339
340 pub const fn is_msb_false(self) -> bool {
347 !self.is_msb_true()
348 }
349}
350
351impl SerializeBytes for Word {
352 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
353 self.0.serialize(write_buf)
354 }
355}
356
357impl DeserializeBytes for Word {
358 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
359 where
360 Self: Sized,
361 {
362 Ok(Word(u64::deserialize(read_buf)?))
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use proptest::prelude::*;
369 use rand::{Rng, SeedableRng, rngs::StdRng};
370
371 use super::*;
372
373 #[test]
374 fn test_constants() {
375 assert_eq!(Word::ZERO, Word(0));
376 assert_eq!(Word::ONE, Word(1));
377 assert_eq!(Word::ALL_ONE, Word(0xFFFFFFFFFFFFFFFF));
378 assert_eq!(Word::MASK_32, Word(0x00000000FFFFFFFF));
379 assert_eq!(Word::MSB_ONE, Word(0x8000000000000000));
380 }
381
382 #[test]
383 fn test_msb_bool() {
384 assert!(Word::MSB_ONE.is_msb_true());
386 assert!(!Word::MSB_ONE.is_msb_false());
387
388 assert!(!Word::ZERO.is_msb_true());
390 assert!(Word::ZERO.is_msb_false());
391
392 assert!(Word(0x8000000000000000).is_msb_true());
394 assert!(Word(0x8000000000000001).is_msb_true());
395 assert!(Word(0x80000000FFFFFFFF).is_msb_true());
396 assert!(Word(0xFFFFFFFFFFFFFFFF).is_msb_true());
397
398 assert!(Word(0x7FFFFFFFFFFFFFFF).is_msb_false());
400 assert!(Word(0x0000000000000001).is_msb_false());
401 assert!(Word(0x00000000FFFFFFFF).is_msb_false());
402 assert!(Word(0x7000000000000000).is_msb_false());
403
404 let test_word = Word(0x8123456789ABCDEF);
406 assert!(test_word.is_msb_true());
407 assert!(!test_word.is_msb_false());
408
409 let test_word2 = Word(0x7123456789ABCDEF);
410 assert!(!test_word2.is_msb_true());
411 assert!(test_word2.is_msb_false());
412 }
413
414 proptest! {
415 #[test]
416 fn prop_msb_bool(val in any::<u64>()) {
417 let word = Word(val);
418
419 assert_eq!(word.is_msb_true(), !word.is_msb_false());
421 assert_eq!(word.is_msb_false(), !word.is_msb_true());
422
423 let msb_set = (val & 0x8000000000000000) != 0;
425 assert_eq!(word.is_msb_true(), msb_set);
426 assert_eq!(word.is_msb_false(), !msb_set);
427
428 let word_with_msb = Word(val | 0x8000000000000000);
430 let word_without_msb = Word(val & 0x7FFFFFFFFFFFFFFF);
431 assert!(word_with_msb.is_msb_true());
432 assert!(word_without_msb.is_msb_false());
433 }
434
435 #[test]
436 fn prop_bitwise_and(a in any::<u64>(), b in any::<u64>()) {
437 let wa = Word(a);
438 let wb = Word(b);
439
440 assert_eq!((wa & wb).0, a & b);
442 assert_eq!(wa & Word::ALL_ONE, wa);
443 assert_eq!(wa & Word::ZERO, Word::ZERO);
444 assert_eq!(wa & wa, wa); assert_eq!(wa & wb, wb & wa);
448 }
449
450 #[test]
451 fn prop_bitwise_or(a in any::<u64>(), b in any::<u64>()) {
452 let wa = Word(a);
453 let wb = Word(b);
454
455 assert_eq!((wa | wb).0, a | b);
457 assert_eq!(wa | Word::ZERO, wa);
458 assert_eq!(wa | Word::ALL_ONE, Word::ALL_ONE);
459 assert_eq!(wa | wa, wa); assert_eq!(wa | wb, wb | wa);
463 }
464
465 #[test]
466 fn prop_bitwise_xor(a in any::<u64>(), b in any::<u64>()) {
467 let wa = Word(a);
468 let wb = Word(b);
469
470 assert_eq!((wa ^ wb).0, a ^ b);
472 assert_eq!(wa ^ Word::ZERO, wa);
473 assert_eq!(wa ^ wa, Word::ZERO);
474 assert_eq!(wa ^ Word::ALL_ONE, !wa);
475
476 assert_eq!(wa ^ wb, wb ^ wa);
478
479 assert_eq!(wa ^ wb ^ wb, wa);
481 }
482
483 #[test]
484 fn prop_bitwise_not(a in any::<u64>()) {
485 let wa = Word(a);
486
487 assert_eq!((!wa).0, !a);
489 assert_eq!(!(!wa), wa); assert_eq!(!Word::ZERO, Word::ALL_ONE);
491 assert_eq!(!Word::ALL_ONE, Word::ZERO);
492
493 let wb = Word(a.wrapping_add(1));
495 assert_eq!(!(wa & wb), !wa | !wb);
496 assert_eq!(!(wa | wb), !wa & !wb);
497 }
498
499 #[test]
500 fn prop_shift_left(val in any::<u64>(), shift in 0u32..64) {
501 let w = Word(val);
502 assert_eq!((w << shift).0, val << shift);
503
504 assert_eq!(w << 0, w);
506
507 if shift >= 64 {
509 assert_eq!((w << shift).0, 0);
510 }
511 }
512
513 #[test]
514 fn prop_shift_right(val in any::<u64>(), shift in 0u32..64) {
515 let w = Word(val);
516 assert_eq!((w >> shift).0, val >> shift);
517
518 assert_eq!(w >> 0, w);
520
521 if shift >= 64 {
523 assert_eq!((w >> shift).0, 0);
524 }
525 }
526
527 #[test]
528 fn prop_shift_inverse(val in any::<u64>(), shift in 1u32..64) {
529 let w = Word(val);
530 let mask = (1u64 << (64 - shift)) - 1;
532 assert_eq!(((w << shift) >> shift).0, val & mask);
533
534 let high_mask = !((1u64 << shift) - 1);
536 assert_eq!(((w >> shift) << shift).0, val & high_mask);
537 }
538
539 #[test]
540 fn prop_sar(val in any::<u64>(), shift in 0u32..64) {
541 let w = Word(val);
542 let expected = ((val as i64) >> shift) as u64;
543 assert_eq!(w.sar(shift).0, expected);
544
545 assert_eq!(w.sar(0), w);
547
548 let sign_extended = if (val as i64) < 0 {
550 Word(0xFFFFFFFFFFFFFFFF)
551 } else {
552 Word(0)
553 };
554 assert_eq!(w.sar(63), sign_extended);
555 }
556
557 #[test]
558 fn prop_sar_sign_extension(val in any::<u64>(), shift in 1u32..64) {
559 let w = Word(val);
560 let result = w.sar(shift);
561
562 let is_negative = (val as i64) < 0;
564 if is_negative {
565 let mask = !((1u64 << (64 - shift)) - 1);
567 assert_eq!(result.0 & mask, mask);
568 } else {
569 let mask = !((1u64 << (64 - shift)) - 1);
571 assert_eq!(result.0 & mask, 0);
572 }
573 }
574
575 #[test]
576 fn prop_iadd32_cin_cout(
577 a in any::<u64>(), b in any::<u64>(),
578 cin_lo in proptest::bool::ANY, cin_hi in proptest::bool::ANY,
579 ) {
580 let cin_word = ((cin_lo as u64) << 31) | ((cin_hi as u64) << 63);
582 let wa = Word(a);
583 let wb = Word(b);
584 let wcin = Word(cin_word);
585 let (sum, cout) = wa.iadd32_cin_cout(wb, wcin);
586
587 let lo_sum = (a as u32 as u64) + (b as u32 as u64) + (cin_lo as u64);
589 let hi_sum = ((a >> 32) as u32 as u64) + ((b >> 32) as u32 as u64) + (cin_hi as u64);
590 let expected_sum = (lo_sum as u32 as u64) | ((hi_sum as u32 as u64) << 32);
591 assert_eq!(sum.0, expected_sum);
592
593 let expected_cout = (a & b) | ((a ^ b) & !expected_sum);
595 assert_eq!(cout.0, expected_cout);
596
597 let (sum0, cout0) = wa.iadd_cout_32(wb);
599 let (sum1, cout1) = wa.iadd32_cin_cout(wb, Word::ZERO);
600 assert_eq!(sum0, sum1);
601 assert_eq!(cout0, cout1);
602 }
603
604 #[test]
605 fn prop_iadd_cin_cout(a in any::<u64>(), b in any::<u64>(), cin in 0u64..=1) {
606 let wa = Word(a);
607 let wb = Word(b);
608 let wcin = Word(cin);
609 let (sum, cout) = wa.iadd_cin_cout(wb, wcin);
610
611 let expected_sum = a.wrapping_add(b).wrapping_add(cin);
613 assert_eq!(sum.0, expected_sum);
614
615 let expected_cout = (a & b) | ((a ^ b) & !expected_sum);
617 assert_eq!(cout.0, expected_cout);
618
619 let (sum0, cout0) = wa.iadd_cin_cout(wb, Word::ZERO);
621 let full_sum = a.wrapping_add(b);
622 assert_eq!(sum0.0, full_sum);
623 assert_eq!(cout0.0, (a & b) | ((a ^ b) & !full_sum));
624 }
625
626 #[test]
627 fn prop_isub_bin_bout(a in any::<u64>(), b in any::<u64>(), bin in 0u64..=1) {
628 let wa = Word(a);
629 let wb = Word(b);
630 let wbin = Word(bin);
631 let (diff, bout) = wa.isub_bin_bout(wb, wbin);
632
633 let expected_diff = a.wrapping_sub(b).wrapping_sub(bin);
635 assert_eq!(diff.0, expected_diff);
636
637 let expected_bout = (!a & b) | (!(a ^ b) & expected_diff);
639 assert_eq!(bout.0, expected_bout);
640
641 let (diff0, bout0) = wa.isub_bin_bout(wb, Word::ZERO);
643 let expected = a.wrapping_sub(b);
644 assert_eq!(diff0.0, expected);
645 assert_eq!(bout0.0, (!a & b) | (!(a ^ b) & expected));
646 }
647
648 #[test]
649 fn prop_shr_32(val in any::<u64>(), shift in 0u32..64) {
650 let w = Word(val);
651 let result = w.shr_32(shift);
652
653 let expected = (val >> shift) & 0xFFFFFFFF;
655 assert_eq!(result.0, expected);
656
657 assert_eq!(w.shr_32(0).0, val & 0xFFFFFFFF);
659
660 if shift >= 32 {
662 assert_eq!(result.0, (val >> shift) & 0xFFFFFFFF);
663 }
664 }
665 #[test]
666 fn prop_rotr(val in any::<u64>(), rotate in 0u32..128) {
667 let w = Word(val);
668 let result = w.rotr(rotate);
669
670 let rotate_mod = rotate % 64;
672 let expected = val.rotate_right(rotate_mod);
673 assert_eq!(result.0, expected);
674
675 assert_eq!(w.rotr(0), w);
677 assert_eq!(w.rotr(64), w);
678
679 let r1 = rotate % 64;
681 let r2 = (64 - r1) % 64;
682 if r1 != 0 {
683 assert_eq!(w.rotr(r1).rotr(r2), w);
684 }
685 }
686
687 #[test]
688 fn prop_imul(a in any::<u64>(), b in any::<u64>()) {
689 let wa = Word(a);
690 let wb = Word(b);
691 let (hi, lo) = wa.imul(wb);
692
693 let result = (a as u128) * (b as u128);
695 assert_eq!(hi.0, (result >> 64) as u64);
696 assert_eq!(lo.0, result as u64);
697
698 let (hi0, lo0) = wa.imul(Word::ZERO);
700 assert_eq!(hi0, Word::ZERO);
701 assert_eq!(lo0, Word::ZERO);
702
703 let (hi1, lo1) = wa.imul(Word::ONE);
705 assert_eq!(hi1, Word::ZERO);
706 assert_eq!(lo1, wa);
707
708 let (hi_ab, lo_ab) = wa.imul(wb);
710 let (hi_reversed, lo_reversed) = wb.imul(wa);
711 assert_eq!(hi_ab, hi_reversed);
712 assert_eq!(lo_ab, lo_reversed);
713 }
714
715 #[test]
716 fn prop_sll32(val in any::<u64>(), shift in 0u32..32) {
717 let w = Word(val);
718 let result = w.sll32(shift);
719
720 let lo = val as u32;
722 let hi = (val >> 32) as u32;
723
724 let expected_lo = ((lo << shift) as u64) & 0xFFFFFFFF;
726 let expected_hi = ((hi << shift) as u64) << 32;
727 let expected = expected_lo | expected_hi;
728
729 assert_eq!(result.0, expected);
730
731 assert_eq!(w.sll32(0), w);
733
734 let w_test = Word(0x40000001_40000001);
736 let result_31 = w_test.sll32(31);
737 assert_eq!(result_31.0, 0x80000000_80000000);
738
739 assert_eq!(w.sll32(shift), w.sll32(shift | 0x20));
741 }
742
743 #[test]
744 fn prop_srl32(val in any::<u64>(), shift in 0u32..32) {
745 let w = Word(val);
746 let result = w.srl32(shift);
747
748 let lo = val as u32;
750 let hi = (val >> 32) as u32;
751
752 let expected_lo = (lo >> shift) as u64;
754 let expected_hi = ((hi >> shift) as u64) << 32;
755 let expected = expected_lo | expected_hi;
756
757 assert_eq!(result.0, expected);
758
759 assert_eq!(w.srl32(0), w);
761
762 let w_test = Word(0x80000000_80000000);
764 let result_31 = w_test.srl32(31);
765 assert_eq!(result_31.0, 0x00000001_00000001);
766
767 assert_eq!(w.srl32(shift), w.srl32(shift | 0x20));
769 }
770
771 #[test]
772 fn prop_sra32(val in any::<u64>(), shift in 0u32..32) {
773 let w = Word(val);
774 let result = w.sra32(shift);
775
776 let lo = val as u32 as i32;
778 let hi = (val >> 32) as u32 as i32;
779
780 let expected_lo = ((lo >> shift) as u32) as u64;
782 let expected_hi = (((hi >> shift) as u32) as u64) << 32;
783 let expected = expected_lo | expected_hi;
784
785 assert_eq!(result.0, expected);
786
787 assert_eq!(w.sra32(0), w);
789
790 let w_neg = Word(0x80000000_80000000);
792 let result_1 = w_neg.sra32(1);
793 assert_eq!(result_1.0, 0xC0000000_C0000000);
794
795 let w_pos = Word(0x40000000_40000000);
797 let result_1_pos = w_pos.sra32(1);
798 assert_eq!(result_1_pos.0, 0x20000000_20000000);
799
800 let result_31 = w.sra32(31);
802 let expected_lo_31 = if lo < 0 { 0xFFFFFFFF } else { 0 };
803 let expected_hi_31 = if hi < 0 { 0xFFFFFFFF00000000 } else { 0 };
804 assert_eq!(result_31.0, expected_lo_31 | expected_hi_31);
805
806 assert_eq!(w.sra32(shift), w.sra32(shift | 0x20));
808 }
809
810 #[test]
811 fn prop_rotr32(val in any::<u64>(), rotate in 0u32..32) {
812 let w = Word(val);
813 let result = w.rotr32(rotate);
814
815 let lo = val as u32;
817 let hi = (val >> 32) as u32;
818
819 let expected_lo = lo.rotate_right(rotate) as u64;
821 let expected_hi = ((hi.rotate_right(rotate)) as u64) << 32;
822 let expected = expected_lo | expected_hi;
823
824 assert_eq!(result.0, expected);
825
826 assert_eq!(w.rotr32(0), w);
828
829 assert_eq!(w.rotr32(32), w.rotr32(0));
831
832 assert_eq!(w.rotr32(rotate), w.rotr32(rotate | 0x20));
834
835 if rotate > 0 && rotate < 32 {
837 let w_test = Word(0x12345678_9ABCDEF0);
838 let rotated = w_test.rotr32(rotate);
839 let back = rotated.rotr32(32 - rotate);
840 assert_eq!(back, w_test);
841 }
842 }
843
844 #[test]
845 fn prop_smul(a in any::<u64>(), b in any::<u64>()) {
846 let wa = Word(a);
847 let wb = Word(b);
848 let (hi, lo) = wa.smul(wb);
849
850 let result = (a as i64 as i128) * (b as i64 as i128);
852 assert_eq!(hi.0, (result >> 64) as u64);
853 assert_eq!(lo.0, result as u64);
854
855 let (hi0, lo0) = wa.smul(Word::ZERO);
857 assert_eq!(hi0, Word::ZERO);
858 assert_eq!(lo0, Word::ZERO);
859
860 let (hi1, lo1) = wa.smul(Word::ONE);
862 let expected_hi = if (a as i64) < 0 { Word(0xFFFFFFFFFFFFFFFF) } else { Word::ZERO };
863 assert_eq!(hi1, expected_hi);
864 assert_eq!(lo1, wa);
865
866 let (hi_neg, lo_neg) = wa.smul(Word(0xFFFFFFFFFFFFFFFF));
868 let neg_result = -(a as i64 as i128);
869 assert_eq!(hi_neg.0, (neg_result >> 64) as u64);
870 assert_eq!(lo_neg.0, neg_result as u64);
871
872 let (hi_ab, lo_ab) = wa.smul(wb);
874 let (hi_reversed, lo_reversed) = wb.smul(wa);
875 assert_eq!(hi_ab, hi_reversed);
876 assert_eq!(lo_ab, lo_reversed);
877 }
878
879 #[test]
880 fn prop_wrapping_sub(a in any::<u64>(), b in any::<u64>()) {
881 let wa = Word(a);
882 let wb = Word(b);
883 let result = wa.wrapping_sub(wb);
884
885 assert_eq!(result.0, a.wrapping_sub(b));
886
887 assert_eq!(wa.wrapping_sub(Word::ZERO), wa);
889
890 assert_eq!(wa.wrapping_sub(wa), Word::ZERO);
892
893 let sum = Word(a.wrapping_add(b));
895 assert_eq!(sum.wrapping_sub(wb), wa);
896 }
897
898 #[test]
899 fn prop_conversions(val in any::<u64>()) {
900 let word = Word::from_u64(val);
901 assert_eq!(word.as_u64(), val);
902 assert_eq!(word, Word(val));
903
904 assert_eq!(Word::from_u64(word.as_u64()), word);
906 }
907
908 #[test]
909 fn prop_debug_format(val in any::<u64>()) {
910 let word = Word(val);
911 let debug_str = format!("{:?}", word);
912 assert!(debug_str.starts_with("Word(0x"));
913 assert!(debug_str.ends_with(")"));
914 let expected = format!("Word({:#018x})", val);
916 assert_eq!(debug_str, expected);
917 }
918 }
919
920 #[test]
921 fn test_32bit_shift_edge_cases() {
922 let w1 = Word(0x12345678_9ABCDEF0);
924 assert_eq!(w1.sll32(4).0, 0x23456780_ABCDEF00);
925 assert_eq!(w1.sll32(16).0, 0x56780000_DEF00000);
926
927 let w2 = Word(0xFFFFFFFF_00000000);
929 assert_eq!(w2.sll32(1).0, 0xFFFFFFFE_00000000);
930 let w3 = Word(0x00000000_FFFFFFFF);
931 assert_eq!(w3.sll32(1).0, 0x00000000_FFFFFFFE);
932
933 assert_eq!(w1.srl32(4).0, 0x01234567_09ABCDEF);
935 assert_eq!(w1.srl32(16).0, 0x00001234_00009ABC);
936
937 let w4 = Word(0x80000000_7FFFFFFF); assert_eq!(w4.sra32(1).0, 0xC0000000_3FFFFFFF);
940 assert_eq!(w4.sra32(31).0, 0xFFFFFFFF_00000000);
941
942 let w5 = Word(0x7FFFFFFF_80000000); assert_eq!(w5.sra32(1).0, 0x3FFFFFFF_C0000000);
944 assert_eq!(w5.sra32(31).0, 0x00000000_FFFFFFFF);
945
946 let all_ones = Word(0xFFFFFFFF_FFFFFFFF);
948 assert_eq!(all_ones.sll32(1).0, 0xFFFFFFFE_FFFFFFFE);
949 assert_eq!(all_ones.srl32(1).0, 0x7FFFFFFF_7FFFFFFF);
950 assert_eq!(all_ones.sra32(1).0, 0xFFFFFFFF_FFFFFFFF);
951
952 let alternating = Word(0xAAAAAAAA_55555555);
953 assert_eq!(alternating.sll32(1).0, 0x55555554_AAAAAAAA);
954 assert_eq!(alternating.srl32(1).0, 0x55555555_2AAAAAAA);
955 assert_eq!(alternating.sra32(1).0, 0xD5555555_2AAAAAAA);
956
957 assert_eq!(w1.sll32(0), w1);
959 assert_eq!(w1.srl32(0), w1);
960 assert_eq!(w1.sra32(0), w1);
961
962 let w6 = Word(0x00000001_00000000);
964 assert_eq!(w6.sll32(31).0, 0x80000000_00000000);
965 assert_eq!(w6.srl32(1).0, 0x00000000_00000000);
966
967 let w7 = Word(0x80000001_80000001);
969 assert_eq!(w7.rotr32(1).0, 0xC0000000_C0000000);
970 assert_eq!(w7.rotr32(31).0, 0x00000003_00000003);
971
972 let w8 = Word(0x12345678_9ABCDEF0);
974 assert_eq!(w8.rotr32(4).0, 0x81234567_09ABCDEF);
975 assert_eq!(w8.rotr32(16).0, 0x56781234_DEF09ABC);
976
977 let w9 = Word(0xFFFF0000_0000FFFF);
979 assert_eq!(w9.rotr32(16).0, 0x0000FFFF_FFFF0000);
980
981 assert_eq!(w8.rotr32(0), w8);
983 }
984
985 #[test]
986 fn test_word_serialization_round_trip() {
987 let mut rng = StdRng::seed_from_u64(0);
988 let word = Word::from_u64(rng.next_u64());
989
990 let mut buf = Vec::new();
991 word.serialize(&mut buf).unwrap();
992
993 let deserialized = Word::deserialize(&mut buf.as_slice()).unwrap();
994 assert_eq!(word, deserialized);
995 }
996}