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