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