ark_ff/biginteger/
arithmetic.rs1use ark_std::{vec, vec::Vec};
2
3macro_rules! adc {
4 ($a:expr, $b:expr, &mut $carry:expr$(,)?) => {{
5 let tmp = ($a as u128) + ($b as u128) + ($carry as u128);
6 $carry = (tmp >> 64) as u64;
7 tmp as u64
8 }};
9}
10
11#[inline(always)]
13#[allow(unused_mut)]
14#[doc(hidden)]
15pub fn adc(a: &mut u64, b: u64, carry: u64) -> u64 {
16 let tmp = *a as u128 + b as u128 + carry as u128;
17 *a = tmp as u64;
18 (tmp >> 64) as u64
19}
20
21#[inline(always)]
23#[allow(unused_mut)]
24#[doc(hidden)]
25pub fn adc_for_add_with_carry(a: &mut u64, b: u64, carry: u8) -> u8 {
26 #[cfg(all(target_arch = "x86_64", feature = "asm"))]
27 #[allow(unsafe_code)]
28 unsafe {
29 use core::arch::x86_64::_addcarry_u64;
30 _addcarry_u64(carry, *a, b, a)
31 }
32 #[cfg(not(all(target_arch = "x86_64", feature = "asm")))]
33 {
34 let tmp = *a as u128 + b as u128 + carry as u128;
35 *a = tmp as u64;
36 (tmp >> 64) as u8
37 }
38}
39
40#[inline(always)]
42#[doc(hidden)]
43pub fn adc_no_carry(a: u64, b: u64, carry: &mut u64) -> u64 {
44 let tmp = a as u128 + b as u128 + *carry as u128;
45 tmp as u64
46}
47
48#[macro_export]
49macro_rules! sbb {
50 ($a:expr, $b:expr, &mut $borrow:expr$(,)?) => {{
51 let tmp = (1u128 << 64) + ($a as u128) - ($b as u128) - ($borrow as u128);
52 $borrow = if tmp >> 64 == 0 { 1 } else { 0 };
53 tmp as u64
54 }};
55}
56
57#[inline(always)]
59#[allow(unused_mut)]
60pub(crate) fn sbb(a: &mut u64, b: u64, borrow: u64) -> u64 {
61 let tmp = (1u128 << 64) + (*a as u128) - (b as u128) - (borrow as u128);
62 *a = tmp as u64;
63 (tmp >> 64 == 0) as u64
64}
65
66#[inline(always)]
68#[allow(unused_mut)]
69#[doc(hidden)]
70pub fn sbb_for_sub_with_borrow(a: &mut u64, b: u64, borrow: u8) -> u8 {
71 #[cfg(all(target_arch = "x86_64", feature = "asm"))]
72 #[allow(unsafe_code)]
73 unsafe {
74 use core::arch::x86_64::_subborrow_u64;
75 _subborrow_u64(borrow, *a, b, a)
76 }
77 #[cfg(not(all(target_arch = "x86_64", feature = "asm")))]
78 {
79 let tmp = (1u128 << 64) + (*a as u128) - (b as u128) - (borrow as u128);
80 *a = tmp as u64;
81 u8::from(tmp >> 64 == 0)
82 }
83}
84
85#[inline(always)]
88#[doc(hidden)]
89pub fn mac(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
90 let tmp = (a as u128) + (b as u128 * c as u128);
91 *carry = (tmp >> 64) as u64;
92 tmp as u64
93}
94
95#[inline(always)]
98#[doc(hidden)]
99pub fn mac_discard(a: u64, b: u64, c: u64, carry: &mut u64) {
100 let tmp = (a as u128) + (b as u128 * c as u128);
101 *carry = (tmp >> 64) as u64;
102}
103
104macro_rules! mac_with_carry {
105 ($a:expr, $b:expr, $c:expr, &mut $carry:expr$(,)?) => {{
106 let tmp = ($a as u128) + ($b as u128 * $c as u128) + ($carry as u128);
107 $carry = (tmp >> 64) as u64;
108 tmp as u64
109 }};
110}
111
112macro_rules! mac {
113 ($a:expr, $b:expr, $c:expr, &mut $carry:expr$(,)?) => {{
114 let tmp = ($a as u128) + ($b as u128 * $c as u128);
115 $carry = (tmp >> 64) as u64;
116 tmp as u64
117 }};
118}
119
120#[inline(always)]
123#[doc(hidden)]
124pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
125 let tmp = (a as u128) + (b as u128 * c as u128) + (*carry as u128);
126 *carry = (tmp >> 64) as u64;
127 tmp as u64
128}
129
130pub fn find_naf(num: &[u64]) -> Vec<i8> {
132 let is_zero = |num: &[u64]| num.iter().all(|x| *x == 0u64);
133 let is_odd = |num: &[u64]| num[0] & 1 == 1;
134 let sub_noborrow = |num: &mut [u64], z: u64| {
135 let mut other = vec![0u64; num.len()];
136 other[0] = z;
137 let mut borrow = 0;
138
139 for (a, b) in num.iter_mut().zip(other) {
140 borrow = sbb(a, b, borrow);
141 }
142 };
143 let add_nocarry = |num: &mut [u64], z: u64| {
144 let mut other = vec![0u64; num.len()];
145 other[0] = z;
146 let mut carry = 0;
147
148 for (a, b) in num.iter_mut().zip(other) {
149 carry = adc(a, b, carry);
150 }
151 };
152 let div2 = |num: &mut [u64]| {
153 let mut t = 0;
154 for i in num.iter_mut().rev() {
155 let t2 = *i << 63;
156 *i >>= 1;
157 *i |= t;
158 t = t2;
159 }
160 };
161
162 let mut num = num.to_vec();
163 let mut res = vec![];
164
165 while !is_zero(&num) {
166 let z: i8;
167 if is_odd(&num) {
168 z = 2 - (num[0] % 4) as i8;
169 if z >= 0 {
170 sub_noborrow(&mut num, z as u64)
171 } else {
172 add_nocarry(&mut num, (-z) as u64)
173 }
174 } else {
175 z = 0;
176 }
177 res.push(z);
178 div2(&mut num);
179 }
180
181 res
182}
183
184pub fn find_relaxed_naf(num: &[u64]) -> Vec<i8> {
197 let mut res = find_naf(num);
198
199 let len = res.len();
200 if res[len - 2] == 0 && res[len - 3] == -1 {
201 res[len - 3] = 1;
202 res[len - 2] = 1;
203 res.resize(len - 1, 0);
204 }
205
206 res
207}
208
209#[test]
210fn test_find_relaxed_naf_usefulness() {
211 let vec = find_naf(&[12u64]);
212 assert_eq!(vec.len(), 5);
213
214 let vec = find_relaxed_naf(&[12u64]);
215 assert_eq!(vec.len(), 4);
216}
217
218#[test]
219fn test_find_relaxed_naf_correctness() {
220 use ark_std::{One, UniformRand, Zero};
221 use num_bigint::BigInt;
222
223 let mut rng = ark_std::test_rng();
224
225 for _ in 0..10 {
226 let num = [
227 u64::rand(&mut rng),
228 u64::rand(&mut rng),
229 u64::rand(&mut rng),
230 u64::rand(&mut rng),
231 ];
232 let relaxed_naf = find_relaxed_naf(&num);
233
234 let test = {
235 let mut sum = BigInt::zero();
236 let mut cur = BigInt::one();
237 for v in relaxed_naf {
238 sum += cur.clone() * v;
239 cur *= 2;
240 }
241 sum
242 };
243
244 let test_expected = {
245 let mut sum = BigInt::zero();
246 let mut cur = BigInt::one();
247 for v in num.iter() {
248 sum += cur.clone() * v;
249 cur <<= 64;
250 }
251 sum
252 };
253
254 assert_eq!(test, test_expected);
255 }
256}