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