snarkvm_utilities/biginteger/
bigint_256.rs1use std::io::{Read, Result as IoResult, Write};
17
18use crate::{
19 FromBits,
20 FromBytes,
21 ToBits,
22 ToBytes,
23 biginteger::BigInteger,
24 bititerator::{BitIteratorBE, BitIteratorLE},
25};
26
27use anyhow::Result;
28use core::fmt::{Debug, Display};
29use num_bigint::BigUint;
30use rand::{
31 Rng,
32 distributions::{Distribution, Standard},
33};
34use zeroize::Zeroize;
35
36#[derive(Copy, Clone, PartialEq, Eq, Default, Hash, Zeroize)]
37pub struct BigInteger256(pub [u64; 4]);
38
39impl BigInteger256 {
40 pub const fn new(value: [u64; 4]) -> Self {
41 BigInteger256(value)
42 }
43}
44
45impl 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
231impl 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
247impl 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
279impl 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
290impl 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
297impl 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
306impl Display for BigInteger256 {
307 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308 write!(f, "{}", self.to_biguint())
309 }
310}
311
312impl 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
327impl PartialOrd for BigInteger256 {
328 #[inline]
329 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
330 Some(self.cmp(other))
331 }
332}
333
334impl Distribution<BigInteger256> for Standard {
335 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BigInteger256 {
336 BigInteger256(rng.r#gen())
337 }
338}
339
340impl AsMut<[u64]> for BigInteger256 {
341 #[inline]
342 fn as_mut(&mut self) -> &mut [u64] {
343 &mut self.0
344 }
345}
346
347impl AsRef<[u64]> for BigInteger256 {
348 #[inline]
349 fn as_ref(&self) -> &[u64] {
350 &self.0
351 }
352}
353
354impl 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}