snarkvm_utilities/biginteger/
mod.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::{FromBits, FromBytes, ToBits, ToBytes, rand::Uniform};
17
18use num_bigint::BigUint;
19use std::fmt::{Debug, Display};
20
21mod bigint_256;
22pub use bigint_256::*;
23
24mod bigint_384;
25pub use bigint_384::*;
26
27#[cfg(test)]
28mod tests;
29
30/// This defines a `BigInteger`, a smart wrapper around a
31/// sequence of `u64` limbs, least-significant digit first.
32pub trait BigInteger:
33    ToBits
34    + FromBits
35    + ToBytes
36    + FromBytes
37    + Copy
38    + Clone
39    + Debug
40    + Default
41    + Display
42    + Eq
43    + Ord
44    + Send
45    + Sized
46    + Sync
47    + 'static
48    + Uniform
49    + AsMut<[u64]>
50    + AsRef<[u64]>
51    + From<u64>
52{
53    /// The number of limbs used in this BigInteger.
54    const NUM_LIMBS: usize;
55
56    /// Add another representation to this one, returning the carry bit.
57    fn add_nocarry(&mut self, other: &Self) -> bool;
58
59    /// Subtract another representation from this one, returning the borrow bit.
60    fn sub_noborrow(&mut self, other: &Self) -> bool;
61
62    /// Performs a leftwise bitshift of this number, effectively multiplying
63    /// it by 2. Overflow is ignored.
64    fn mul2(&mut self);
65
66    /// Performs a leftwise bitshift of this number by some amount.
67    fn muln(&mut self, amt: u32);
68
69    /// Performs a rightwise bitshift of this number, effectively dividing
70    /// it by 2.
71    fn div2(&mut self);
72
73    /// Performs a rightwise bitshift of this number by some amount.
74    fn divn(&mut self, amt: u32);
75
76    /// Returns true iff this number is odd.
77    fn is_odd(&self) -> bool;
78
79    /// Returns true if this number is even.
80    fn is_even(&self) -> bool;
81
82    /// Returns true if this number is zero.
83    fn is_zero(&self) -> bool;
84
85    /// Compute the number of bits needed to encode this number. Always a
86    /// multiple of 64.
87    fn num_bits(&self) -> u32;
88
89    /// Compute the `i`-th bit of `self`.
90    fn get_bit(&self, i: usize) -> bool;
91
92    /// Returns the BigUint representation.
93    fn to_biguint(&self) -> BigUint;
94
95    /// Returns a vector for wnaf.
96    fn find_wnaf(&self) -> Vec<i64>;
97}
98
99pub mod arithmetic {
100    /// set a = a + b + carry, and return the new carry value.
101    #[inline(always)]
102    pub fn adc(a: &mut u64, b: u64, carry: u64) -> u64 {
103        let tmp = u128::from(*a) + u128::from(b) + u128::from(carry);
104        *a = tmp as u64;
105        (tmp >> 64) as u64
106    }
107
108    /// set a = a - b - borrow, and return the new borrow value.
109    #[inline(always)]
110    pub fn sbb(a: &mut u64, b: u64, borrow: u64) -> u64 {
111        let tmp = (1u128 << 64) + u128::from(*a) - u128::from(b) - u128::from(borrow);
112        let carry = u64::from(tmp >> 64 == 0);
113        *a = tmp as u64;
114        carry
115    }
116
117    /// Calculate a + (b * c) + carry, returning the least significant digit
118    /// and setting carry to the most significant digit.
119    #[inline(always)]
120    pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
121        let tmp = (u128::from(a)) + u128::from(b) * u128::from(c) + u128::from(*carry);
122
123        *carry = (tmp >> 64) as u64;
124
125        tmp as u64
126    }
127
128    /// Calculate a + b * c, returning the lower 64 bits of the result and setting
129    /// `carry` to the upper 64 bits.
130    #[inline(always)]
131    pub fn mac(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
132        let tmp = (u128::from(a)) + u128::from(b) * u128::from(c);
133
134        *carry = (tmp >> 64) as u64;
135
136        tmp as u64
137    }
138
139    /// Calculate a + b * c, discarding the lower 64 bits of the result and setting
140    /// `carry` to the upper 64 bits.
141    #[inline(always)]
142    pub fn mac_discard(a: u64, b: u64, c: u64, carry: &mut u64) {
143        let tmp = (u128::from(a)) + u128::from(b) * u128::from(c);
144
145        *carry = (tmp >> 64) as u64;
146    }
147}