1#[cfg(test)]
7use super::{SuperTrait};
8
9use super::{ArithUtils};
10
11#[allow(non_snake_case)]
13pub fn inverse_butterfly<T>(X: &mut T, Y: &mut T, W: &T, q: &T) where T: ArithUtils<T>{
14 let temp = T::sub_mod(X,Y, q);
15 *X = T::add_mod(X, Y, q);
16 *Y = T::mul_mod(W, &temp, q);
17}
18
19#[allow(non_snake_case)]
21pub fn butterfly<T>(X: &mut T, Y: &mut T, W: &T, q: &T) where T: ArithUtils<T>{
22 let temp = T::mul_mod(Y, W, q);
23 *Y = T::sub_mod(X, &temp, q);
24 *X = T::add_mod(X, &temp, q);
25}
26
27#[allow(non_snake_case)]
30#[cfg(test)]
31pub fn lazy_butterfly<T>(X: &mut T, Y: &mut T, W: u64, Wprime: u64, q: &T, twoq: u64) where T: SuperTrait<T>{
32 let mut xx = X.rep();
33 if xx > twoq{
34 xx -= twoq;
35 }
36 let _qq = super::util::mul_high_word(Wprime, Y.rep());
37 let quo = W.wrapping_mul(Y.rep()) - _qq.wrapping_mul(q.rep());
38 *X = T::from(xx + quo);
40 *Y = T::from(xx + twoq - quo);
42}
43
44#[allow(clippy::many_single_char_names)]
45pub fn lazy_butterfly_u64(mut x: u64, y:u64, w: u64, wprime: u64, q: u64, twoq: u64) -> (u64, u64){
46 if x > twoq{
48 x -= twoq;
49 }
50 let _qq = super::util::mul_high_word(wprime, y);
51 let wy = w.wrapping_mul(y);
52 let qqq = _qq.wrapping_mul(q);
53 let quo;
54 if wy >= qqq {
55 quo = wy - qqq;
56 }
57 else{
58 quo = u64::MAX - qqq + wy + 1;
59 }
60 (x + quo, x + twoq - quo)
61}
62
63#[allow(clippy::many_single_char_names)]
64pub fn lazy_inverse_butterfly_u64(x: u64, y:u64, w: u64, wprime: u64, q: u64, twoq: u64) -> (u64, u64){
65 let mut xx = x+y;
66
67 if xx > twoq {
68 xx -= twoq;
69 }
70 let t = twoq - y + x;
71 let quo = super::util::mul_high_word(wprime, t);
72 let wt = w.wrapping_mul(t);
73 let qquo = quo.wrapping_mul(q);
74 let yy;
75 if wt >= qquo {
76 yy = wt - qquo;
77 }
78 else{
79 yy = u64::MAX - qquo + wt + 1;
80 }
81 (xx, yy)
82}
83
84#[allow(non_snake_case)]
87#[cfg(test)]
88pub(crate) fn lazy_inverse_butterfly<T>(X: &mut T, Y: &mut T, W: u64, Wprime: u64, q: &T) where T: SuperTrait<T>{
89 let mut xx = X.rep() + Y.rep();
90
91 let twoq = 2*q.rep();
92 if xx > twoq {
93 xx -= twoq;
94 }
95 let t = twoq - Y.rep() + X.rep();
96 let quo = super::util::mul_high_word(Wprime, t);
97 let yy = W.wrapping_mul(t) - quo.wrapping_mul(q.rep());
98 *X = T::from(xx);
99 *Y = T::from(yy);
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use super::super::scalar::Scalar;
106
107 fn butterfly_for_test(arr: [u64;4]) -> [u64; 2] {
108 let mut X:Scalar = Scalar::from(arr[0]);
109 let mut Y:Scalar = Scalar::from(arr[1]);
110 let W:Scalar = Scalar::from(arr[2]);
111 let q:Scalar = Scalar::new_modulus(arr[3]);
112
113 butterfly(&mut X, &mut Y, &W, &q);
114 [X.into(), Y.into()]
115 }
116
117 fn inverse_butterfly_for_test(arr: [u64;4]) -> [u64; 2] {
118 let mut X:Scalar = Scalar::from(arr[0]);
119 let mut Y:Scalar = Scalar::from(arr[1]);
120 let W:Scalar = Scalar::from(arr[2]);
121 let q:Scalar = Scalar::new_modulus(arr[3]);
122
123 inverse_butterfly(&mut X, &mut Y, &W, &q);
124 [X.into(), Y.into()]
125 }
126
127 fn lazy_butterfly_for_test(arr: [u64;4]) -> [u64; 2] {
128 let mut X:Scalar = Scalar::from(arr[0]);
129 let mut Y:Scalar = Scalar::from(arr[1]);
130 let W = arr[2];
131 let q:Scalar = Scalar::new_modulus(arr[3]);
132 let Wprime: u64 = super::super::util::compute_harvey_ratio(W, q.rep());
134 let twoq = q.rep() << 1;
135
136 lazy_butterfly(&mut X, &mut Y, W, Wprime, &q, twoq);
137 [X.into(), Y.into()]
138 }
139
140 fn lazy_inverse_butterfly_for_test(arr: [u64;4]) -> [u64; 2] {
141 let mut X:Scalar = Scalar::from(arr[0]);
142 let mut Y:Scalar = Scalar::from(arr[1]);
143 let W = arr[2];
144 let q:Scalar = Scalar::new_modulus(arr[3]);
145 let Wprime: u64 = super::super::util::compute_harvey_ratio(W, q.rep());
147
148 lazy_inverse_butterfly(&mut X, &mut Y, W, Wprime, &q);
149 [X.into(), Y.into()]
150 }
151
152 macro_rules! lazy_butterfly_tests {
153 ($($name:ident: $value:expr,)*) => {
154 $(
155 #[test]
156 fn $name() {
157 let input = $value;
158 let butterfly_out = butterfly_for_test(input);
159 let output = lazy_butterfly_for_test(input);
160 println!("{:?}", butterfly_out);
161 println!("{:?}", output);
162 assert!(output[0] < 4*input[3]);
163 assert!(output[1] < 4*input[3]);
164 assert_eq!((output[1] - butterfly_out[1]) % input[3], 0);
165 assert_eq!((output[0] - butterfly_out[0]) % input[3], 0);
166 }
167 )*
168 }
169 }
170
171 macro_rules! lazy_inverse_butterfly_tests {
172 ($($name:ident: $value:expr,)*) => {
173 $(
174 #[test]
175 fn $name() {
176 let input = $value;
177 let butterfly_out = inverse_butterfly_for_test(input);
178 let output = lazy_inverse_butterfly_for_test(input);
179 println!("{:?}", butterfly_out);
180 println!("{:?}", output);
181 assert!(output[0] < 2*input[3]);
182 assert!(output[1] < 2*input[3]);
183 assert_eq!((output[1] - butterfly_out[1]) % input[3], 0);
184 assert_eq!((output[0] - butterfly_out[0]) % input[3], 0);
185 }
186 )*
187 }
188 }
189
190 macro_rules! inverse_butterfly_tests {
191 ($($name:ident: $value:expr,)*) => {
192 $(
193 #[test]
194 fn $name() {
195 let (input, expected) = $value;
196 assert_eq!(expected, inverse_butterfly_for_test(input));
197 }
198 )*
199 }
200 }
201
202 macro_rules! butterfly_tests {
203 ($($name:ident: $value:expr,)*) => {
204 $(
205 #[test]
206 fn $name() {
207 let (input, expected) = $value;
208 assert_eq!(expected, butterfly_for_test(input));
209 }
210 )*
211 }
212 }
213
214 butterfly_tests! {
215 butterfly_0: ([0u64, 1u64, 0u64, 100u64], [0u64, 0u64]),
216 butterfly_1: ([1u64, 1u64, 1u64, 100u64], [2u64, 0u64]),
217 butterfly_2: ([50u64, 50u64, 1u64, 100u64], [0u64, 0u64]),
218 butterfly_3: ([1u64, 1u64, 50u64, 100u64], [51u64, 51u64]),
219 }
220
221 inverse_butterfly_tests! {
222 inverse_butterfly_0: ([0u64, 1u64, 0u64, 100u64], [1u64, 0u64]),
223 inverse_butterfly_1: ([1u64, 1u64, 1u64, 100u64], [2u64, 0u64]),
224 inverse_butterfly_2: ([50u64, 50u64, 1u64, 100u64], [0u64, 0u64]),
225 inverse_butterfly_3: ([2u64, 1u64, 50u64, 100u64], [3u64, 50u64]),
226 }
227
228 lazy_butterfly_tests! {
229 lazy_butterfly_0: ([0u64, 1u64, 0u64, 100u64]),
230 lazy_butterfly_1: ([1u64, 1u64, 1u64, 100u64]),
231 lazy_butterfly_2: ([50u64, 50u64, 1u64, 100u64]),
232 lazy_butterfly_3: ([1u64, 1u64, 50u64, 100u64]),
233 }
234
235 lazy_inverse_butterfly_tests! {
236 lazy_inverse_butterfly_0: ([0u64, 1u64, 0u64, 100u64]),
237 lazy_inverse_butterfly_1: ([1u64, 1u64, 1u64, 100u64]),
238 lazy_inverse_butterfly_2: ([50u64, 50u64, 1u64, 100u64]),
239 lazy_inverse_butterfly_3: ([1u64, 1u64, 50u64, 100u64]),
240 }
241}