1use std::{cmp::Ordering, iter};
2
3use crate::{
4 common::{bit_subset64::BitSubset64, default::default, vec::new_resize},
5 mem::{
6 block::Block,
7 flexible_array::{
8 constructor::FlexibleArrayConstructor, header::FlexibleArrayHeader, FlexibleArray,
9 },
10 manager::{Dealloc, Manager},
11 mut_ref::MutRef,
12 ref_::Ref,
13 },
14};
15
16use super::{bitset::BIGINT, ref_cast::RefCast};
17
18#[derive(Debug, PartialEq, Clone, Copy, Eq)]
19pub enum Sign {
20 Positive = 1,
21 Negative = -1,
22}
23
24#[derive(Debug)]
25pub struct JsBigintHeader {
26 len: isize,
27}
28
29pub struct TwosComplement {
30 sign: Sign,
31 vec: Vec<u64>,
32}
33
34impl JsBigint {
35 pub fn header_len(&self) -> isize {
36 self.header.len
37 }
38}
39
40pub type JsBigint = FlexibleArray<u64, JsBigintHeader>;
41
42pub type JsBigintRef<D> = Ref<JsBigint, D>;
43
44pub type JsBigintMutRef<D> = MutRef<JsBigint, D>;
45
46impl FlexibleArrayHeader for JsBigintHeader {
47 fn len(&self) -> usize {
48 self.len.unsigned_abs()
49 }
50}
51
52impl<D: Dealloc> RefCast<D> for JsBigint {
53 const REF_SUBSET: BitSubset64<*const Block<JsBigint, D>> = BIGINT.cast();
54}
55
56impl TwosComplement {
57 fn repeat(&self) -> u64 {
58 match self.sign {
59 Sign::Positive => 0,
60 Sign::Negative => u64::MAX,
61 }
62 }
63}
64
65pub fn new_bigint<M: Manager, I: ExactSizeIterator<Item = u64>>(
66 m: M,
67 sign: Sign,
68 i: impl IntoIterator<IntoIter = I>,
69) -> JsBigintMutRef<M::Dealloc> {
70 let items = i.into_iter();
71 m.new(FlexibleArrayConstructor::new(
72 JsBigintHeader {
73 len: (items.len() as isize) * sign as isize,
74 },
75 items,
76 ))
77}
78
79impl Sign {
80 fn opposite(self) -> Self {
81 match self {
82 Self::Positive => Sign::Negative,
83 Self::Negative => Sign::Positive,
84 }
85 }
86}
87
88pub fn zero<M: Manager>(m: M) -> JsBigintMutRef<M::Dealloc> {
89 new_bigint(m, Sign::Positive, iter::empty())
90}
91
92pub fn from_u64<M: Manager>(m: M, sign: Sign, n: u64) -> JsBigintMutRef<M::Dealloc> {
93 if n == 0 {
94 return zero(m);
95 }
96 new_bigint(m, sign, iter::once(n))
97}
98
99pub fn not<M: Manager>(m: M, value: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
100 if is_zero(value) {
101 return from_u64(m, Sign::Negative, 1);
102 }
103 match value.sign() {
104 Sign::Positive => new_bigint(m, Sign::Negative, add_vec(value.items(), &[1])),
105 Sign::Negative => new_bigint(
106 m,
107 Sign::Positive,
108 normalize_vec(sub_vec(value.items(), &[1])),
109 ),
110 }
111}
112
113pub fn add<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
114 if lhs.sign() == rhs.sign() {
115 new_bigint(m, lhs.sign(), add_vec(lhs.items(), rhs.items()))
116 } else {
117 match cmp_vec(lhs.items(), rhs.items()) {
118 Ordering::Equal => zero(m),
119 Ordering::Greater => new_bigint(m, lhs.sign(), sub_vec_norm(lhs.items(), rhs.items())),
120 Ordering::Less => new_bigint(m, rhs.sign(), sub_vec_norm(rhs.items(), lhs.items())),
121 }
122 }
123}
124
125pub fn is_zero(value: &JsBigint) -> bool {
126 value.items().is_empty()
127}
128
129impl JsBigint {
130 pub fn compare(&self, other: &Self) -> Ordering {
131 match self.header_len().cmp(&other.header_len()) {
132 Ordering::Equal => cmp_vec(self.items(), other.items()),
133 Ordering::Less => Ordering::Less,
134 Ordering::Greater => Ordering::Greater,
135 }
136 }
137
138 pub fn get_last_bit(&self) -> u64 {
139 if is_zero(self) {
140 return 0;
141 }
142 self.items()[0] & 1
143 }
144}
145
146pub fn negative<M: Manager>(m: M, value: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
147 if is_zero(value) {
148 return zero(m);
149 }
150 new_bigint(m, value.sign().opposite(), value.items().iter().copied())
151}
152
153pub fn sub<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
154 if lhs.sign() != rhs.sign() {
155 new_bigint(m, lhs.sign(), add_vec(lhs.items(), rhs.items()))
156 } else {
157 match cmp_vec(lhs.items(), rhs.items()) {
158 Ordering::Equal => zero(m),
159 Ordering::Greater => new_bigint(m, lhs.sign(), sub_vec_norm(lhs.items(), rhs.items())),
160 Ordering::Less => new_bigint(
161 m,
162 rhs.sign().opposite(),
163 sub_vec_norm(rhs.items(), lhs.items()),
164 ),
165 }
166 }
167}
168
169pub fn mul<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
170 if is_zero(lhs) || is_zero(rhs) {
171 return zero(m);
172 }
173 let sign = match lhs.sign() == rhs.sign() {
174 true => Sign::Positive,
175 false => Sign::Negative,
176 };
177 new_bigint(m, sign, mul_vec(lhs.items(), rhs.items()))
178}
179
180fn mul_vec(lhs: &[u64], rhs: &[u64]) -> Vec<u64> {
181 let lhs_max = lhs.len() - 1;
182 let rhs_max = rhs.len() - 1;
183 let total_max = lhs_max + rhs_max + 1;
184 let mut vec = new_resize(total_max + 1);
185 let mut i: usize = 0;
186 while i < total_max {
187 let mut j = i.saturating_sub(rhs_max);
188 let max = if i < lhs_max { i } else { lhs_max };
189 while j <= max {
190 vec = add_to_vec(vec, i, lhs[j] as u128 * rhs[i - j] as u128);
191 j += 1;
192 }
193 i += 1;
194 }
195 normalize_vec(vec)
196}
197
198fn add_to_vec(mut vec: Vec<u64>, index: usize, add: u128) -> Vec<u64> {
199 let sum = vec[index] as u128 + add;
200 vec[index] = sum as u64;
201 let carry = sum >> 64;
202 if carry > 0 {
203 vec = add_to_vec(vec, index + 1, carry);
204 }
205 vec
206}
207
208pub fn div_mod<M: Manager>(
209 m: M,
210 lhs: &JsBigint,
211 rhs: &JsBigint,
212) -> (JsBigintMutRef<M::Dealloc>, JsBigintMutRef<M::Dealloc>) {
213 if is_zero(rhs) {
214 panic!("attempt to divide by zero");
215 }
216
217 let sign = match lhs.sign() == rhs.sign() {
218 true => Sign::Positive,
219 false => Sign::Negative,
220 };
221
222 match cmp_vec(lhs.items(), rhs.items()) {
223 Ordering::Less => (zero(m), new_bigint(m, sign, rhs.items().to_vec())),
224 Ordering::Equal => (from_u64(m, sign, 1), zero(m)),
225 Ordering::Greater => {
226 let mut a = lhs.items().to_vec();
227 let b = rhs.items();
228 let mut result: Vec<u64> = default();
229 loop {
230 if cmp_vec(&a, b) == Ordering::Less {
231 return (new_bigint(m, sign, result), new_bigint(m, sign, a));
232 }
233 let a_high_digit = a.len() - 1;
234 let b_high_digit = b.len() - 1;
235 let a_high = a[a_high_digit];
236 let b_high = b[b_high_digit];
237 let (q_index, q_digit) = match b_high.cmp(&a_high) {
238 Ordering::Less | Ordering::Equal => {
239 (a_high_digit - b_high_digit, a_high / b_high)
240 }
241 Ordering::Greater => {
242 let a_high_2 = ((a_high as u128) << 64) + a[a_high_digit - 1] as u128;
243 (
244 a_high_digit - b_high_digit - 1,
245 (a_high_2 / b_high as u128) as u64,
246 )
247 }
248 };
249 let mut q = new_resize(q_index + 1);
250 q[q_index] = q_digit;
251 let mut m = mul_vec(b, &q);
252 if a.cmp(&m) == Ordering::Less {
253 q[q_index] = q_digit - 1;
254 m = mul_vec(b, &q);
255 }
256 a = sub_vec(&a, &m);
257 a = normalize_vec(a);
258 result = add_vec(&result, &q);
259 }
260 }
261 }
262}
263
264pub fn pow<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
265 if rhs.sign() == Sign::Negative {
266 panic!("exponent must be positive");
267 }
268
269 if lhs.items().len() == 1 && lhs.items()[0] == 1 {
270 return from_u64(m, Sign::Positive, 1);
271 }
272
273 if is_zero(lhs) {
274 return if is_zero(rhs) {
275 from_u64(m, Sign::Positive, 1)
276 } else {
277 zero(m)
278 };
279 }
280
281 if is_zero(rhs) {
282 return from_u64(m, Sign::Positive, 1);
283 }
284
285 if rhs.items().len() != 1 {
286 panic!("maximum bigint size exceeded")
287 }
288
289 pow_u64(m, lhs, rhs.items()[0])
290}
291
292pub fn pow_u64<M: Manager>(m: M, lhs: &JsBigint, mut rhs: u64) -> JsBigintMutRef<M::Dealloc> {
293 let mut res = [1].to_vec();
294 let mut b = lhs.items().to_vec();
295 let sign = if lhs.sign() == Sign::Positive || rhs & 1 == 0 {
296 Sign::Positive
297 } else {
298 Sign::Negative
299 };
300 loop {
301 if rhs == 0 {
302 return new_bigint(m, sign, res);
303 }
304 if rhs & 1 > 0 {
305 res = mul_vec(&res, &b);
306 }
307 rhs >>= 1;
308 b = mul_vec(&b, &b);
309 }
310}
311
312pub fn and<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
313 let lhs_tc = to_twos_complement(lhs);
314 let rhs_tc = to_twos_complement(rhs);
315 let res_tc = and_twos_complement(lhs_tc, rhs_tc);
316 from_twos_complement(m, res_tc)
317}
318
319pub fn or<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
320 let lhs_tc = to_twos_complement(lhs);
321 let rhs_tc = to_twos_complement(rhs);
322 let res_tc = or_twos_complement(lhs_tc, rhs_tc);
323 from_twos_complement(m, res_tc)
324}
325
326pub fn xor<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
327 let lhs_tc = to_twos_complement(lhs);
328 let rhs_tc = to_twos_complement(rhs);
329 let res_tc = xor_twos_complement(lhs_tc, rhs_tc);
330 from_twos_complement(m, res_tc)
331}
332
333pub fn shl<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
334 if is_zero(lhs) {
335 return zero(m);
336 }
337
338 if is_zero(rhs) {
339 return new_bigint(m, lhs.sign(), lhs.items().to_vec());
340 }
341
342 if rhs.items().len() != 1 {
343 return match rhs.sign() {
344 Sign::Positive => panic!("Maximum bigint size exceeded"),
345 Sign::Negative => shr_on_big(m, lhs.sign()),
346 };
347 }
348
349 match rhs.sign() {
350 Sign::Positive => shl_on_u64(m, lhs, rhs.items()[0]),
351 Sign::Negative => shr_on_u64(m, lhs, rhs.items()[0]),
352 }
353}
354
355pub fn shr<M: Manager>(m: M, lhs: &JsBigint, rhs: &JsBigint) -> JsBigintMutRef<M::Dealloc> {
356 if is_zero(lhs) {
357 return zero(m);
358 }
359
360 if is_zero(rhs) {
361 return new_bigint(m, lhs.sign(), lhs.items().to_vec());
362 }
363
364 if rhs.items().len() != 1 {
365 return match rhs.sign() {
366 Sign::Positive => shr_on_big(m, lhs.sign()),
367 Sign::Negative => panic!("Maximum bigint size exceeded"),
368 };
369 }
370
371 match rhs.sign() {
372 Sign::Positive => shr_on_u64(m, lhs, rhs.items()[0]),
373 Sign::Negative => shl_on_u64(m, lhs, rhs.items()[0]),
374 }
375}
376
377pub fn equals(lhs: &JsBigint, rhs: &JsBigint) -> bool {
378 if lhs.sign() != rhs.sign() {
379 return false;
380 }
381 cmp_vec(lhs.items(), rhs.items()) == Ordering::Equal
382}
383
384fn to_twos_complement(value: &JsBigint) -> TwosComplement {
385 TwosComplement {
386 sign: value.sign(),
387 vec: match value.sign() {
388 Sign::Positive => value.items().to_vec(),
389 Sign::Negative => {
390 let sub = sub_vec(value.items(), &[1]);
391 let mut res: Vec<_> = default();
392 for d in sub {
393 res.push(!d);
394 }
395 res
396 }
397 },
398 }
399}
400
401fn from_twos_complement<M: Manager>(m: M, value: TwosComplement) -> JsBigintMutRef<M::Dealloc> {
402 match value.sign {
403 Sign::Positive => new_bigint(m, Sign::Positive, value.vec),
404 Sign::Negative => {
405 let sub = sub_vec(&value.vec, &[1]);
406 let mut res: Vec<u64> = default();
407 for d in sub {
408 res.push(!d);
409 }
410 res = normalize_vec(res);
411 if res.is_empty() {
412 return from_u64(m, Sign::Negative, 1);
413 }
414 new_bigint(m, Sign::Negative, res)
415 }
416 }
417}
418
419fn and_twos_complement(lhs: TwosComplement, rhs: TwosComplement) -> TwosComplement {
420 let sign = match lhs.sign == Sign::Negative && rhs.sign == Sign::Negative {
421 true => Sign::Negative,
422 false => Sign::Positive,
423 };
424 let mut vec: Vec<_> = default();
425 for (a, b) in twos_complement_zip(&lhs, &rhs) {
426 vec.push(a & b);
427 }
428 vec = normalize_vec(vec);
429 TwosComplement { sign, vec }
430}
431
432fn or_twos_complement(lhs: TwosComplement, rhs: TwosComplement) -> TwosComplement {
433 let sign = match lhs.sign == Sign::Negative || rhs.sign == Sign::Negative {
434 true => Sign::Negative,
435 false => Sign::Positive,
436 };
437 let mut vec: Vec<_> = default();
438 for (a, b) in twos_complement_zip(&lhs, &rhs) {
439 vec.push(a | b);
440 }
441 vec = normalize_vec(vec);
442 TwosComplement { sign, vec }
443}
444
445fn xor_twos_complement(lhs: TwosComplement, rhs: TwosComplement) -> TwosComplement {
446 let sign = match lhs.sign == rhs.sign {
447 true => Sign::Positive,
448 false => Sign::Negative,
449 };
450 let mut vec: Vec<_> = default();
451 for (a, b) in twos_complement_zip(&lhs, &rhs) {
452 vec.push(a ^ b);
453 }
454 vec = normalize_vec(vec);
455 TwosComplement { sign, vec }
456}
457
458fn twos_complement_zip<'a>(
459 lhs: &'a TwosComplement,
460 rhs: &'a TwosComplement,
461) -> impl Iterator<Item = (u64, u64)> + 'a {
462 match rhs.vec.len() > lhs.vec.len() {
463 true => rhs
464 .vec
465 .iter()
466 .copied()
467 .zip(lhs.vec.iter().copied().chain(iter::repeat(lhs.repeat()))),
468 false => lhs
469 .vec
470 .iter()
471 .copied()
472 .zip(rhs.vec.iter().copied().chain(iter::repeat(rhs.repeat()))),
473 }
474}
475
476impl JsBigint {
477 pub fn sign(&self) -> Sign {
478 if self.header.len < 0 {
479 Sign::Negative
480 } else {
481 Sign::Positive
482 }
483 }
484}
485
486fn add_vec(lhs: &[u64], rhs: &[u64]) -> Vec<u64> {
487 let mut value: Vec<_> = default();
488 let mut carry = 0;
489 let iter = match rhs.len() > lhs.len() {
490 true => rhs
491 .iter()
492 .copied()
493 .zip(lhs.iter().copied().chain(iter::repeat(0))),
494 false => lhs
495 .iter()
496 .copied()
497 .zip(rhs.iter().copied().chain(iter::repeat(0))),
498 };
499 for (a, b) in iter {
500 let next = a as u128 + b as u128 + carry;
501 value.push(next as u64);
502 carry = next >> 64;
503 }
504 if carry != 0 {
505 value.push(carry as u64);
506 }
507 value
508}
509
510fn sub_vec_norm(lhs: &[u64], rhs: &[u64]) -> Vec<u64> {
511 normalize_vec(sub_vec(lhs, rhs))
512}
513
514fn sub_vec(lhs: &[u64], rhs: &[u64]) -> Vec<u64> {
515 let mut value: Vec<_> = default();
516 let mut borrow = 0;
517 let iter = lhs
518 .iter()
519 .copied()
520 .zip(rhs.iter().copied().chain(iter::repeat(0)));
521 for (a, b) in iter {
522 let next = a as i128 - b as i128 - borrow;
523 value.push(next as u64);
524 borrow = next >> 64 & 1;
525 }
526 value
527}
528
529fn normalize_vec(mut vec: Vec<u64>) -> Vec<u64> {
530 while let Some(&0) = vec.last() {
531 vec.pop();
532 }
533 vec
534}
535
536fn cmp_vec(lhs: &[u64], rhs: &[u64]) -> Ordering {
537 let self_len = lhs.len();
538 let other_len: usize = rhs.len();
539 if self_len != other_len {
540 return self_len.cmp(&other_len);
541 }
542 for (self_digit, other_digit) in lhs.iter().copied().rev().zip(rhs.iter().copied().rev()) {
543 if self_digit != other_digit {
544 return self_digit.cmp(&other_digit);
545 }
546 }
547 Ordering::Equal
548}
549
550pub fn shl_on_u64<M: Manager>(m: M, lhs: &JsBigint, rhs: u64) -> JsBigintMutRef<M::Dealloc> {
551 let mut vec = lhs.items().to_vec();
552 let shift_mod = rhs & ((1 << 6) - 1);
553 if shift_mod > 0 {
554 let len = vec.len();
555 vec.push(0);
556 for i in (0..=len - 1).rev() {
557 let mut digit = vec[i] as u128;
558 digit <<= shift_mod;
559 vec[i + 1] |= (digit >> 64) as u64;
560 vec[i] = digit as u64;
561 }
562 }
563
564 let number_of_zeros = (rhs / 64) as usize;
565 if number_of_zeros > 0 {
566 let mut zeros_vector: Vec<_> = new_resize(number_of_zeros);
567 zeros_vector.extend(vec);
568 vec = zeros_vector;
569 }
570
571 vec = normalize_vec(vec);
572 new_bigint(m, lhs.sign(), vec)
573}
574
575pub fn shr_on_u64<M: Manager>(m: M, lhs: &JsBigint, rhs: u64) -> JsBigintMutRef<M::Dealloc> {
576 let number_to_remove = (rhs / 64) as usize;
577 if number_to_remove >= lhs.items().len() {
578 return shr_on_big(m, lhs.sign());
579 }
580
581 let mut vec = lhs.items().to_vec();
582 vec = vec.split_off(number_to_remove);
583 let shift_mod = rhs & ((1 << 6) - 1);
584 if shift_mod > 0 {
585 let len = vec.len();
586 let mask = 1 << (shift_mod - 1);
587 let mut i = 0;
588 loop {
589 vec[i] >>= shift_mod;
590 i += 1;
591 if i == len {
592 break;
593 }
594 vec[i - 1] |= (vec[i] & mask) << (64 - shift_mod);
595 }
596 }
597
598 vec = normalize_vec(vec);
599 if vec.is_empty() && lhs.sign() == Sign::Negative {
600 return from_u64(m, Sign::Negative, 1);
601 }
602 new_bigint(m, lhs.sign(), vec)
603}
604
605fn shr_on_big<M: Manager>(m: M, sign: Sign) -> JsBigintMutRef<M::Dealloc> {
606 match sign {
607 Sign::Positive => zero(m),
608 Sign::Negative => from_u64(m, Sign::Negative, 1),
609 }
610}
611
612#[cfg(test)]
613mod test {
614 use std::{cmp::Ordering, ops::Deref};
615
616 use wasm_bindgen_test::wasm_bindgen_test;
617
618 use crate::{
619 js::{any::Any, js_bigint::xor, type_::Type},
620 mem::global::Global,
621 };
622
623 use super::{
624 add, and, div_mod, from_u64, mul, new_bigint, not, or, pow, shl, shr, sub, zero,
625 JsBigintRef, Sign,
626 };
627
628 #[test]
629 #[wasm_bindgen_test]
630 fn test_add_u64() {
631 type A = Any<Global>;
632 type BigintRef = JsBigintRef<Global>;
633
634 let a_ref = from_u64(Global(), Sign::Positive, 1);
635 let b_ref = from_u64(Global(), Sign::Positive, 2);
636 let a = a_ref.deref();
637 let b = b_ref.deref();
638 let sum: BigintRef = add(Global(), a, b).to_ref();
639 let res = A::move_from(sum);
640 assert_eq!(res.get_type(), Type::Bigint);
641 {
642 let o = res.try_move::<BigintRef>().unwrap();
643 assert_eq!(o.sign(), Sign::Positive);
644 assert_eq!(o.items(), &[3]);
645 }
646
647 let a_ref = from_u64(Global(), Sign::Negative, 1);
648 let b_ref = from_u64(Global(), Sign::Negative, 2);
649 let a = a_ref.deref();
650 let b = b_ref.deref();
651 let sum: BigintRef = add(Global(), a, b).to_ref();
652 let res = A::move_from(sum);
653 assert_eq!(res.get_type(), Type::Bigint);
654 {
655 let o = res.try_move::<BigintRef>().unwrap();
656 assert_eq!(o.sign(), Sign::Negative);
657 assert_eq!(o.items(), &[3]);
658 }
659
660 let a_ref = from_u64(Global(), Sign::Positive, 1);
661 let b_ref = from_u64(Global(), Sign::Negative, 2);
662 let a = a_ref.deref();
663 let b = b_ref.deref();
664 let sum: BigintRef = add(Global(), a, b).to_ref();
665 let res = A::move_from(sum);
666 assert_eq!(res.get_type(), Type::Bigint);
667 {
668 let o = res.try_move::<BigintRef>().unwrap();
669 assert_eq!(o.sign(), Sign::Negative);
670 assert_eq!(o.items(), &[1]);
671 }
672
673 let a_ref = from_u64(Global(), Sign::Negative, 100);
674 let b_ref = from_u64(Global(), Sign::Positive, 100);
675 let a = a_ref.deref();
676 let b = b_ref.deref();
677 let sum: BigintRef = add(Global(), a, b).to_ref();
678 let u = A::move_from(sum);
679 assert_eq!(u.get_type(), Type::Bigint);
680 {
681 let o = u.try_move::<BigintRef>().unwrap();
682 assert!(o.items().is_empty());
683 }
684
685 let a_ref = from_u64(Global(), Sign::Positive, 1 << 63);
686 let b_ref = from_u64(Global(), Sign::Positive, 1 << 63);
687 let a = a_ref.deref();
688 let b = b_ref.deref();
689 let sum: BigintRef = add(Global(), a, b).to_ref();
690 let res = A::move_from(sum);
691 assert_eq!(res.get_type(), Type::Bigint);
692 {
693 let o = res.try_move::<BigintRef>().unwrap();
694 assert_eq!(o.sign(), Sign::Positive);
695 assert_eq!(o.items(), &[0, 1]);
696 }
697 }
698
699 #[test]
700 #[wasm_bindgen_test]
701 fn test_add_overflow() {
702 type A = Any<Global>;
703 type BigintRef = JsBigintRef<Global>;
704
705 let a_ref = from_u64(Global(), Sign::Positive, 1 << 63);
706 let b_ref = from_u64(Global(), Sign::Positive, 1 << 63);
707 let a = a_ref.deref();
708 let b = b_ref.deref();
709 let sum: BigintRef = add(Global(), a, b).to_ref();
710 let res = A::move_from(sum);
711 assert_eq!(res.get_type(), Type::Bigint);
712 {
713 let o = res.try_move::<BigintRef>().unwrap();
714 assert_eq!(o.sign(), Sign::Positive);
715 assert_eq!(o.items(), &[0, 1]);
716 }
717 }
718
719 #[test]
720 #[wasm_bindgen_test]
721 fn test_sub_u64() {
722 type A = Any<Global>;
723 type BigintRef = JsBigintRef<Global>;
724
725 let a_ref = from_u64(Global(), Sign::Positive, 1);
726 let b_ref = from_u64(Global(), Sign::Positive, 2);
727 let a = a_ref.deref();
728 let b = b_ref.deref();
729 let sum: BigintRef = sub(Global(), a, b).to_ref();
730 let res = A::move_from(sum);
731 assert_eq!(res.get_type(), Type::Bigint);
732 {
733 let o = res.try_move::<BigintRef>().unwrap();
734 assert_eq!(o.sign(), Sign::Negative);
735 assert_eq!(o.items(), &[1]);
736 }
737
738 let a_ref = from_u64(Global(), Sign::Positive, 1);
739 let b_ref = from_u64(Global(), Sign::Negative, 2);
740 let a = a_ref.deref();
741 let b = b_ref.deref();
742 let sum: BigintRef = sub(Global(), a, b).to_ref();
743 let res = A::move_from(sum);
744 assert_eq!(res.get_type(), Type::Bigint);
745 {
746 let o = res.try_move::<BigintRef>().unwrap();
747 assert_eq!(o.sign(), Sign::Positive);
748 assert_eq!(o.items(), &[3]);
749 }
750
751 let a_ref = from_u64(Global(), Sign::Negative, 100);
752 let b_ref = from_u64(Global(), Sign::Negative, 100);
753 let a = a_ref.deref();
754 let b = b_ref.deref();
755 let sum: BigintRef = sub(Global(), a, b).to_ref();
756 let res = A::move_from(sum);
757 assert_eq!(res.get_type(), Type::Bigint);
758 {
759 let o = res.try_move::<BigintRef>().unwrap();
760 assert!(o.items().is_empty());
761 }
762 }
763
764 #[test]
765 #[wasm_bindgen_test]
766 fn test_cmp() {
767 type A = Any<Global>;
768 type BigintRef = JsBigintRef<Global>;
769
770 let a_ref = from_u64(Global(), Sign::Positive, 1);
771 let b_ref = from_u64(Global(), Sign::Positive, 1);
772 let a = a_ref.deref();
773 let b = b_ref.deref();
774 assert_eq!(a.compare(b), Ordering::Equal);
775
776 let a_ref = from_u64(Global(), Sign::Positive, 1);
777 let b_ref = from_u64(Global(), Sign::Positive, 2);
778 let a = a_ref.deref();
779 let b = b_ref.deref();
780 assert_eq!(a.compare(b), Ordering::Less);
781
782 let a_ref = from_u64(Global(), Sign::Positive, 1);
783 let b_ref = from_u64(Global(), Sign::Negative, 2);
784 let a = a_ref.deref();
785 let b = b_ref.deref();
786 assert_eq!(a.compare(b), Ordering::Greater);
787
788 let a_ref = new_bigint(Global(), Sign::Positive, [1, 2]);
789 let b_ref = new_bigint(Global(), Sign::Positive, [2, 1]);
790 let a = a_ref.deref();
791 let b = b_ref.deref();
792 assert_eq!(a.compare(b), Ordering::Greater);
793 }
794
795 #[test]
796 #[wasm_bindgen_test]
797 fn test_shl_zero() {
798 type A = Any<Global>;
799 type BigintRef = JsBigintRef<Global>;
800
801 let a_ref = zero(Global());
802 let b_ref = from_u64(Global(), Sign::Positive, 2);
803 let a = a_ref.deref();
804 let b = b_ref.deref();
805
806 let c: BigintRef = shl(Global(), a, b).to_ref();
807 let res = A::move_from(c);
808 assert_eq!(res.get_type(), Type::Bigint);
809 {
810 let o = res.try_move::<BigintRef>().unwrap();
811 assert!(o.items().is_empty());
812 }
813
814 let c: BigintRef = shl(Global(), b, a).to_ref();
815 let res = A::move_from(c);
816 assert_eq!(res.get_type(), Type::Bigint);
817 {
818 let o = res.try_move::<BigintRef>().unwrap();
819 assert_eq!(o.sign(), Sign::Positive);
820 assert_eq!(o.items(), &[2]);
821 }
822
823 let c: BigintRef = shl(Global(), a, a).to_ref();
824 let res = A::move_from(c);
825 assert_eq!(res.get_type(), Type::Bigint);
826 {
827 let o = res.try_move::<BigintRef>().unwrap();
828 assert!(o.items().is_empty());
829 }
830 }
831
832 #[test]
833 #[wasm_bindgen_test]
834 fn test_shl() {
835 type A = Any<Global>;
836 type BigintRef = JsBigintRef<Global>;
837
838 let a_ref = from_u64(Global(), Sign::Positive, 1);
839 let b_ref = from_u64(Global(), Sign::Positive, 1);
840 let a = a_ref.deref();
841 let b = b_ref.deref();
842 let c: BigintRef = shl(Global(), a, b).to_ref();
843 let res = A::move_from(c);
844 assert_eq!(res.get_type(), Type::Bigint);
845 {
846 let o = res.try_move::<BigintRef>().unwrap();
847 assert_eq!(o.sign(), Sign::Positive);
848 assert_eq!(o.items(), &[2]);
849 }
850
851 let a_ref = from_u64(Global(), Sign::Negative, 1);
852 let b_ref = from_u64(Global(), Sign::Positive, 1);
853 let a = a_ref.deref();
854 let b = b_ref.deref();
855 let c: BigintRef = shl(Global(), a, b).to_ref();
856 let res = A::move_from(c);
857 assert_eq!(res.get_type(), Type::Bigint);
858 {
859 let o = res.try_move::<BigintRef>().unwrap();
860 assert_eq!(o.sign(), Sign::Negative);
861 assert_eq!(o.items(), &[2]);
862 }
863
864 let a_ref = from_u64(Global(), Sign::Positive, 5);
865 let b_ref = from_u64(Global(), Sign::Positive, 63);
866 let a = a_ref.deref();
867 let b = b_ref.deref();
868 let c: BigintRef = shl(Global(), a, b).to_ref();
869 let res = A::move_from(c);
870 assert_eq!(res.get_type(), Type::Bigint);
871 {
872 let o = res.try_move::<BigintRef>().unwrap();
873 assert_eq!(o.sign(), Sign::Positive);
874 assert_eq!(o.items(), &[1 << 63, 2]);
875 }
876
877 let a_ref = new_bigint(Global(), Sign::Positive, [5, 9]);
878 let b_ref = from_u64(Global(), Sign::Positive, 63);
879 let a = a_ref.deref();
880 let b = b_ref.deref();
881 let c: BigintRef = shl(Global(), a, b).to_ref();
882 let res = A::move_from(c);
883 assert_eq!(res.get_type(), Type::Bigint);
884 {
885 let o = res.try_move::<BigintRef>().unwrap();
886 assert_eq!(o.sign(), Sign::Positive);
887 assert_eq!(o.items(), &[1 << 63, (1 << 63) + 2, 4]);
888 }
889
890 let a_ref = new_bigint(Global(), Sign::Positive, [5, 9]);
891 let b_ref = from_u64(Global(), Sign::Positive, 64);
892 let a = a_ref.deref();
893 let b = b_ref.deref();
894 let c: BigintRef = shl(Global(), a, b).to_ref();
895 let res = A::move_from(c);
896 assert_eq!(res.get_type(), Type::Bigint);
897 {
898 let o = res.try_move::<BigintRef>().unwrap();
899 assert_eq!(o.sign(), Sign::Positive);
900 assert_eq!(o.items(), &[0, 5, 9]);
901 }
902
903 let a_ref = new_bigint(Global(), Sign::Positive, [5, 9]);
904 let b_ref = from_u64(Global(), Sign::Positive, 65);
905 let a = a_ref.deref();
906 let b = b_ref.deref();
907 let c: BigintRef = shl(Global(), a, b).to_ref();
908 let res = A::move_from(c);
909 assert_eq!(res.get_type(), Type::Bigint);
910 {
911 let o = res.try_move::<BigintRef>().unwrap();
912 assert_eq!(o.sign(), Sign::Positive);
913 assert_eq!(o.items(), &[0, 10, 18]);
914 }
915
916 let a_ref = from_u64(Global(), Sign::Positive, 2);
917 let b_ref = from_u64(Global(), Sign::Negative, 1);
918 let a = a_ref.deref();
919 let b = b_ref.deref();
920 let c: BigintRef = shl(Global(), a, b).to_ref();
921 let res = A::move_from(c);
922 assert_eq!(res.get_type(), Type::Bigint);
923 {
924 let o = res.try_move::<BigintRef>().unwrap();
925 assert_eq!(o.sign(), Sign::Positive);
926 assert_eq!(o.items(), &[1]);
927 }
928 }
929
930 #[test]
931 #[should_panic(expected = "Maximum bigint size exceeded")]
932 #[wasm_bindgen_test]
933 fn test_shl_overflow() {
934 type A = Any<Global>;
935 type BigintRef = JsBigintRef<Global>;
936
937 let a_ref = from_u64(Global(), Sign::Positive, 1);
938 let b_ref = new_bigint(Global(), Sign::Positive, [1, 1]);
939 let a = a_ref.deref();
940 let b = b_ref.deref();
941 let _c: BigintRef = shl(Global(), a, b).to_ref();
942 }
943
944 #[test]
945 #[wasm_bindgen_test]
946 fn test_shr_zero() {
947 type A = Any<Global>;
948 type BigintRef = JsBigintRef<Global>;
949
950 let a_ref = zero(Global());
951 let b_ref = from_u64(Global(), Sign::Positive, 2);
952 let a = a_ref.deref();
953 let b = b_ref.deref();
954
955 let c: BigintRef = shr(Global(), a, b).to_ref();
956 let res = A::move_from(c);
957 assert_eq!(res.get_type(), Type::Bigint);
958 {
959 let o = res.try_move::<BigintRef>().unwrap();
960 assert!(o.items().is_empty());
961 }
962
963 let c: BigintRef = shr(Global(), b, a).to_ref();
964 let res = A::move_from(c);
965 assert_eq!(res.get_type(), Type::Bigint);
966 {
967 let o = res.try_move::<BigintRef>().unwrap();
968 assert_eq!(o.sign(), Sign::Positive);
969 assert_eq!(o.items(), &[2]);
970 }
971
972 let c: BigintRef = shr(Global(), a, a).to_ref();
973 let res = A::move_from(c);
974 assert_eq!(res.get_type(), Type::Bigint);
975 {
976 let o = res.try_move::<BigintRef>().unwrap();
977 assert!(o.items().is_empty());
978 }
979 }
980
981 #[test]
982 #[wasm_bindgen_test]
983 fn test_shr() {
984 type A = Any<Global>;
985 type BigintRef = JsBigintRef<Global>;
986
987 let a_ref = new_bigint(Global(), Sign::Positive, [1, 1, 1, 1]);
988 let b_ref = from_u64(Global(), Sign::Positive, 256);
989 let a = a_ref.deref();
990 let b = b_ref.deref();
991 let c: BigintRef = shr(Global(), a, b).to_ref();
992 let res = A::move_from(c);
993 assert_eq!(res.get_type(), Type::Bigint);
994 {
995 let o = res.try_move::<BigintRef>().unwrap();
996 assert!(o.items().is_empty());
997 }
998
999 let a_ref = new_bigint(Global(), Sign::Negative, [1, 1, 1, 1]);
1000 let b_ref = from_u64(Global(), Sign::Positive, 256);
1001 let a = a_ref.deref();
1002 let b = b_ref.deref();
1003 let c: BigintRef = shr(Global(), a, b).to_ref();
1004 let res = A::move_from(c);
1005 assert_eq!(res.get_type(), Type::Bigint);
1006 {
1007 let o = res.try_move::<BigintRef>().unwrap();
1008 assert_eq!(o.sign(), Sign::Negative);
1009 assert_eq!(o.items(), &[1]);
1010 }
1011
1012 let a_ref = from_u64(Global(), Sign::Positive, 1);
1013 let b_ref = from_u64(Global(), Sign::Positive, 1);
1014 let a = a_ref.deref();
1015 let b = b_ref.deref();
1016 let c: BigintRef = shr(Global(), a, b).to_ref();
1017 let res = A::move_from(c);
1018 assert_eq!(res.get_type(), Type::Bigint);
1019 {
1020 let o = res.try_move::<BigintRef>().unwrap();
1021 assert!(o.items().is_empty());
1022 }
1023
1024 let a_ref = from_u64(Global(), Sign::Negative, 1);
1025 let b_ref = from_u64(Global(), Sign::Positive, 1);
1026 let a = a_ref.deref();
1027 let b = b_ref.deref();
1028 let c: BigintRef = shr(Global(), a, b).to_ref();
1029 let res = A::move_from(c);
1030 assert_eq!(res.get_type(), Type::Bigint);
1031 {
1032 let o = res.try_move::<BigintRef>().unwrap();
1033 assert_eq!(o.sign(), Sign::Negative);
1034 assert_eq!(o.items(), &[1]);
1035 }
1036
1037 let a_ref = from_u64(Global(), Sign::Positive, 2);
1038 let b_ref = from_u64(Global(), Sign::Positive, 1);
1039 let a = a_ref.deref();
1040 let b = b_ref.deref();
1041 let c: BigintRef = shr(Global(), a, b).to_ref();
1042 let res = A::move_from(c);
1043 assert_eq!(res.get_type(), Type::Bigint);
1044 {
1045 let o = res.try_move::<BigintRef>().unwrap();
1046 assert_eq!(o.sign(), Sign::Positive);
1047 assert_eq!(o.items(), &[1]);
1048 }
1049
1050 let a_ref = new_bigint(Global(), Sign::Positive, [1, 5, 9]);
1051 let b_ref = from_u64(Global(), Sign::Positive, 65);
1052 let a = a_ref.deref();
1053 let b = b_ref.deref();
1054 let c: BigintRef = shr(Global(), a, b).to_ref();
1055 let res = A::move_from(c);
1056 assert_eq!(res.get_type(), Type::Bigint);
1057 {
1058 let o = res.try_move::<BigintRef>().unwrap();
1059 assert_eq!(o.sign(), Sign::Positive);
1060 assert_eq!(o.items(), &[(1 << 63) + 2, 4]);
1061 }
1062
1063 let a_ref = from_u64(Global(), Sign::Positive, 2);
1064 let b_ref = from_u64(Global(), Sign::Negative, 1);
1065 let a = a_ref.deref();
1066 let b = b_ref.deref();
1067 let c: BigintRef = shr(Global(), a, b).to_ref();
1068 let res = A::move_from(c);
1069 assert_eq!(res.get_type(), Type::Bigint);
1070 {
1071 let o = res.try_move::<BigintRef>().unwrap();
1072 assert_eq!(o.sign(), Sign::Positive);
1073 assert_eq!(o.items(), &[4]);
1074 }
1075 }
1076
1077 #[test]
1078 #[should_panic(expected = "Maximum bigint size exceeded")]
1079 #[wasm_bindgen_test]
1080 fn test_shr_overflow() {
1081 type A = Any<Global>;
1082 type BigintRef = JsBigintRef<Global>;
1083
1084 let a_ref = from_u64(Global(), Sign::Positive, 1);
1085 let b_ref = new_bigint(Global(), Sign::Negative, [1, 1]);
1086 let a = a_ref.deref();
1087 let b = b_ref.deref();
1088 let _c: BigintRef = shr(Global(), a, b).to_ref();
1089 }
1090
1091 #[test]
1092 #[wasm_bindgen_test]
1093 fn test_and() {
1094 type A = Any<Global>;
1095 type BigintRef = JsBigintRef<Global>;
1096
1097 let a_ref = new_bigint(Global(), Sign::Positive, [1, 3, 5, 7, 9]);
1098 let b_ref = new_bigint(Global(), Sign::Positive, [3, 5, 7, 9, 11]);
1099 let a = a_ref.deref();
1100 let b = b_ref.deref();
1101 let c: BigintRef = and(Global(), a, b).to_ref();
1102 let res = A::move_from(c);
1103 assert_eq!(res.get_type(), Type::Bigint);
1104 {
1105 let o = res.try_move::<BigintRef>().unwrap();
1106 assert_eq!(o.items(), &[1, 1, 5, 1, 9]);
1107 }
1108
1109 let a_ref = from_u64(Global(), Sign::Positive, 12);
1110 let b_ref = from_u64(Global(), Sign::Negative, 9);
1111 let a = a_ref.deref();
1112 let b = b_ref.deref();
1113 let c: BigintRef = and(Global(), a, b).to_ref();
1114 let res = A::move_from(c);
1115 assert_eq!(res.get_type(), Type::Bigint);
1116 {
1117 let o = res.try_move::<BigintRef>().unwrap();
1118 assert_eq!(o.sign(), Sign::Positive);
1119 assert_eq!(o.items(), &[4]);
1120 }
1121
1122 let a_ref = from_u64(Global(), Sign::Negative, 12);
1123 let b_ref = from_u64(Global(), Sign::Negative, 9);
1124 let a = a_ref.deref();
1125 let b = b_ref.deref();
1126 let c: BigintRef = and(Global(), a, b).to_ref();
1127 let res = A::move_from(c);
1128 assert_eq!(res.get_type(), Type::Bigint);
1129 {
1130 let o = res.try_move::<BigintRef>().unwrap();
1131 assert_eq!(o.sign(), Sign::Negative);
1132 assert_eq!(o.items(), &[12]);
1133 }
1134
1135 let a_ref = from_u64(Global(), Sign::Positive, 1);
1136 let b_ref = zero(Global());
1137 let a = a_ref.deref();
1138 let b = b_ref.deref();
1139 let c: BigintRef = and(Global(), a, b).to_ref();
1140 let res = A::move_from(c);
1141 assert_eq!(res.get_type(), Type::Bigint);
1142 {
1143 let o = res.try_move::<BigintRef>().unwrap();
1144 assert!(o.items().is_empty());
1145 }
1146
1147 let a_ref = from_u64(Global(), Sign::Negative, 1);
1148 let b_ref = zero(Global());
1149 let a = a_ref.deref();
1150 let b = b_ref.deref();
1151 let c: BigintRef = and(Global(), a, b).to_ref();
1152 let res = A::move_from(c);
1153 assert_eq!(res.get_type(), Type::Bigint);
1154 {
1155 let o = res.try_move::<BigintRef>().unwrap();
1156 assert!(o.items().is_empty());
1157 }
1158
1159 let a_ref = from_u64(Global(), Sign::Positive, 1);
1160 let b_ref = new_bigint(Global(), Sign::Negative, [1, 1]);
1161 let a = a_ref.deref();
1162 let b = b_ref.deref();
1163 let c: BigintRef = and(Global(), a, b).to_ref();
1164 let res = A::move_from(c);
1165 assert_eq!(res.get_type(), Type::Bigint);
1166 {
1167 let o = res.try_move::<BigintRef>().unwrap();
1168 assert_eq!(o.sign(), Sign::Positive);
1169 assert_eq!(o.items(), &[1]);
1170 }
1171
1172 let a_ref = from_u64(Global(), Sign::Negative, 1);
1173 let b_ref = new_bigint(Global(), Sign::Positive, [1, 1]);
1174 let a = a_ref.deref();
1175 let b = b_ref.deref();
1176 let c: BigintRef = and(Global(), a, b).to_ref();
1177 let res = A::move_from(c);
1178 assert_eq!(res.get_type(), Type::Bigint);
1179 {
1180 let o = res.try_move::<BigintRef>().unwrap();
1181 assert_eq!(o.sign(), Sign::Positive);
1182 assert_eq!(o.items(), &[1, 1]);
1183 }
1184 }
1185
1186 #[test]
1187 #[wasm_bindgen_test]
1188 fn test_or() {
1189 type A = Any<Global>;
1190 type BigintRef = JsBigintRef<Global>;
1191
1192 let a_ref = new_bigint(Global(), Sign::Positive, [1, 3, 5, 7, 9]);
1193 let b_ref = new_bigint(Global(), Sign::Positive, [3, 5, 7, 9, 11]);
1194 let a = a_ref.deref();
1195 let b = b_ref.deref();
1196 let c: BigintRef = or(Global(), a, b).to_ref();
1197 let res = A::move_from(c);
1198 assert_eq!(res.get_type(), Type::Bigint);
1199 {
1200 let o = res.try_move::<BigintRef>().unwrap();
1201 assert_eq!(o.items(), &[3, 7, 7, 15, 11]);
1202 }
1203
1204 let a_ref = from_u64(Global(), Sign::Positive, 12);
1205 let b_ref = from_u64(Global(), Sign::Negative, 9);
1206 let a = a_ref.deref();
1207 let b = b_ref.deref();
1208 let c: BigintRef = or(Global(), a, b).to_ref();
1209 let res = A::move_from(c);
1210 assert_eq!(res.get_type(), Type::Bigint);
1211 {
1212 let o = res.try_move::<BigintRef>().unwrap();
1213 assert_eq!(o.sign(), Sign::Negative);
1214 assert_eq!(o.items(), &[1]);
1215 }
1216
1217 let a_ref = from_u64(Global(), Sign::Negative, 12);
1218 let b_ref = from_u64(Global(), Sign::Negative, 9);
1219 let a = a_ref.deref();
1220 let b = b_ref.deref();
1221 let c: BigintRef = or(Global(), a, b).to_ref();
1222 let res = A::move_from(c);
1223 assert_eq!(res.get_type(), Type::Bigint);
1224 {
1225 let o = res.try_move::<BigintRef>().unwrap();
1226 assert_eq!(o.sign(), Sign::Negative);
1227 assert_eq!(o.items(), &[9]);
1228 }
1229
1230 let a_ref = from_u64(Global(), Sign::Positive, 1);
1231 let b_ref = zero(Global());
1232 let a = a_ref.deref();
1233 let b = b_ref.deref();
1234 let c: BigintRef = or(Global(), a, b).to_ref();
1235 let res = A::move_from(c);
1236 assert_eq!(res.get_type(), Type::Bigint);
1237 {
1238 let o = res.try_move::<BigintRef>().unwrap();
1239 assert_eq!(o.sign(), Sign::Positive);
1240 assert_eq!(o.items(), &[1]);
1241 }
1242
1243 let a_ref = from_u64(Global(), Sign::Negative, 1);
1244 let b_ref = zero(Global());
1245 let a = a_ref.deref();
1246 let b = b_ref.deref();
1247 let c: BigintRef = or(Global(), a, b).to_ref();
1248 let res = A::move_from(c);
1249 assert_eq!(res.get_type(), Type::Bigint);
1250 {
1251 let o = res.try_move::<BigintRef>().unwrap();
1252 assert_eq!(o.sign(), Sign::Negative);
1253 assert_eq!(o.items(), &[1]);
1254 }
1255
1256 let a_ref = from_u64(Global(), Sign::Positive, 1);
1257 let b_ref = new_bigint(Global(), Sign::Negative, [0, 1]);
1258 let a = a_ref.deref();
1259 let b = b_ref.deref();
1260 let c: BigintRef = or(Global(), a, b).to_ref();
1261 let res = A::move_from(c);
1262 assert_eq!(res.get_type(), Type::Bigint);
1263 {
1264 let o = res.try_move::<BigintRef>().unwrap();
1265 assert_eq!(o.sign(), Sign::Negative);
1266 assert_eq!(o.items(), &[u64::MAX]);
1267 }
1268
1269 let a_ref = from_u64(Global(), Sign::Negative, 1);
1270 let b_ref = new_bigint(Global(), Sign::Positive, [0, 1]);
1271 let a = a_ref.deref();
1272 let b = b_ref.deref();
1273 let c: BigintRef = or(Global(), a, b).to_ref();
1274 let res = A::move_from(c);
1275 assert_eq!(res.get_type(), Type::Bigint);
1276 {
1277 let o = res.try_move::<BigintRef>().unwrap();
1278 assert_eq!(o.sign(), Sign::Negative);
1279 assert_eq!(o.items(), &[1]);
1280 }
1281 }
1282
1283 #[test]
1284 #[wasm_bindgen_test]
1285 fn test_xor() {
1286 type A = Any<Global>;
1287 type BigintRef = JsBigintRef<Global>;
1288
1289 let a_ref = new_bigint(Global(), Sign::Positive, [1, 3, 5, 7, 9]);
1290 let b_ref = new_bigint(Global(), Sign::Positive, [3, 5, 7, 9, 11]);
1291 let a = a_ref.deref();
1292 let b = b_ref.deref();
1293 let c: BigintRef = xor(Global(), a, b).to_ref();
1294 let res = A::move_from(c);
1295 assert_eq!(res.get_type(), Type::Bigint);
1296 {
1297 let o = res.try_move::<BigintRef>().unwrap();
1298 assert_eq!(o.items(), &[2, 6, 2, 14, 2]);
1299 }
1300
1301 let a_ref = from_u64(Global(), Sign::Positive, 12);
1302 let b_ref = from_u64(Global(), Sign::Negative, 9);
1303 let a = a_ref.deref();
1304 let b = b_ref.deref();
1305 let c: BigintRef = xor(Global(), a, b).to_ref();
1306 let res = A::move_from(c);
1307 assert_eq!(res.get_type(), Type::Bigint);
1308 {
1309 let o = res.try_move::<BigintRef>().unwrap();
1310 assert_eq!(o.sign(), Sign::Negative);
1311 assert_eq!(o.items(), &[5]);
1312 }
1313
1314 let a_ref = from_u64(Global(), Sign::Negative, 12);
1315 let b_ref = from_u64(Global(), Sign::Negative, 9);
1316 let a = a_ref.deref();
1317 let b = b_ref.deref();
1318 let c: BigintRef = xor(Global(), a, b).to_ref();
1319 let res = A::move_from(c);
1320 assert_eq!(res.get_type(), Type::Bigint);
1321 {
1322 let o = res.try_move::<BigintRef>().unwrap();
1323 assert_eq!(o.sign(), Sign::Positive);
1324 assert_eq!(o.items(), &[3]);
1325 }
1326
1327 let a_ref = from_u64(Global(), Sign::Positive, 1);
1328 let b_ref = zero(Global());
1329 let a = a_ref.deref();
1330 let b = b_ref.deref();
1331 let c: BigintRef = xor(Global(), a, b).to_ref();
1332 let res = A::move_from(c);
1333 assert_eq!(res.get_type(), Type::Bigint);
1334 {
1335 let o = res.try_move::<BigintRef>().unwrap();
1336 assert_eq!(o.sign(), Sign::Positive);
1337 assert_eq!(o.items(), &[1]);
1338 }
1339
1340 let a_ref = from_u64(Global(), Sign::Negative, 1);
1341 let b_ref = zero(Global());
1342 let a = a_ref.deref();
1343 let b = b_ref.deref();
1344 let c: BigintRef = xor(Global(), a, b).to_ref();
1345 let res = A::move_from(c);
1346 assert_eq!(res.get_type(), Type::Bigint);
1347 {
1348 let o = res.try_move::<BigintRef>().unwrap();
1349 assert_eq!(o.sign(), Sign::Negative);
1350 assert_eq!(o.items(), &[1]);
1351 }
1352
1353 let a_ref = from_u64(Global(), Sign::Positive, 1);
1354 let b_ref = new_bigint(Global(), Sign::Negative, [0, 1]);
1355 let a = a_ref.deref();
1356 let b = b_ref.deref();
1357 let c: BigintRef = xor(Global(), a, b).to_ref();
1358 let res = A::move_from(c);
1359 assert_eq!(res.get_type(), Type::Bigint);
1360 {
1361 let o = res.try_move::<BigintRef>().unwrap();
1362 assert_eq!(o.sign(), Sign::Negative);
1363 assert_eq!(o.items(), &[u64::MAX]);
1364 }
1365
1366 let a_ref = from_u64(Global(), Sign::Negative, 1);
1367 let b_ref = new_bigint(Global(), Sign::Positive, [0, 1]);
1368 let a = a_ref.deref();
1369 let b = b_ref.deref();
1370 let c: BigintRef = xor(Global(), a, b).to_ref();
1371 let res = A::move_from(c);
1372 assert_eq!(res.get_type(), Type::Bigint);
1373 {
1374 let o = res.try_move::<BigintRef>().unwrap();
1375 assert_eq!(o.sign(), Sign::Negative);
1376 assert_eq!(o.items(), &[1, 1]);
1377 }
1378 }
1379
1380 #[test]
1381 #[wasm_bindgen_test]
1382 fn test_not() {
1383 type A = Any<Global>;
1384 type BigintRef = JsBigintRef<Global>;
1385
1386 let a_ref = zero(Global());
1387 let a = a_ref.deref();
1388 let not_a: BigintRef = not(Global(), a).to_ref();
1389 let res = A::move_from(not_a);
1390 assert_eq!(res.get_type(), Type::Bigint);
1391 {
1392 let o = res.try_move::<BigintRef>().unwrap();
1393 assert_eq!(o.sign(), Sign::Negative);
1394 assert_eq!(o.items(), &[1]);
1395 }
1396
1397 let a_ref = from_u64(Global(), Sign::Negative, 1);
1398 let a = a_ref.deref();
1399 let not_a: BigintRef = not(Global(), a).to_ref();
1400 let res = A::move_from(not_a);
1401 assert_eq!(res.get_type(), Type::Bigint);
1402 {
1403 let o = res.try_move::<BigintRef>().unwrap();
1404 assert!(o.items().is_empty());
1405 }
1406
1407 let a_ref = new_bigint(Global(), Sign::Positive, [1, 5, 9]);
1408 let a = a_ref.deref();
1409 let not_a: BigintRef = not(Global(), a).to_ref();
1410 let res = A::move_from(not_a);
1411 assert_eq!(res.get_type(), Type::Bigint);
1412 {
1413 let o = res.try_move::<BigintRef>().unwrap();
1414 assert_eq!(o.sign(), Sign::Negative);
1415 assert_eq!(o.items(), &[2, 5, 9]);
1416 }
1417
1418 let a_ref = new_bigint(Global(), Sign::Negative, [1, 5, 9]);
1419 let a = a_ref.deref();
1420 let not_a: BigintRef = not(Global(), a).to_ref();
1421 let res = A::move_from(not_a);
1422 assert_eq!(res.get_type(), Type::Bigint);
1423 {
1424 let o = res.try_move::<BigintRef>().unwrap();
1425 assert_eq!(o.sign(), Sign::Positive);
1426 assert_eq!(o.items(), &[0, 5, 9]);
1427 }
1428
1429 let a_ref = new_bigint(Global(), Sign::Negative, [0, 1]);
1430 let a = a_ref.deref();
1431 let not_a: BigintRef = not(Global(), a).to_ref();
1432 let res = A::move_from(not_a);
1433 assert_eq!(res.get_type(), Type::Bigint);
1434 {
1435 let o = res.try_move::<BigintRef>().unwrap();
1436 assert_eq!(o.sign(), Sign::Positive);
1437 assert_eq!(o.items(), &[u64::MAX]);
1438 }
1439 }
1440
1441 #[test]
1442 #[wasm_bindgen_test]
1443 fn test_mul() {
1444 type A = Any<Global>;
1445 type BigintRef = JsBigintRef<Global>;
1446
1447 let a_ref = from_u64(Global(), Sign::Positive, 1);
1448 let b_ref = from_u64(Global(), Sign::Negative, 1);
1449 let zero_ref = zero(Global());
1450 let a = a_ref.deref();
1451 let b = b_ref.deref();
1452 let z = zero_ref.deref();
1453
1454 let product: BigintRef = mul(Global(), a, z).to_ref();
1455 let res = A::move_from(product);
1456 assert_eq!(res.get_type(), Type::Bigint);
1457 {
1458 let o = res.try_move::<BigintRef>().unwrap();
1459 assert!(o.items().is_empty());
1460 }
1461
1462 let product: BigintRef = mul(Global(), z, a).to_ref();
1463 let res = A::move_from(product);
1464 assert_eq!(res.get_type(), Type::Bigint);
1465 {
1466 let o = res.try_move::<BigintRef>().unwrap();
1467 assert!(o.items().is_empty());
1468 }
1469
1470 let product: BigintRef = mul(Global(), b, z).to_ref();
1471 let res = A::move_from(product);
1472 assert_eq!(res.get_type(), Type::Bigint);
1473 {
1474 let o = res.try_move::<BigintRef>().unwrap();
1475 assert!(o.items().is_empty());
1476 }
1477
1478 let product: BigintRef = mul(Global(), z, b).to_ref();
1479 let res = A::move_from(product);
1480 assert_eq!(res.get_type(), Type::Bigint);
1481 {
1482 let o = res.try_move::<BigintRef>().unwrap();
1483 assert!(o.items().is_empty());
1484 }
1485
1486 let product: BigintRef = mul(Global(), a, b).to_ref();
1487 let res = A::move_from(product);
1488 assert_eq!(res.get_type(), Type::Bigint);
1489 {
1490 let o = res.try_move::<BigintRef>().unwrap();
1491 assert_eq!(o.sign(), Sign::Negative);
1492 assert_eq!(o.items(), &[1]);
1493 }
1494
1495 let a_ref = new_bigint(Global(), Sign::Positive, [1, 2, 3, 4]);
1496 let b_ref = new_bigint(Global(), Sign::Positive, [5, 6, 7]);
1497 let a = a_ref.deref();
1498 let b = b_ref.deref();
1499 let product: BigintRef = mul(Global(), a, b).to_ref();
1500 let res = A::move_from(product);
1501 assert_eq!(res.get_type(), Type::Bigint);
1502 {
1503 let o = res.try_move::<BigintRef>().unwrap();
1504 assert_eq!(o.sign(), Sign::Positive);
1505 assert_eq!(o.items(), &[5, 16, 34, 52, 45, 28]);
1506 }
1507
1508 let a_ref = from_u64(Global(), Sign::Negative, u64::MAX);
1509 let b_ref = from_u64(Global(), Sign::Negative, u64::MAX);
1510 let a = a_ref.deref();
1511 let b = b_ref.deref();
1512 let product: BigintRef = mul(Global(), a, b).to_ref();
1513 let res = A::move_from(product);
1514 assert_eq!(res.get_type(), Type::Bigint);
1515 {
1516 let o = res.try_move::<BigintRef>().unwrap();
1517 assert_eq!(o.sign(), Sign::Positive);
1518 assert_eq!(o.items(), &[1, u64::MAX - 1]);
1519 }
1520
1521 let a_ref = new_bigint(Global(), Sign::Negative, [u64::MAX, u64::MAX, u64::MAX]);
1522 let b_ref = from_u64(Global(), Sign::Negative, u64::MAX);
1523 let a = a_ref.deref();
1524 let b = b_ref.deref();
1525 let product: BigintRef = mul(Global(), a, b).to_ref();
1526 let res = A::move_from(product);
1527 assert_eq!(res.get_type(), Type::Bigint);
1528 {
1529 let o = res.try_move::<BigintRef>().unwrap();
1530 assert_eq!(o.sign(), Sign::Positive);
1531 assert_eq!(o.items(), &[1, u64::MAX, u64::MAX, u64::MAX - 1]);
1532 }
1533 }
1534
1535 #[test]
1536 #[should_panic(expected = "attempt to divide by zero")]
1537 #[wasm_bindgen_test]
1538 fn test_div_by_zero() {
1539 let a_ref = from_u64(Global(), Sign::Positive, 1);
1540 let b_ref = zero(Global());
1541 let a = a_ref.deref();
1542 let b = b_ref.deref();
1543 let _ = div_mod(Global(), a, b);
1544 }
1545
1546 #[test]
1547 #[should_panic(expected = "attempt to divide by zero")]
1548 #[wasm_bindgen_test]
1549 fn test_div_zero_by_zero() {
1550 let a_ref = zero(Global());
1551 let b_ref = zero(Global());
1552 let a = a_ref.deref();
1553 let b = b_ref.deref();
1554 let _ = div_mod(Global(), a, b);
1555 }
1556
1557 #[test]
1558 #[wasm_bindgen_test]
1559 fn test_div() {
1560 type A = Any<Global>;
1561 type BigintRef = JsBigintRef<Global>;
1562
1563 let a_ref = from_u64(Global(), Sign::Positive, 2);
1564 let b_ref = from_u64(Global(), Sign::Positive, 7);
1565 let a = a_ref.deref();
1566 let b = b_ref.deref();
1567 let (d, m) = div_mod(Global(), a, b);
1568 let d_ref = d.to_ref();
1569 let d_res = A::move_from(d_ref);
1570 assert_eq!(d_res.get_type(), Type::Bigint);
1571 {
1572 let o = d_res.try_move::<BigintRef>().unwrap();
1573 assert_eq!(o.sign(), Sign::Positive);
1574 assert!(o.items().is_empty());
1575 }
1576 let m_ref = m.to_ref();
1577 let m_res = A::move_from(m_ref);
1578 assert_eq!(m_res.get_type(), Type::Bigint);
1579 {
1580 let o = m_res.try_move::<BigintRef>().unwrap();
1581 assert_eq!(o.sign(), Sign::Positive);
1582 assert_eq!(o.items(), &[7]);
1583 }
1584
1585 let a_ref = from_u64(Global(), Sign::Positive, 7);
1586 let b_ref = from_u64(Global(), Sign::Positive, 2);
1587 let a = a_ref.deref();
1588 let b = b_ref.deref();
1589 let (d, m) = div_mod(Global(), a, b);
1590 let d_ref = d.to_ref();
1591 let d_res = A::move_from(d_ref);
1592 assert_eq!(d_res.get_type(), Type::Bigint);
1593 {
1594 let o = d_res.try_move::<BigintRef>().unwrap();
1595 assert_eq!(o.sign(), Sign::Positive);
1596 assert_eq!(o.items(), &[3]);
1597 }
1598 let m_ref = m.to_ref();
1599 let m_res = A::move_from(m_ref);
1600 assert_eq!(m_res.get_type(), Type::Bigint);
1601 {
1602 let o = m_res.try_move::<BigintRef>().unwrap();
1603 assert_eq!(o.sign(), Sign::Positive);
1604 assert_eq!(o.items(), &[1]);
1605 }
1606
1607 let a_ref = new_bigint(Global(), Sign::Negative, [1, 1]);
1608 let b_ref = from_u64(Global(), Sign::Negative, 1);
1609 let a = a_ref.deref();
1610 let b = b_ref.deref();
1611 let (d, m) = div_mod(Global(), a, b);
1612 let d_ref = d.to_ref();
1613 let d_res = A::move_from(d_ref);
1614 assert_eq!(d_res.get_type(), Type::Bigint);
1615 {
1616 let o = d_res.try_move::<BigintRef>().unwrap();
1617 assert_eq!(o.sign(), Sign::Positive);
1618 assert_eq!(o.items(), &[1, 1]);
1619 }
1620 let m_ref = m.to_ref();
1621 let m_res = A::move_from(m_ref);
1622 assert_eq!(m_res.get_type(), Type::Bigint);
1623 {
1624 let o = m_res.try_move::<BigintRef>().unwrap();
1625 assert_eq!(o.sign(), Sign::Positive);
1626 assert!(o.items().is_empty());
1627 }
1628
1629 let a_ref = new_bigint(Global(), Sign::Positive, [7, 5]);
1630 let b_ref = new_bigint(Global(), Sign::Negative, [0, 3]);
1631 let a = a_ref.deref();
1632 let b = b_ref.deref();
1633 let (d, m) = div_mod(Global(), a, b);
1634 let d_ref = d.to_ref();
1635 let d_res = A::move_from(d_ref);
1636 assert_eq!(d_res.get_type(), Type::Bigint);
1637 {
1638 let o = d_res.try_move::<BigintRef>().unwrap();
1639 assert_eq!(o.sign(), Sign::Negative);
1640 assert_eq!(o.items(), &[1]);
1641 }
1642 let m_ref = m.to_ref();
1643 let m_res = A::move_from(m_ref);
1644 assert_eq!(m_res.get_type(), Type::Bigint);
1645 {
1646 let o = m_res.try_move::<BigintRef>().unwrap();
1647 assert_eq!(o.sign(), Sign::Negative);
1648 assert_eq!(o.items(), &[7, 2]);
1649 }
1650 }
1651
1652 #[test]
1653 #[should_panic(expected = "maximum bigint size exceeded")]
1654 #[wasm_bindgen_test]
1655 fn test_pow_overflow() {
1656 let a_ref = from_u64(Global(), Sign::Positive, 5);
1657 let b_ref = new_bigint(Global(), Sign::Positive, [100, 100]);
1658 let a = a_ref.deref();
1659 let b = b_ref.deref();
1660 let _ = pow(Global(), a, b);
1661 }
1662
1663 #[test]
1664 #[should_panic(expected = "exponent must be positive")]
1665 #[wasm_bindgen_test]
1666 fn test_pow_negative() {
1667 let a_ref = from_u64(Global(), Sign::Positive, 5);
1668 let b_ref = new_bigint(Global(), Sign::Negative, [5]);
1669 let a = a_ref.deref();
1670 let b = b_ref.deref();
1671 let _ = pow(Global(), a, b);
1672 }
1673
1674 #[test]
1675 #[wasm_bindgen_test]
1676 fn test_pow() {
1677 type A = Any<Global>;
1678 type BigintRef = JsBigintRef<Global>;
1679
1680 let a_ref = from_u64(Global(), Sign::Positive, 100);
1681 let b_ref = zero(Global());
1682 let a = a_ref.deref();
1683 let b = b_ref.deref();
1684 let c = pow(Global(), a, b).to_ref();
1685 let result = A::move_from(c);
1686 assert_eq!(result.get_type(), Type::Bigint);
1687 {
1688 let o = result.try_move::<BigintRef>().unwrap();
1689 assert_eq!(o.sign(), Sign::Positive);
1690 assert_eq!(o.items(), &[1]);
1691 }
1692
1693 let a_ref = from_u64(Global(), Sign::Positive, 2);
1694 let b_ref = from_u64(Global(), Sign::Positive, 7);
1695 let a = a_ref.deref();
1696 let b = b_ref.deref();
1697 let c = pow(Global(), a, b).to_ref();
1698 let result = A::move_from(c);
1699 assert_eq!(result.get_type(), Type::Bigint);
1700 {
1701 let o = result.try_move::<BigintRef>().unwrap();
1702 assert_eq!(o.sign(), Sign::Positive);
1703 assert_eq!(o.items(), &[128]);
1704 }
1705
1706 let a_ref = from_u64(Global(), Sign::Negative, 2);
1707 let b_ref = from_u64(Global(), Sign::Positive, 7);
1708 let a = a_ref.deref();
1709 let b = b_ref.deref();
1710 let c = pow(Global(), a, b).to_ref();
1711 let result = A::move_from(c);
1712 assert_eq!(result.get_type(), Type::Bigint);
1713 {
1714 let o = result.try_move::<BigintRef>().unwrap();
1715 assert_eq!(o.sign(), Sign::Negative);
1716 assert_eq!(o.items(), &[128]);
1717 }
1718
1719 let a_ref = from_u64(Global(), Sign::Positive, 5);
1720 let b_ref = from_u64(Global(), Sign::Positive, 4);
1721 let a = a_ref.deref();
1722 let b = b_ref.deref();
1723 let c = pow(Global(), a, b).to_ref();
1724 let result = A::move_from(c);
1725 assert_eq!(result.get_type(), Type::Bigint);
1726 {
1727 let o = result.try_move::<BigintRef>().unwrap();
1728 assert_eq!(o.sign(), Sign::Positive);
1729 assert_eq!(o.items(), &[625]);
1730 }
1731
1732 let a_ref = from_u64(Global(), Sign::Negative, 5);
1733 let b_ref = from_u64(Global(), Sign::Positive, 4);
1734 let a = a_ref.deref();
1735 let b = b_ref.deref();
1736 let c = pow(Global(), a, b).to_ref();
1737 let result = A::move_from(c);
1738 assert_eq!(result.get_type(), Type::Bigint);
1739 {
1740 let o = result.try_move::<BigintRef>().unwrap();
1741 assert_eq!(o.sign(), Sign::Positive);
1742 assert_eq!(o.items(), &[625]);
1743 }
1744
1745 let a_ref = zero(Global());
1746 let b_ref = zero(Global());
1747 let a = a_ref.deref();
1748 let b = b_ref.deref();
1749 let c = pow(Global(), a, b).to_ref();
1750 let result = A::move_from(c);
1751 assert_eq!(result.get_type(), Type::Bigint);
1752 {
1753 let o = result.try_move::<BigintRef>().unwrap();
1754 assert_eq!(o.sign(), Sign::Positive);
1755 assert_eq!(o.items(), &[1]);
1756 }
1757
1758 let a_ref = from_u64(Global(), Sign::Positive, 1);
1759 let b_ref = zero(Global());
1760 let a = a_ref.deref();
1761 let b = b_ref.deref();
1762 let c = pow(Global(), a, b).to_ref();
1763 let result = A::move_from(c);
1764 assert_eq!(result.get_type(), Type::Bigint);
1765 {
1766 let o = result.try_move::<BigintRef>().unwrap();
1767 assert_eq!(o.sign(), Sign::Positive);
1768 assert_eq!(o.items(), &[1]);
1769 }
1770
1771 let a_ref = from_u64(Global(), Sign::Positive, 1);
1772 let b_ref = new_bigint(Global(), Sign::Positive, [100, 100]);
1773 let a = a_ref.deref();
1774 let b = b_ref.deref();
1775 let c = pow(Global(), a, b).to_ref();
1776 let result = A::move_from(c);
1777 assert_eq!(result.get_type(), Type::Bigint);
1778 {
1779 let o = result.try_move::<BigintRef>().unwrap();
1780 assert_eq!(o.sign(), Sign::Positive);
1781 assert_eq!(o.items(), &[1]);
1782 }
1783 }
1784}