/ utilities / src / biginteger / bigint_256.rs
bigint_256.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm 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  
 16  use std::io::{Read, Result as IoResult, Write};
 17  
 18  use crate::{
 19      FromBits,
 20      FromBytes,
 21      ToBits,
 22      ToBytes,
 23      biginteger::BigInteger,
 24      bititerator::{BitIteratorBE, BitIteratorLE},
 25  };
 26  
 27  use anyhow::Result;
 28  use core::fmt::{Debug, Display};
 29  use num_bigint::BigUint;
 30  use rand::{
 31      Rng,
 32      distributions::{Distribution, Standard},
 33  };
 34  use zeroize::Zeroize;
 35  
 36  #[derive(Copy, Clone, PartialEq, Eq, Default, Hash, Zeroize)]
 37  pub struct BigInteger256(pub [u64; 4]);
 38  
 39  impl BigInteger256 {
 40      pub const fn new(value: [u64; 4]) -> Self {
 41          BigInteger256(value)
 42      }
 43  }
 44  
 45  impl crate::biginteger::BigInteger for BigInteger256 {
 46      const NUM_LIMBS: usize = 4;
 47  
 48      #[inline]
 49      fn add_nocarry(&mut self, other: &Self) -> bool {
 50          #[cfg(target_arch = "x86_64")]
 51          unsafe {
 52              use core::arch::x86_64::_addcarry_u64;
 53              let mut carry = 0;
 54              carry = _addcarry_u64(carry, self.0[0], other.0[0], &mut self.0[0]);
 55              carry = _addcarry_u64(carry, self.0[1], other.0[1], &mut self.0[1]);
 56              carry = _addcarry_u64(carry, self.0[2], other.0[2], &mut self.0[2]);
 57              carry = _addcarry_u64(carry, self.0[3], other.0[3], &mut self.0[3]);
 58              carry != 0
 59          }
 60          #[cfg(not(target_arch = "x86_64"))]
 61          {
 62              let mut carry = 0;
 63              carry = super::arithmetic::adc(&mut self.0[0], other.0[0], carry);
 64              carry = super::arithmetic::adc(&mut self.0[1], other.0[1], carry);
 65              carry = super::arithmetic::adc(&mut self.0[2], other.0[2], carry);
 66              carry = super::arithmetic::adc(&mut self.0[3], other.0[3], carry);
 67              carry != 0
 68          }
 69      }
 70  
 71      #[inline]
 72      fn sub_noborrow(&mut self, other: &Self) -> bool {
 73          #[cfg(target_arch = "x86_64")]
 74          unsafe {
 75              use core::arch::x86_64::_subborrow_u64;
 76              let mut borrow = 0;
 77              borrow = _subborrow_u64(borrow, self.0[0], other.0[0], &mut self.0[0]);
 78              borrow = _subborrow_u64(borrow, self.0[1], other.0[1], &mut self.0[1]);
 79              borrow = _subborrow_u64(borrow, self.0[2], other.0[2], &mut self.0[2]);
 80              borrow = _subborrow_u64(borrow, self.0[3], other.0[3], &mut self.0[3]);
 81              borrow != 0
 82          }
 83          #[cfg(not(target_arch = "x86_64"))]
 84          {
 85              let mut borrow = 0;
 86              borrow = super::arithmetic::sbb(&mut self.0[0], other.0[0], borrow);
 87              borrow = super::arithmetic::sbb(&mut self.0[1], other.0[1], borrow);
 88              borrow = super::arithmetic::sbb(&mut self.0[2], other.0[2], borrow);
 89              borrow = super::arithmetic::sbb(&mut self.0[3], other.0[3], borrow);
 90              borrow != 0
 91          }
 92      }
 93  
 94      #[inline]
 95      fn mul2(&mut self) {
 96          let mut last = 0;
 97          for i in &mut self.0 {
 98              let tmp = *i >> 63;
 99              *i <<= 1;
100              *i |= last;
101              last = tmp;
102          }
103      }
104  
105      #[inline]
106      fn muln(&mut self, mut n: u32) {
107          if n >= 64 * 4 {
108              *self = Self::from(0);
109              return;
110          }
111          while n >= 64 {
112              let mut t = 0;
113              for i in &mut self.0 {
114                  std::mem::swap(&mut t, i);
115              }
116              n -= 64;
117          }
118          if n > 0 {
119              let mut t = 0;
120              for i in &mut self.0 {
121                  let t2 = *i >> (64 - n);
122                  *i <<= n;
123                  *i |= t;
124                  t = t2;
125              }
126          }
127      }
128  
129      #[inline]
130      fn div2(&mut self) {
131          let mut t = 0;
132          for i in self.0.iter_mut().rev() {
133              let t2 = *i << 63;
134              *i >>= 1;
135              *i |= t;
136              t = t2;
137          }
138      }
139  
140      #[inline]
141      fn divn(&mut self, mut n: u32) {
142          if n >= 64 * 4 {
143              *self = Self::from(0);
144              return;
145          }
146          while n >= 64 {
147              let mut t = 0;
148              for i in self.0.iter_mut().rev() {
149                  std::mem::swap(&mut t, i);
150              }
151              n -= 64;
152          }
153          if n > 0 {
154              let mut t = 0;
155              for i in self.0.iter_mut().rev() {
156                  let t2 = *i << (64 - n);
157                  *i >>= n;
158                  *i |= t;
159                  t = t2;
160              }
161          }
162      }
163  
164      #[inline]
165      fn is_odd(&self) -> bool {
166          self.0[0] & 1 == 1
167      }
168  
169      #[inline]
170      fn is_even(&self) -> bool {
171          !self.is_odd()
172      }
173  
174      #[inline]
175      fn is_zero(&self) -> bool {
176          self.0.iter().all(|&e| e == 0)
177      }
178  
179      #[inline]
180      fn num_bits(&self) -> u32 {
181          let mut ret = 4 * 64;
182          for i in self.0.iter().rev() {
183              let leading = i.leading_zeros();
184              ret -= leading;
185              if leading != 64 {
186                  break;
187              }
188          }
189          ret
190      }
191  
192      #[inline]
193      fn get_bit(&self, i: usize) -> bool {
194          if i >= 64 * 4 {
195              false
196          } else {
197              let limb = i / 64;
198              let bit = i - (64 * limb);
199              (self.0[limb] & (1 << bit)) != 0
200          }
201      }
202  
203      #[inline]
204      fn to_biguint(&self) -> num_bigint::BigUint {
205          BigUint::from_bytes_le(&self.to_bytes_le().unwrap())
206      }
207  
208      #[inline]
209      fn find_wnaf(&self) -> Vec<i64> {
210          let mut res = Vec::new();
211          let mut e = *self;
212          while !e.is_zero() {
213              let z: i64;
214              if e.is_odd() {
215                  z = 2 - (e.0[0] % 4) as i64;
216                  if z >= 0 {
217                      e.sub_noborrow(&Self::from(z as u64));
218                  } else {
219                      e.add_nocarry(&Self::from((-z) as u64));
220                  }
221              } else {
222                  z = 0;
223              }
224              res.push(z);
225              e.div2();
226          }
227          res
228      }
229  }
230  
231  impl ToBits for BigInteger256 {
232      #[doc = " Returns `self` as a boolean array in little-endian order, with trailing zeros."]
233      fn write_bits_le(&self, vec: &mut Vec<bool>) {
234          let iter = BitIteratorLE::new(self);
235          vec.reserve(iter.len());
236          vec.extend(iter);
237      }
238  
239      #[doc = " Returns `self` as a boolean array in big-endian order, with leading zeros."]
240      fn write_bits_be(&self, vec: &mut Vec<bool>) {
241          let iter = BitIteratorBE::new(self);
242          vec.reserve(iter.len());
243          vec.extend(iter);
244      }
245  }
246  
247  impl FromBits for BigInteger256 {
248      #[doc = " Returns a `BigInteger` by parsing a slice of bits in little-endian format"]
249      #[doc = " and transforms it into a slice of little-endian u64 elements."]
250      fn from_bits_le(bits: &[bool]) -> Result<Self> {
251          let mut res = Self::default();
252          for (i, bits64) in bits.chunks(64).enumerate() {
253              let mut acc: u64 = 0;
254              for bit in bits64.iter().rev() {
255                  acc <<= 1;
256                  acc += *bit as u64;
257              }
258              res.0[i] = acc;
259          }
260          Ok(res)
261      }
262  
263      #[doc = " Returns a `BigInteger` by parsing a slice of bits in big-endian format"]
264      #[doc = " and transforms it into a slice of little-endian u64 elements."]
265      fn from_bits_be(bits: &[bool]) -> Result<Self> {
266          let mut res = Self::default();
267          for (i, bits64) in bits.rchunks(64).enumerate() {
268              let mut acc: u64 = 0;
269              for bit in bits64.iter() {
270                  acc <<= 1;
271                  acc += *bit as u64;
272              }
273              res.0[i] = acc;
274          }
275          Ok(res)
276      }
277  }
278  
279  impl ToBytes for BigInteger256 {
280      #[inline]
281      fn write_le<W: Write>(&self, writer: W) -> IoResult<()> {
282          let mut arr = [0u8; 8 * 4];
283          for (i, num) in self.0.iter().enumerate() {
284              arr[i * 8..(i + 1) * 8].copy_from_slice(&num.to_le_bytes());
285          }
286          arr.write_le(writer)
287      }
288  }
289  
290  impl FromBytes for BigInteger256 {
291      #[inline]
292      fn read_le<R: Read>(reader: R) -> IoResult<Self> {
293          <[u64; 4]>::read_le(reader).map(Self::new)
294      }
295  }
296  
297  impl Debug for BigInteger256 {
298      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299          for i in self.0.iter().rev() {
300              write!(f, "{:016X}", *i)?;
301          }
302          Ok(())
303      }
304  }
305  
306  impl Display for BigInteger256 {
307      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308          write!(f, "{}", self.to_biguint())
309      }
310  }
311  
312  impl Ord for BigInteger256 {
313      #[inline]
314      #[allow(clippy::comparison_chain)]
315      fn cmp(&self, other: &Self) -> std::cmp::Ordering {
316          for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
317              if a < b {
318                  return std::cmp::Ordering::Less;
319              } else if a > b {
320                  return std::cmp::Ordering::Greater;
321              }
322          }
323          std::cmp::Ordering::Equal
324      }
325  }
326  
327  impl PartialOrd for BigInteger256 {
328      #[inline]
329      fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
330          Some(self.cmp(other))
331      }
332  }
333  
334  impl Distribution<BigInteger256> for Standard {
335      fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BigInteger256 {
336          BigInteger256(rng.r#gen())
337      }
338  }
339  
340  impl AsMut<[u64]> for BigInteger256 {
341      #[inline]
342      fn as_mut(&mut self) -> &mut [u64] {
343          &mut self.0
344      }
345  }
346  
347  impl AsRef<[u64]> for BigInteger256 {
348      #[inline]
349      fn as_ref(&self) -> &[u64] {
350          &self.0
351      }
352  }
353  
354  impl From<u64> for BigInteger256 {
355      #[inline]
356      fn from(val: u64) -> BigInteger256 {
357          let mut repr = Self::default();
358          repr.0[0] = val;
359          repr
360      }
361  }