nanvm_lib/js/
js_bigint.rs

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}