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