1pub mod inner;
2
3mod fp_wrapper;
4mod impl_fqslice;
5mod impl_fqslicemut;
6mod impl_fqvector;
7mod iter;
8
9pub use fp_wrapper::*;
10#[cfg(feature = "proptest")]
11pub use impl_fqvector::arbitrary;
12pub use inner::*;
13
14#[cfg(test)]
15pub(super) mod tests {
16 use itertools::Itertools;
17 use proptest::prelude::*;
18
19 use super::{arbitrary::MAX_LEN as MAX_TEST_VEC_LEN, inner::FqVector};
20 use crate::{
21 field::{Field, element::FieldElement, fp::F2},
22 limb,
23 };
24
25 pub struct VectorDiffEntry<F: Field> {
26 pub index: usize,
27 pub left: FieldElement<F>,
28 pub right: FieldElement<F>,
29 }
30
31 impl<F: Field> FqVector<F> {
32 pub fn diff_list(&self, other: &[FieldElement<F>]) -> Vec<VectorDiffEntry<F>> {
33 assert!(self.len() == other.len());
34 let mut result = Vec::new();
35 #[allow(clippy::needless_range_loop)]
36 for index in 0..self.len() {
37 let left = self.entry(index);
38 let right = other[index].clone();
39 if left != right {
40 result.push(VectorDiffEntry { index, left, right });
41 }
42 }
43 result
44 }
45
46 pub fn diff_vec(&self, other: &Self) -> Vec<VectorDiffEntry<F>> {
47 assert!(self.len() == other.len());
48 let mut result = Vec::new();
49 for index in 0..self.len() {
50 let left = self.entry(index);
51 let right = other.entry(index);
52 if left != right {
53 result.push(VectorDiffEntry { index, left, right });
54 }
55 }
56 result
57 }
58
59 pub fn format_diff(diff: Vec<VectorDiffEntry<F>>) -> String {
60 let data_formatter =
61 diff.iter()
62 .format_with("\n ", |VectorDiffEntry { index, left, right }, f| {
63 f(&format_args!(" At index {index}: {left}!={right}"))
64 });
65 format!("{data_formatter}")
66 }
67
68 pub fn assert_list_eq(&self, other: &[FieldElement<F>]) {
69 let diff = self.diff_list(other);
70 if diff.is_empty() {
71 return;
72 }
73 panic!(
74 "assert {} == {:?}\n{}",
75 self,
76 other,
77 Self::format_diff(diff)
78 );
79 }
80
81 pub fn assert_vec_eq(&self, other: &Self) {
82 let diff = self.diff_vec(other);
83 if diff.is_empty() {
84 return;
85 }
86 panic!(
87 "assert {} == {:?}\n{}",
88 self,
89 other,
90 Self::format_diff(diff)
91 );
92 }
93 }
94
95 fn arb_field_dim<F: Field>() -> impl Strategy<Value = (F, usize)> {
97 (any::<F>(), 0..=MAX_TEST_VEC_LEN)
98 }
99
100 fn arb_slice(dimension: usize) -> impl Strategy<Value = (usize, usize)> {
102 (0..=dimension).prop_flat_map(move |first| (Just(first), first..=dimension))
103 }
104
105 prop_compose! {
106 fn arb_slice_pair(dimension: usize)
108 (len in 0..=dimension)
109 (len in Just(len), first in 0..=dimension - len, second in 0..=dimension - len)
110 -> [(usize, usize); 2]
111 {
112 [(first, first + len), (second, second + len)]
113 }
114 }
115
116 fn arb_element_vec<F: Field>(
120 fq: F,
121 dimension: usize,
122 ) -> impl Strategy<Value = Vec<FieldElement<F>>> {
123 proptest::collection::vec(fq.arb_element(), dimension)
124 }
125
126 pub fn arb_vec<F: Field>() -> impl Strategy<Value = (F, Vec<FieldElement<F>>)> {
129 arb_field_dim().prop_flat_map(|(fq, dim)| (Just(fq), arb_element_vec(fq, dim)))
130 }
131
132 fn arb_vec_and_slice<F: Field>()
134 -> impl Strategy<Value = (F, Vec<FieldElement<F>>, (usize, usize))> {
135 arb_field_dim()
136 .prop_flat_map(|(fq, dim)| (Just(fq), arb_element_vec(fq, dim), arb_slice(dim)))
137 }
138
139 fn arb_vec_pair<F: Field>()
141 -> impl Strategy<Value = (F, Vec<FieldElement<F>>, Vec<FieldElement<F>>)> {
142 arb_field_dim().prop_flat_map(|(fq, dim)| {
143 (Just(fq), arb_element_vec(fq, dim), arb_element_vec(fq, dim))
144 })
145 }
146
147 fn arb_vec_pair_and_slice<F: Field>() -> impl Strategy<
149 Value = (
150 F,
151 Vec<FieldElement<F>>,
152 Vec<FieldElement<F>>,
153 (usize, usize),
154 ),
155 > {
156 arb_field_dim().prop_flat_map(|(fq, dim)| {
157 (
158 Just(fq),
159 arb_element_vec(fq, dim),
160 arb_element_vec(fq, dim),
161 arb_slice(dim),
162 )
163 })
164 }
165
166 fn arb_vec_pair_and_mask<F: Field>()
169 -> impl Strategy<Value = (F, Vec<FieldElement<F>>, Vec<FieldElement<F>>, Vec<usize>)> {
170 any::<F>()
171 .prop_flat_map(|fq| (Just(fq), arb_slice(MAX_TEST_VEC_LEN)))
172 .prop_flat_map(|(fq, (dim_small, dim_large))| {
173 (
174 Just(fq),
175 arb_element_vec(fq, dim_small),
176 arb_element_vec(fq, dim_large),
177 proptest::collection::vec(0..dim_large, dim_small),
178 )
179 })
180 }
181
182 macro_rules! vector_tests {
183 ($field:ty) => {
184 proptest! {
185 #![proptest_config(ProptestConfig {
186 max_shrink_time: 30_000,
187 max_shrink_iters: 1_000_000,
188 .. ProptestConfig::default()
189 })]
190
191 #[test]
195 fn test_incompatible_fields_assign((fq1, fq2) in (any::<$field>(), any::<$field>())) {
196 if fq1 != fq2 {
197 let panic = std::panic::catch_unwind(|| {
198 FqVector::new(fq1, 10).assign(&FqVector::new(fq2, 10))
199 });
200 prop_assert!(panic.is_err());
201 }
202 }
203
204 #[test]
205 fn test_incompatible_fields_assign_partial((fq1, fq2) in (any::<$field>(), any::<$field>())) {
206 if fq1 != fq2 {
207 let panic = std::panic::catch_unwind(|| {
208 FqVector::new(fq1, 10).assign_partial(&FqVector::new(fq2, 10))
209 });
210 prop_assert!(panic.is_err());
211 }
212 }
213
214 #[test]
215 fn test_incompatible_fields_add((fq1, fq2) in (any::<$field>(), any::<$field>())) {
216 if fq1 != fq2 {
217 let panic = std::panic::catch_unwind(|| {
218 FqVector::new(fq1, 10).add(&FqVector::new(fq2, 10), fq2.one())
219 });
220 prop_assert!(panic.is_err());
221 }
222 }
223
224 #[test]
225 fn test_incompatible_fields_add_offset((fq1, fq2) in (any::<$field>(), any::<$field>())) {
226 if fq1 != fq2 {
227 let panic = std::panic::catch_unwind(|| {
228 FqVector::new(fq1, 10).add_offset(&FqVector::new(fq2, 10), fq2.one(), 5)
229 });
230 prop_assert!(panic.is_err());
231 }
232 }
233
234 #[test]
235 fn test_incompatible_fields_add_truncate((fq1, fq2) in (any::<$field>(), any::<$field>())) {
236 if fq1 != fq2 {
237 let panic = std::panic::catch_unwind(|| {
238 FqVector::new(fq1, 10).add_truncate(&FqVector::new(fq2, 10), fq2.one())
239 });
240 prop_assert!(panic.is_err());
241 }
242 }
243
244 #[test]
245 fn test_incompatible_fields_sign_rule((fq1, fq2) in (any::<$field>(), any::<$field>())) {
246 if fq1 != fq2 {
247 let panic = std::panic::catch_unwind(|| {
248 FqVector::new(fq1, 10).sign_rule(&FqVector::new(fq2, 10))
249 });
250 prop_assert!(panic.is_err());
251 }
252 }
253
254 #[test]
255 fn test_incompatible_fields_add_carry((fq1, fq2) in (any::<$field>(), any::<$field>())) {
256 if fq1 != fq2 {
257 let panic = std::panic::catch_unwind(|| {
258 FqVector::new(fq1, 10).add_carry::<FqVector<_>>(&FqVector::new(fq2, 10), fq2.one(), &mut [])
259 });
260 prop_assert!(panic.is_err());
261 }
262 }
263
264 #[test]
265 fn test_serialize((fq, v_arr) in arb_vec::<$field>()) {
266 use std::io::{Seek, Cursor};
267
268 let v = FqVector::from_slice(fq, &v_arr);
269
270 let mut cursor = Cursor::new(Vec::<u8>::new());
271 v.to_bytes(&mut cursor).unwrap();
272 cursor.rewind().unwrap();
273
274 let w = FqVector::from_bytes(v.fq(), v.len(), &mut cursor).unwrap();
275 v.assert_vec_eq(&w);
276 }
277
278 #[test]
279 fn test_add((fq, mut v_arr, w_arr) in arb_vec_pair::<$field>()) {
280 let mut v = FqVector::from_slice(fq, &v_arr);
281 let w = FqVector::from_slice(fq, &w_arr);
282
283 v.add(&w, fq.one());
284
285 for (v_element, w_element) in v_arr.iter_mut().zip(w_arr.iter()) {
286 *v_element += *w_element;
287 }
288 v.assert_list_eq(&v_arr);
289 }
290
291 #[test]
292 fn test_add_offset((fq, mut v_arr, w_arr, (slice_start, slice_end), offset) in
293 arb_field_dim::<$field>().prop_flat_map(|(fq, dim)| {
294 (Just(fq), arb_element_vec(fq, dim), arb_element_vec(fq, dim), arb_slice(dim), any::<prop::sample::Index>())
295 })
296 ) {
297 let mut v = FqVector::from_slice(fq, &v_arr);
298 let w = FqVector::from_slice(fq, &w_arr);
299
300 let mut v_slice = v.slice_mut(slice_start, slice_end);
301 let w_slice = w.slice(slice_start, slice_end);
302
303 let slice_len = w_slice.len();
304 let real_offset = if slice_len > 0 { offset.index(slice_len) } else { 0 };
305
306 v_slice.add_offset(w_slice, fq.one(), real_offset);
307
308 for (v_element, w_element) in v_arr.iter_mut()
309 .zip(w_arr.iter())
310 .skip(slice_start)
311 .take(slice_len)
312 .skip(real_offset)
313 {
314 *v_element += *w_element;
315 }
316 v.assert_list_eq(&v_arr);
317 }
318
319 #[test]
320 fn test_scale((fq, mut v_arr, c) in arb_field_dim::<$field>().prop_flat_map(|(fq, dim)| {
321 (Just(fq), arb_element_vec(fq, dim), fq.arb_element())
322 })) {
323 let mut v = FqVector::from_slice(fq, &v_arr);
324 v.scale(c);
325 for entry in &mut v_arr {
326 *entry *= c;
327 }
328 v.assert_list_eq(&v_arr);
329 }
330
331 #[test]
332 fn test_scale_slice((fq, mut v_arr, (slice_start, slice_end), c) in
333 arb_field_dim::<$field>().prop_flat_map(|(fq, dim)| {
334 (Just(fq), arb_element_vec(fq, dim), arb_slice(dim), fq.arb_element())
335 })
336 ) {
337 let mut v = FqVector::from_slice(fq, &v_arr);
338 v.slice_mut(slice_start, slice_end).scale(c);
339
340 for entry in &mut v_arr[slice_start..slice_end] {
341 *entry *= c;
342 }
343 v.assert_list_eq(&v_arr);
344 }
345
346 #[test]
347 fn test_entry((fq, v_arr) in arb_vec::<$field>()) {
348 let v = FqVector::from_slice(fq, &v_arr);
349
350 let mut diffs = Vec::new();
351 for (i, val) in v.iter().enumerate() {
352 if v.entry(i) != val {
353 diffs.push((i, val, v.entry(i)));
354 }
355 }
356 prop_assert_eq!(diffs, []);
357 }
358
359 #[test]
360 fn test_entry_slice((fq, v_arr, (slice_start, slice_end)) in arb_vec_and_slice::<$field>()) {
361 let v = FqVector::from_slice(fq, &v_arr);
362 let v = v.slice(slice_start, slice_end);
363 println!(
364 "slice_start: {slice_start}, slice_end: {slice_end}, slice: {v}"
365 );
366
367 let mut diffs = Vec::new();
368 for i in 0..v.len() {
369 if v.entry(i) != v_arr[i + slice_start] {
370 diffs.push((i, v_arr[i + slice_start], v.entry(i)));
371 }
372 }
373 prop_assert_eq!(diffs, []);
374 }
375
376 #[test]
377 fn test_set_entry((fq, v_arr) in arb_vec::<$field>()) {
378 let mut v = FqVector::new(fq, v_arr.len());
379
380 for (i, &val) in v_arr.iter().enumerate() {
381 v.set_entry(i, val);
382 }
383 v.assert_list_eq(&v_arr);
384 }
385
386 #[test]
387 fn test_set_entry_slice((fq, v_arr, (slice_start, slice_end)) in arb_vec_and_slice::<$field>()) {
388 let dim = v_arr.len();
389 let mut v = FqVector::new(fq, dim);
390 let mut v = v.slice_mut(slice_start, slice_end);
391
392 let v_slice = &v_arr[slice_start..slice_end];
393 for (i, &val) in v_slice.iter().enumerate() {
394 v.set_entry(i, val);
395 }
396 let v = v.as_slice();
397
398 let mut diffs = Vec::new();
399 for (i, &val) in v_slice.iter().enumerate() {
400 if v.entry(i) != val {
401 diffs.push((i, val, v.entry(i)));
402 }
403 }
404 prop_assert_eq!(diffs, []);
405 }
406
407 #[test]
408 fn test_set_to_zero_slice((fq, mut v_arr, (slice_start, slice_end)) in arb_vec_and_slice::<$field>()) {
409 println!("slice_start : {slice_start}, slice_end : {slice_end}");
410 let mut v = FqVector::from_slice(fq, &v_arr);
411
412 v.slice_mut(slice_start, slice_end).set_to_zero();
413 prop_assert!(v.slice(slice_start, slice_end).is_zero());
414
415 for entry in &mut v_arr[slice_start..slice_end] {
416 *entry = fq.zero();
417 }
418 v.assert_list_eq(&v_arr);
419 }
420
421 #[test]
422 fn test_add_slice_to_slice((fq, mut v_arr, w_arr, (slice_start, slice_end)) in arb_vec_pair_and_slice::<$field>()) {
423 let mut v = FqVector::from_slice(fq, &v_arr);
424 let w = FqVector::from_slice(fq, &w_arr);
425
426 v.slice_mut(slice_start, slice_end)
427 .add(w.slice(slice_start, slice_end), fq.one());
428
429 for i in slice_start..slice_end {
430 v_arr[i] += w_arr[i];
431 }
432 v.assert_list_eq(&v_arr);
433 }
434
435 #[test]
436 fn test_assign((fq, v_arr, w_arr) in arb_vec_pair::<$field>()) {
437 let mut v = FqVector::from_slice(fq, &v_arr);
438 let w = FqVector::from_slice(fq, &w_arr);
439
440 v.assign(&w);
441 v.assert_vec_eq(&w);
442 }
443
444 #[test]
445 fn test_assign_partial((fq, v_arr, w_arr) in arb_vec_pair::<$field>()) {
446 let dim = v_arr.len();
447 let mut v = FqVector::from_slice(fq, &v_arr);
448 let w = FqVector::from_slice(fq, &w_arr[0..(dim / 2)]);
449
450 v.assign_partial(&w);
451 prop_assert!(v.slice(dim / 2, dim).is_zero());
452 prop_assert_eq!(v.len(), dim);
453 v.slice(0, dim / 2).to_owned().assert_vec_eq(&w);
454 }
455
456 #[test]
457 fn test_assign_slice_to_slice((fq, mut v_arr, w_arr, (slice_start, slice_end)) in arb_vec_pair_and_slice::<$field>()) {
458 let mut v = FqVector::from_slice(fq, &v_arr);
459 let w = FqVector::from_slice(fq, &w_arr);
460
461 v.slice_mut(slice_start, slice_end)
462 .assign(w.slice(slice_start, slice_end));
463 v_arr[slice_start..slice_end].clone_from_slice(&w_arr[slice_start..slice_end]);
464 v.assert_list_eq(&v_arr);
465 }
466
467 #[test]
468 fn test_add_shift((fq, mut v_arr, w_arr, [(slice1_start, slice1_end), (slice2_start, slice2_end)])
469 in arb_field_dim::<$field>().prop_flat_map(|(fq, dim)| {
470 (
471 Just(fq),
472 arb_element_vec(fq, dim),
473 arb_element_vec(fq, dim),
474 arb_slice_pair(dim),
475 )
476 })
477 ) {
478 let mut v = FqVector::from_slice(fq, &v_arr);
479 let w = FqVector::from_slice(fq, &w_arr);
480
481 v.slice_mut(slice1_start, slice1_end)
482 .add(w.slice(slice2_start, slice2_end), fq.one());
483
484 for (v_element, w_element) in v_arr[slice1_start..slice1_end]
485 .iter_mut()
486 .zip(w_arr[slice2_start..slice2_end].iter())
487 {
488 *v_element += *w_element;
489 }
490 v.assert_list_eq(&v_arr);
491 }
492
493 #[test]
494 fn test_add_masked((fq, mut v_small, v_big, mask) in arb_vec_pair_and_mask::<$field>()) {
495 let mut v = FqVector::from_slice(fq, &v_small);
496 let w = FqVector::from_slice(fq, &v_big);
497
498 v.as_slice_mut().add_masked(w.as_slice(), fq.one(), &mask);
499
500 for (i, x) in v_small.iter_mut().enumerate() {
501 *x += v_big[mask[i]];
502 }
503
504 v.assert_list_eq(&v_small);
505 }
506
507 #[test]
508 fn test_add_unmasked((fq, v_small, mut v_big, mask) in arb_vec_pair_and_mask::<$field>()) {
509 let mut v = FqVector::from_slice(fq, &v_big);
510 let w = FqVector::from_slice(fq, &v_small);
511
512 v.as_slice_mut().add_unmasked(w.as_slice(), fq.one(), &mask);
513 for (i, &x) in v_small.iter().enumerate() {
514 v_big[mask[i]] += x;
515 }
516 v.assert_list_eq(&v_big);
517 }
518
519 #[test]
520 fn test_iterator_slice((p, v_arr, (slice_start, slice_end)) in arb_vec_and_slice::<$field>()) {
521 let v = FqVector::from_slice(p, &v_arr);
522 let v = v.slice(slice_start, slice_end);
523
524 let w = v.iter();
525 let mut counter = 0;
526 for (i, x) in w.enumerate() {
527 prop_assert_eq!(v.entry(i), x);
528 counter += 1;
529 }
530 prop_assert_eq!(counter, v.len());
531 }
532
533 #[test]
534 fn test_iterator_skip((p, v_arr, num_skip) in arb_field_dim::<$field>().prop_flat_map(|(p, dim)| {
535 (Just(p), arb_element_vec(p, dim), 0..=dim)
536 })) {
537 let v = FqVector::from_slice(p, &v_arr);
538
539 let mut w = v.iter();
540 w.skip_n(num_skip);
541 let mut counter = 0;
542 for (i, x) in w.enumerate() {
543 prop_assert_eq!(v.entry(i + num_skip), x);
544 counter += 1;
545 }
546
547 prop_assert_eq!(counter, v.len() - num_skip);
548 }
549
550 #[test]
551 fn test_iterator((p, v_arr) in arb_vec::<$field>()) {
552 let v = FqVector::from_slice(p, &v_arr);
553
554 let w = v.iter();
555 let mut counter = 0;
556 for (i, x) in w.enumerate() {
557 prop_assert_eq!(v.entry(i), x);
558 counter += 1;
559 }
560 prop_assert_eq!(counter, v.len());
561 }
562
563 #[test]
564 fn test_iter_nonzero_empty((p, dimension) in arb_field_dim::<$field>()) {
565 let v = FqVector::new(p, dimension);
566 prop_assert_eq!(v.iter_nonzero().next(), None);
567 }
568
569 #[test]
570 fn test_iter_nonzero((fq, v_arr, (slice_start, slice_end)) in arb_vec_and_slice::<$field>()) {
571 use std::fmt::Write;
572
573 let v = FqVector::from_slice(fq, &v_arr);
574
575 println!("v: {v}");
576 println!("v_arr: {v_arr:?}");
577 let result: Vec<_> = v.slice(slice_start, slice_end).iter_nonzero().collect();
578 let comparison_result: Vec<_> = v_arr[slice_start..slice_end]
579 .iter()
580 .copied()
581 .enumerate()
582 .filter(|&(_, x)| x != fq.zero())
583 .collect();
584
585 let mut i = 0;
586 let mut j = 0;
587 let mut diffs_str = String::new();
588 while i < result.len() && j < comparison_result.len() {
589 if result[i] != comparison_result[j] {
590 if result[i].0 < comparison_result[j].0 {
591 let _ = write!(
592 diffs_str,
593 "\n({:?}) present in result, missing from comparison_result",
594 result[i]
595 );
596 i += 1;
597 } else {
598 let _ = write!(
599 diffs_str,
600 "\n({:?}) present in comparison_result, missing from result",
601 comparison_result[j]
602 );
603 j += 1;
604 }
605 } else {
606 i += 1;
607 j += 1;
608 }
609 }
610 prop_assert!(diffs_str.is_empty(), "{}", diffs_str);
614 }
615 }
616};
617 }
618
619 macro_rules! test_prime {
622 ($fq:tt, $p:tt) => {
623 paste::paste! {
624 mod [<$p:lower>] {
625 use super::*;
626 use crate::prime::$p;
627
628 vector_tests!($fq<$p>);
629 }
630 }
631 };
632 }
633
634 macro_rules! test_field {
638 ($fq:tt) => {
639 paste::paste! {
640 mod [<$fq:lower>] {
641 use super::*;
642 use crate::field::[<$fq:lower>]::$fq;
643
644 test_prime!($fq, ValidPrime);
645 test_prime!($fq, P2);
646 cfg_if::cfg_if! { if #[cfg(feature = "odd-primes")] {
647 test_prime!($fq, P3);
648 test_prime!($fq, P5);
649 test_prime!($fq, P7);
650 }}
651 }
652 }
653 };
654 }
655
656 test_field!(Fp);
657 test_field!(SmallFq);
658
659 #[test]
660 fn test_sign_rule_limb() {
661 assert!(limb::sign_rule(1, 0b10) == 1);
662 assert!(limb::sign_rule(0b10, 1) == 0);
663 assert!(limb::sign_rule(0x84012c02, 0x6b920241) == 1);
664 assert!(limb::sign_rule(0x6b920241, 0x84012c02) == 0);
665 }
666
667 #[test]
668 #[ignore]
669 fn test_sign_rule() {
670 let mut in1 = FqVector::new(F2, 128);
671 let mut in2 = FqVector::new(F2, 128);
672 let tests = [
673 (
674 0x181e20846a820820,
675 0x2122a1a08c1a0069,
676 0xe30140608100e540,
677 0xd2180e4350008004,
678 false,
679 false,
680 ),
681 (
682 0x2090400020017044,
683 0xa04e0802080000e1,
684 0x18298a0a85080089,
685 0x050020311030411a,
686 false,
687 false,
688 ),
689 (
690 0x082080022408d510,
691 0x538a000802078210,
692 0x2355308c4a920002,
693 0x00058130800000a2,
694 true,
695 true,
696 ),
697 (
698 0x33a0824922050704,
699 0x00400520a0800404,
700 0x00090836000a980b,
701 0x4801d005064b9840,
702 false,
703 false,
704 ),
705 (
706 0x290c14040154a01b,
707 0x38014102810a0245,
708 0x0093281a620a1060,
709 0x029014cd0684080a,
710 true,
711 true,
712 ),
713 (
714 0x240255b490b0e040,
715 0x0815414130548881,
716 0x8ad4880a00000416,
717 0xb660a4b84cab002c,
718 true,
719 true,
720 ),
721 (
722 0x010c000060840540,
723 0x8008001480104028,
724 0x8842938396233a31,
725 0x5e20400311059a41,
726 true,
727 true,
728 ),
729 (
730 0x02012141008e5081,
731 0x2829060241920a00,
732 0xe0208a1a47102310,
733 0x051240010e6c4008,
734 false,
735 false,
736 ),
737 (
738 0x200812011081880f,
739 0x100661c082625864,
740 0x48840c76c03a2380,
741 0x861088274000060a,
742 false,
743 false,
744 ),
745 (
746 0x84000f5490449008,
747 0x00891820f4623401,
748 0x107490a964b802a4,
749 0x40024487008800b0,
750 false,
751 false,
752 ),
753 (
754 0x080448a2db282c41,
755 0x2c100011e00097dd,
756 0x0131024124844028,
757 0x8329600202440002,
758 false,
759 false,
760 ),
761 (
762 0x441c60a208c2e206,
763 0x00a4210b50049281,
764 0x0842020160091158,
765 0x48131424846a6868,
766 true,
767 true,
768 ),
769 (
770 0xc2743ad490a21411,
771 0x0150221280868050,
772 0x1082402043040888,
773 0xdc070000021128a0,
774 true,
775 true,
776 ),
777 (
778 0x0614030849072140,
779 0x0e7a710422002540,
780 0x300904418240c422,
781 0x80850ccad8a10200,
782 false,
783 true,
784 ),
785 (
786 0x90080028402bc624,
787 0x215002cf204840a0,
788 0x6373f01012001042,
789 0x420b111008350859,
790 false,
791 true,
792 ),
793 (
794 0x4220c41100513301,
795 0x332c050498c21102,
796 0x0c0c206c8a008044,
797 0xc0024840461484d0,
798 true,
799 false,
800 ),
801 (
802 0x0353a04b08000010,
803 0x3e00045295202851,
804 0x60040810a42a1284,
805 0x001d680860800080,
806 true,
807 false,
808 ),
809 (
810 0x084801c0c2100581,
811 0x1820090035001080,
812 0x3111121b0522185c,
813 0x01404209002c080c,
814 true,
815 false,
816 ),
817 (
818 0x414800000823a20e,
819 0x008074081080a214,
820 0x1a12852095d040c0,
821 0x8119003425575408,
822 false,
823 true,
824 ),
825 (
826 0x210c730112098440,
827 0x01c0b106111483d0,
828 0x920004486810020c,
829 0xb614405084c30004,
830 true,
831 true,
832 ),
833 (
834 0x60210168b8802094,
835 0x2a10021a4b08420c,
836 0x1554000102241028,
837 0x04048d0000349000,
838 true,
839 true,
840 ),
841 (
842 0x81200240041188c8,
843 0x148008c1c6220818,
844 0x0082a92c10000010,
845 0x0050500800100084,
846 true,
847 false,
848 ),
849 (
850 0x4593105c94090408,
851 0x820029daa0026830,
852 0x1864242101429200,
853 0x1822060103290348,
854 true,
855 false,
856 ),
857 (
858 0x551a0002870e6000,
859 0x0040a00040353a00,
860 0x200409c110101589,
861 0x28870e620a488442,
862 true,
863 false,
864 ),
865 (
866 0x8a0200806440124b,
867 0x9c6000904e824800,
868 0x5150404003022c84,
869 0x2014452420012031,
870 true,
871 false,
872 ),
873 (
874 0x840216c970c02c10,
875 0x16490c8222011000,
876 0x4a6040120034800b,
877 0x09008001d4166827,
878 false,
879 true,
880 ),
881 (
882 0x042040900809589c,
883 0x4102064021804040,
884 0x98903b221480a523,
885 0x964840081847130e,
886 false,
887 false,
888 ),
889 (
890 0xa005ed201240a002,
891 0x580903106014a842,
892 0x16680288c4321521,
893 0x2030400608021010,
894 true,
895 true,
896 ),
897 (
898 0x405008860b020123,
899 0x2100052200602aee,
900 0xb809422040018014,
901 0x0a21a20090041001,
902 true,
903 true,
904 ),
905 (
906 0x3108541538030498,
907 0x014302a04a20a081,
908 0x0080806005804804,
909 0xdc00700020cc405c,
910 true,
911 true,
912 ),
913 (
914 0x6020490087030a00,
915 0x008a11c320049998,
916 0x069512591824a091,
917 0x4a300a0808002006,
918 true,
919 true,
920 ),
921 (
922 0x206e90b404108a02,
923 0x4a0408221400b022,
924 0x0580040201607498,
925 0x0131d21d80080b08,
926 false,
927 false,
928 ),
929 (
930 0x84811204041e00bd,
931 0x011410092c824801,
932 0x0162802203216100,
933 0xd8200844514c8040,
934 false,
935 false,
936 ),
937 (
938 0x0020000005800845,
939 0x4c19021081244589,
940 0x56026e803008012a,
941 0x916081a350103000,
942 true,
943 true,
944 ),
945 (
946 0x407050c08808e102,
947 0x1102095040020904,
948 0x000187005245184c,
949 0x28104485228804e3,
950 true,
951 true,
952 ),
953 (
954 0x6d20550000808446,
955 0x4008211019808425,
956 0x804e20c004212381,
957 0x02305c0542603848,
958 false,
959 false,
960 ),
961 (
962 0x8010400016110202,
963 0x5a40a22409e0220c,
964 0x04e20103604a3980,
965 0x80181142f20a9103,
966 false,
967 true,
968 ),
969 (
970 0x002c12089073280e,
971 0x80c8680090b66020,
972 0xd8c12d02488850a0,
973 0x010217794101901c,
974 false,
975 true,
976 ),
977 (
978 0x290c01102e12800c,
979 0x4c881498c852154e,
980 0x86c0142101a810b2,
981 0x31420a2623a40091,
982 false,
983 true,
984 ),
985 (
986 0xe08400012018c888,
987 0x020204c23b0a1010,
988 0x0301230249420426,
989 0x01340a3084204282,
990 false,
991 true,
992 ),
993 (
994 0x4038ea62022e8480,
995 0x4098130044062cf8,
996 0x2400009810006028,
997 0xb200606800900100,
998 true,
999 true,
1000 ),
1001 (
1002 0x502000190002d410,
1003 0x0438100a01024d00,
1004 0x2217c2025085020a,
1005 0xa302e11110002008,
1006 false,
1007 false,
1008 ),
1009 (
1010 0x4200400240411212,
1011 0xb816804201c00229,
1012 0x94401924308a01c8,
1013 0x41203911e0009114,
1014 true,
1015 true,
1016 ),
1017 (
1018 0x00181012e8048110,
1019 0xa040200b8c000504,
1020 0xe2c08424148b3621,
1021 0x04a6473461be288b,
1022 false,
1023 false,
1024 ),
1025 (
1026 0x118930450a104281,
1027 0x601aa1629118e100,
1028 0x0072c190b1208908,
1029 0x8125461c400018cd,
1030 false,
1031 true,
1032 ),
1033 (
1034 0x6420649001148862,
1035 0xb8140a29851b311c,
1036 0x93c9180820881088,
1037 0x014040400a000040,
1038 true,
1039 true,
1040 ),
1041 (
1042 0x080622a043c60190,
1043 0x2103c10f04000312,
1044 0x1120404098087809,
1045 0x00000090f8918000,
1046 false,
1047 false,
1048 ),
1049 (
1050 0xc19e4204800b0b88,
1051 0x008040504c102020,
1052 0x3000844216406441,
1053 0x4e450203006dc014,
1054 false,
1055 false,
1056 ),
1057 (
1058 0xc0204c082c200c01,
1059 0x13046c600e0044c1,
1060 0x01cb111600005240,
1061 0x8012028130c18800,
1062 false,
1063 false,
1064 ),
1065 (
1066 0x80e1850014a56020,
1067 0x20055110c8011012,
1068 0x240422904200918e,
1069 0x10d02c21213442a0,
1070 true,
1071 true,
1072 ),
1073 ];
1074 let mut diffs = Vec::new();
1075 for &(in1_limb1, in1_limb2, in2_limb1, in2_limb2, res1, res2) in tests.iter() {
1076 in1.limbs_mut()[1] = in1_limb1;
1077 in1.limbs_mut()[0] = in1_limb2;
1078 in2.limbs_mut()[1] = in2_limb1;
1079 in2.limbs_mut()[0] = in2_limb2;
1080 let test_res1 = in1.sign_rule(&in2);
1081 let test_res2 = in2.sign_rule(&in1);
1082 let res = (res1, res2);
1083 let test_res = (test_res1, test_res2);
1084 let tuple = (in1_limb1, in1_limb2, in2_limb1, in2_limb2);
1085 let popcnts = (
1086 in1_limb1.count_ones() % 2,
1087 in1_limb2.count_ones() % 2,
1088 in2_limb1.count_ones() % 2,
1089 in2_limb2.count_ones() % 2,
1090 );
1091 if res != test_res {
1092 diffs.push((tuple, popcnts, res, test_res))
1093 }
1094 }
1095 if !diffs.is_empty() {
1096 let formatter = diffs
1097 .iter()
1098 .format_with("\n", |(tuple, popcnts, res, test_res), f| {
1099 f(&format_args!(
1100 " Inputs: {tuple:x?}\n expected {res:?}, got {test_res:?}. \
1101 popcnts: {popcnts:?}"
1102 ))
1103 });
1104 panic!("\nFailed test cases:\n {formatter}");
1105 }
1106 }
1107}