/src/OpenSK/libraries/crypto/src/ec/int256.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2019 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | use alloc::vec; |
16 | | use alloc::vec::Vec; |
17 | | use arrayref::{array_mut_ref, array_ref}; |
18 | | use byteorder::{BigEndian, ByteOrder}; |
19 | | use core::ops::{Add, AddAssign, Sub, SubAssign}; |
20 | | use rand_core::RngCore; |
21 | | use subtle::{self, Choice, ConditionallySelectable, ConstantTimeEq}; |
22 | | use zeroize::Zeroize; |
23 | | |
24 | | const BITS_PER_DIGIT: usize = 32; |
25 | | const BYTES_PER_DIGIT: usize = BITS_PER_DIGIT >> 3; |
26 | | const NDIGITS: usize = 8; |
27 | | pub const NBYTES: usize = NDIGITS * BYTES_PER_DIGIT; |
28 | | |
29 | | pub type Digit = u32; |
30 | | type DoubleDigit = u64; |
31 | | type SignedDoubleDigit = i64; |
32 | | |
33 | | /// Big integer implementation with 256 bits. |
34 | | /// |
35 | | /// Never call zeroize explicitly, to not invalidate any invariants. |
36 | 280 | #[derive(Clone, Copy, PartialEq, Eq, Zeroize)] |
37 | | // TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is |
38 | | // resolved. |
39 | 6.26k | #[derive(Default)] |
40 | | pub struct Int256 { |
41 | | digits: [Digit; NDIGITS], |
42 | | } |
43 | | |
44 | | impl ConditionallySelectable for Int256 { |
45 | 2.14M | fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { |
46 | 2.14M | let mut digits = [0; NDIGITS]; |
47 | 17.1M | for (i, digit) in digits.iter_mut().enumerate() { |
48 | 17.1M | *digit = Digit::conditional_select(&a.digits[i], &b.digits[i], choice); |
49 | 17.1M | } |
50 | 2.14M | Self { digits } |
51 | 2.14M | } |
52 | | } |
53 | | |
54 | | /** Arithmetic operations on the secp256r1 field, where elements are represented as 8 digits of |
55 | | * 32 bits. **/ |
56 | | #[allow(clippy::unreadable_literal)] |
57 | | impl Int256 { |
58 | | /** Constants for the secp256r1 curve. **/ |
59 | | // Curve order (prime) |
60 | | pub const N: Int256 = Int256 { |
61 | | digits: [ |
62 | | 0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, 0xffffffff, 0xffffffff, 0x00000000, |
63 | | 0xffffffff, |
64 | | ], |
65 | | }; |
66 | | // Curve order - 2 |
67 | | pub const N_MIN_2: Int256 = Int256 { |
68 | | digits: [ |
69 | | 0xfc63254f, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, 0xffffffff, 0xffffffff, 0x00000000, |
70 | | 0xffffffff, |
71 | | ], |
72 | | }; |
73 | | // Curve field size |
74 | | pub const P: Int256 = Int256 { |
75 | | digits: [ |
76 | | 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000001, |
77 | | 0xffffffff, |
78 | | ], |
79 | | }; |
80 | | // Curve b |
81 | | pub const B: Int256 = Int256 { |
82 | | digits: [ |
83 | | 0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, |
84 | | 0x5ac635d8, |
85 | | ], |
86 | | }; |
87 | | // 2^257 mod P |
88 | | pub const R: Int256 = Int256 { |
89 | | digits: [ |
90 | | 0x00000002, 0x00000000, 0x00000000, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, |
91 | | 0x00000001, |
92 | | ], |
93 | | }; |
94 | | // 1 / 2^257 mod P |
95 | | pub const R_INV: Int256 = Int256 { |
96 | | digits: [ |
97 | | 0x80000000, 0x00000001, 0xffffffff, 0x00000000, 0x80000001, 0xfffffffe, 0x00000001, |
98 | | 0x7fffffff, |
99 | | ], |
100 | | }; |
101 | | |
102 | | pub const ZERO: Int256 = Int256 { digits: [0; 8] }; |
103 | | pub const ONE: Int256 = Int256 { |
104 | | digits: [1, 0, 0, 0, 0, 0, 0, 0], |
105 | | }; |
106 | | |
107 | | #[cfg(test)] |
108 | | pub const fn new(digits: [Digit; NDIGITS]) -> Int256 { |
109 | | Int256 { digits } |
110 | | } |
111 | | |
112 | | #[cfg(test)] |
113 | | pub fn digits(self) -> [Digit; NDIGITS] { |
114 | | self.digits |
115 | | } |
116 | | |
117 | | #[cfg(test)] |
118 | | fn hamming_weight(&self) -> u32 { |
119 | | self.digits.iter().map(|d| d.count_ones()).sum() |
120 | | } |
121 | | |
122 | | /** RNG **/ |
123 | | // Generates a uniformly distributed integer 0 <= x < 2^256 |
124 | 31.5k | pub fn gen_uniform_256<R>(r: &mut R) -> Int256 |
125 | 31.5k | where |
126 | 31.5k | R: RngCore, |
127 | 31.5k | { |
128 | 31.5k | let mut digits = [0; NDIGITS]; |
129 | 283k | for i in 0..NDIGITS { |
130 | 252k | digits[i] = r.next_u32(); |
131 | 252k | } |
132 | 31.5k | Int256 { digits } |
133 | 31.5k | } <crypto::ec::int256::Int256>::gen_uniform_256::<rand::rngs::std::StdRng> Line | Count | Source | 124 | 31.5k | pub fn gen_uniform_256<R>(r: &mut R) -> Int256 | 125 | 31.5k | where | 126 | 31.5k | R: RngCore, | 127 | 31.5k | { | 128 | 31.5k | let mut digits = [0; NDIGITS]; | 129 | 283k | for i in 0..NDIGITS { | 130 | 252k | digits[i] = r.next_u32(); | 131 | 252k | } | 132 | 31.5k | Int256 { digits } | 133 | 31.5k | } |
Unexecuted instantiation: <crypto::ec::int256::Int256>::gen_uniform_256::<_> |
134 | | |
135 | | /** Serialization **/ |
136 | 11.0k | pub fn from_bin(src: &[u8; NBYTES]) -> Int256 { |
137 | 11.0k | let mut digits = [0; NDIGITS]; |
138 | 99.0k | for i in 0..NDIGITS { |
139 | 88.0k | digits[NDIGITS - 1 - i] = BigEndian::read_u32(array_ref![src, 4 * i, 4]); |
140 | 88.0k | } |
141 | 11.0k | Int256 { digits } |
142 | 11.0k | } |
143 | | |
144 | 16.5k | pub fn to_bin(&self, dst: &mut [u8; NBYTES]) { |
145 | 149k | for i in 0..NDIGITS { |
146 | 132k | BigEndian::write_u32(array_mut_ref![dst, 4 * i, 4], self.digits[NDIGITS - 1 - i]); |
147 | 132k | } |
148 | 16.5k | } |
149 | | |
150 | 4.17k | pub fn to_minimal_encoding(self) -> Vec<u8> { |
151 | 4.17k | let mut bytes_buffer = [0; NBYTES]; |
152 | 4.17k | self.to_bin(&mut bytes_buffer); |
153 | 4.25k | match bytes_buffer.iter().position(|x| *x != 0) { |
154 | 4.17k | Some(pos) => { |
155 | 4.17k | let mut encoding = vec![]; |
156 | 4.17k | if bytes_buffer[pos] & 0x80 == 0x80 { |
157 | 2.17k | encoding.push(0x00); |
158 | 2.17k | } |
159 | 4.17k | encoding.extend_from_slice(&bytes_buffer[pos..]); |
160 | 4.17k | encoding |
161 | | } |
162 | 0 | None => vec![0x00], |
163 | | } |
164 | 4.17k | } |
165 | | |
166 | | /** Useful getters **/ |
167 | | #[inline(always)] |
168 | 0 | pub fn digit(&self, i: usize) -> Digit { |
169 | 0 | self.digits[i] |
170 | 0 | } |
171 | | |
172 | 1.83M | pub fn bit(&self, i: usize) -> Digit { |
173 | 1.83M | let digit = i / BITS_PER_DIGIT; |
174 | 1.83M | let bit = i & (BITS_PER_DIGIT - 1); |
175 | 1.83M | (self.digits[digit] >> bit) & 1 |
176 | 1.83M | } |
177 | | |
178 | 10.9k | pub fn is_zero(&self) -> subtle::Choice { |
179 | 10.9k | // Best effort constant-time comparison, assuming the compiler doesn't optimize that. |
180 | 10.9k | Choice::from( |
181 | 10.9k | self.digits |
182 | 10.9k | .iter() |
183 | 87.9k | .fold(1u8, |acc, x| acc & x.ct_eq(&0).unwrap_u8()), |
184 | 10.9k | ) |
185 | 10.9k | } |
186 | | |
187 | | // Helper function to implement variable-time modular inverse. |
188 | | #[cfg(test)] |
189 | | fn is_even(&self) -> bool { |
190 | | self.digits[0] & 1 == 0 |
191 | | } |
192 | | |
193 | | #[cfg(test)] |
194 | | fn count_ones(&self) -> u32 { |
195 | | self.digits.iter().map(|x| x.count_ones()).sum() |
196 | | } |
197 | | |
198 | | /** Arithmetic operations: bit shifts **/ |
199 | | // Shift left by n bits, and return the result as well as the top digit that was shifted out. |
200 | | // This is valid only for 0 < n < BITS_PER_DIGIT |
201 | 81.0k | pub fn shl(&self, n: usize) -> (Int256, Digit) { |
202 | 81.0k | let mut digits = [0; NDIGITS]; |
203 | 81.0k | digits[0] = self.digits[0] << n; |
204 | | #[allow(clippy::needless_range_loop)] |
205 | 648k | for i in 1..NDIGITS { |
206 | 567k | digits[i] = (self.digits[i] << n) | (self.digits[i - 1] >> (BITS_PER_DIGIT - n)); |
207 | 567k | } |
208 | | |
209 | 81.0k | ( |
210 | 81.0k | Int256 { digits }, |
211 | 81.0k | self.digits[NDIGITS - 1] >> (BITS_PER_DIGIT - n), |
212 | 81.0k | ) |
213 | 81.0k | } |
214 | | |
215 | | // Shift right by n bits. |
216 | | // This is valid only for 0 < n < BITS_PER_DIGIT |
217 | 0 | pub fn shr(&self, n: usize) -> Int256 { |
218 | 0 | let mut digits = [0; NDIGITS]; |
219 | | #[allow(clippy::needless_range_loop)] |
220 | 0 | for i in 0..(NDIGITS - 1) { |
221 | 0 | digits[i] = (self.digits[i] >> n) | (self.digits[i + 1] << (BITS_PER_DIGIT - n)); |
222 | 0 | } |
223 | 0 | digits[NDIGITS - 1] = self.digits[NDIGITS - 1] >> n; |
224 | 0 |
|
225 | 0 | Int256 { digits } |
226 | 0 | } |
227 | | |
228 | | // Helper function to implement variable-time modular inverse. |
229 | | // Shift right by 1 bit, pushing highbit at the top. |
230 | | #[cfg(test)] |
231 | | fn shr1(&self, highbit: Digit) -> Int256 { |
232 | | let mut digits = [0; NDIGITS]; |
233 | | for i in 0..(NDIGITS - 1) { |
234 | | digits[i] = (self.digits[i] >> 1) | (self.digits[i + 1] << (BITS_PER_DIGIT - 1)); |
235 | | } |
236 | | digits[NDIGITS - 1] = (self.digits[NDIGITS - 1] >> 1) | (highbit << (BITS_PER_DIGIT - 1)); |
237 | | |
238 | | Int256 { digits } |
239 | | } |
240 | | |
241 | | /** Arithmetic operations: addition/substraction **/ |
242 | | // Reduction modulo modd. |
243 | 6.26k | pub fn modd(&self, modd: &Int256) -> Int256 { |
244 | 6.26k | let mut digits = self.digits; |
245 | 6.26k | let choice = Int256::sub_conditional(&mut digits, modd, 0, Choice::from(1u8)); |
246 | 6.26k | Int256::add_conditional(&mut digits, modd, 0, choice); |
247 | 6.26k | Int256 { digits } |
248 | 6.26k | } |
249 | | |
250 | | // Computes: dst[], top += if choice { mod[] } else { 0 } |
251 | | // Returns: new top digit |
252 | 718k | fn add_conditional( |
253 | 718k | dst: &mut [Digit; NDIGITS], |
254 | 718k | modd: &Int256, |
255 | 718k | top: Digit, |
256 | 718k | choice: Choice, |
257 | 718k | ) -> Digit { |
258 | 718k | let mut carry: DoubleDigit = 0; |
259 | | |
260 | 5.74M | for (i, digit) in dst.iter_mut().enumerate() { |
261 | 5.74M | carry += *digit as DoubleDigit; |
262 | 5.74M | carry += u32::conditional_select(&0, &modd.digits[i], choice) as DoubleDigit; |
263 | 5.74M | *digit = carry as Digit; |
264 | 5.74M | carry >>= BITS_PER_DIGIT; |
265 | 5.74M | } |
266 | | |
267 | 718k | (carry as Digit) + top |
268 | 718k | } |
269 | | |
270 | | // Computes: dst[], top -= if choice { mod[] } else { 0 } |
271 | | // Returns: new top digit |
272 | 7.12M | fn sub_conditional( |
273 | 7.12M | dst: &mut [Digit; NDIGITS], |
274 | 7.12M | modd: &Int256, |
275 | 7.12M | top: Digit, |
276 | 7.12M | choice: Choice, |
277 | 7.12M | ) -> Choice { |
278 | 7.12M | let mut borrow: SignedDoubleDigit = 0; |
279 | | |
280 | 57.0M | for (i, digit) in dst.iter_mut().enumerate() { |
281 | 57.0M | borrow += *digit as SignedDoubleDigit; |
282 | 57.0M | borrow -= u32::conditional_select(&0, &modd.digits[i], choice) as SignedDoubleDigit; |
283 | 57.0M | *digit = borrow as Digit; |
284 | 57.0M | borrow >>= BITS_PER_DIGIT; |
285 | 57.0M | } |
286 | | |
287 | 7.12M | ((borrow + (top as SignedDoubleDigit)) as Digit).ct_eq(&!0) |
288 | 7.12M | } |
289 | | |
290 | | /** Modular arithmetic operations **/ |
291 | | // Modular addition. |
292 | 280 | pub fn modadd_vartime(&self, other: &Int256, modd: &Int256) -> Int256 { |
293 | 280 | let (sum, carry) = (self as &Int256) + other; |
294 | 280 | let tmp = if carry != 0 { (&sum - modd).0 } else { sum }; |
295 | | |
296 | | // At this point, the sum can be >= modd, even without carry. |
297 | | // We substract modd to handle this case. |
298 | 280 | tmp.modsub_vartime(modd, modd) |
299 | 280 | } |
300 | | |
301 | | // Modular substraction. |
302 | 1.12k | pub fn modsub_vartime(&self, other: &Int256, modd: &Int256) -> Int256 { |
303 | 1.12k | let (diff, borrow) = (self as &Int256) - other; |
304 | 1.12k | if borrow != 0 { |
305 | 404 | (&diff + modd).0 |
306 | | } else { |
307 | 716 | diff |
308 | | } |
309 | 1.12k | } |
310 | | |
311 | | // Requires: the most-significant word of the modulus is 0xffffffff. |
312 | | // Computes: a * b modulo modd. |
313 | 699k | pub fn modmul(a: &Int256, b: &Int256, modd: &Int256) -> Int256 { |
314 | 699k | Int256::modmul_top(a, b, 0, modd) |
315 | 699k | } |
316 | | |
317 | | // Requires: the most-significant word of the modulus is 0xffffffff. |
318 | | // Computes: a * (b, top_b) modulo modd. |
319 | 712k | pub fn modmul_top(a: &Int256, b: &Int256, top_b: Digit, modd: &Int256) -> Int256 { |
320 | 712k | let mut tmp = [0; NDIGITS * 2 + 1]; |
321 | 712k | let mut top = 0; |
322 | | |
323 | | // Multiply/add into tmp. |
324 | 6.40M | for i in 0..NDIGITS { |
325 | 5.69M | if i != 0 { |
326 | 4.98M | tmp[i + NDIGITS - 1] = top; |
327 | 4.98M | } |
328 | 5.69M | top = Int256::mul_add(array_mut_ref![tmp, i, NDIGITS], a, b.digits[i]); |
329 | | } |
330 | | |
331 | 712k | tmp[2 * NDIGITS - 1] = top; |
332 | 712k | top = Int256::mul_add(array_mut_ref![tmp, NDIGITS, NDIGITS], a, top_b); |
333 | | |
334 | | // Reduce tmp, digit by digit. |
335 | 7.12M | for j in 0..=NDIGITS { |
336 | 6.40M | let i = NDIGITS - j; |
337 | 6.40M | |
338 | 6.40M | // Estimate the reducer as top * modd, because the most significant word of modd is |
339 | 6.40M | // 0xffffffff. |
340 | 6.40M | let mut reducer = Int256::ZERO; |
341 | 6.40M | let top_reducer = Int256::mul_add(&mut reducer.digits, modd, top); |
342 | 6.40M | top = Int256::sub_top(array_mut_ref![tmp, i, NDIGITS], &reducer, top, top_reducer); |
343 | 6.40M | |
344 | 6.40M | #[cfg(test)] |
345 | 6.40M | assert!(top <= 1); |
346 | 6.40M | |
347 | 6.40M | let _top = |
348 | 6.40M | Int256::sub_conditional(array_mut_ref![tmp, i, NDIGITS], modd, top, top.ct_eq(&1)); |
349 | 6.40M | |
350 | 6.40M | #[cfg(test)] |
351 | 6.40M | assert_eq!(bool::from(_top), false); |
352 | 6.40M | |
353 | 6.40M | top = tmp[i + NDIGITS - 1]; |
354 | 6.40M | } |
355 | | |
356 | 712k | let choice = |
357 | 712k | Int256::sub_conditional(array_mut_ref![tmp, 0, NDIGITS], modd, 0, Choice::from(1u8)); |
358 | 712k | Int256::add_conditional(array_mut_ref![tmp, 0, NDIGITS], modd, 0, choice); |
359 | 712k | |
360 | 712k | Int256 { |
361 | 712k | digits: *array_ref![tmp, 0, NDIGITS], |
362 | 712k | } |
363 | 712k | } |
364 | | |
365 | | // Helper function to implement modular multiplication. |
366 | | // Computes: dst[] += src[] * factor |
367 | | // Returns: carry digit |
368 | 12.8M | fn mul_add(dst: &mut [Digit; NDIGITS], src: &Int256, factor: Digit) -> Digit { |
369 | 12.8M | let mut carry: DoubleDigit = 0; |
370 | | |
371 | 102M | for (i, digit) in dst.iter_mut().enumerate() { |
372 | 102M | carry += *digit as DoubleDigit; |
373 | 102M | carry += (src.digits[i] as DoubleDigit) * (factor as DoubleDigit); |
374 | 102M | *digit = carry as Digit; |
375 | 102M | carry >>= BITS_PER_DIGIT; |
376 | 102M | } |
377 | | |
378 | 12.8M | carry as Digit |
379 | 12.8M | } |
380 | | |
381 | | // Helper function to implement modular multiplication. |
382 | | // Computes: dst[], top -= src[], src_top |
383 | | // Returns: borrow digit (new top) |
384 | 6.40M | fn sub_top(dst: &mut [Digit; NDIGITS], src: &Int256, top: Digit, src_top: Digit) -> Digit { |
385 | 6.40M | let mut borrow: SignedDoubleDigit = 0; |
386 | | |
387 | 51.2M | for (i, digit) in dst.iter_mut().enumerate() { |
388 | 51.2M | borrow += *digit as SignedDoubleDigit; |
389 | 51.2M | borrow -= src.digits[i] as SignedDoubleDigit; |
390 | 51.2M | *digit = borrow as Digit; |
391 | 51.2M | borrow >>= BITS_PER_DIGIT; |
392 | 51.2M | } |
393 | | |
394 | 6.40M | borrow += top as SignedDoubleDigit; |
395 | 6.40M | borrow -= src_top as SignedDoubleDigit; |
396 | 6.40M | |
397 | 6.40M | #[cfg(test)] |
398 | 6.40M | assert_eq!(borrow >> BITS_PER_DIGIT, 0); |
399 | 6.40M | |
400 | 6.40M | borrow as Digit |
401 | 6.40M | } |
402 | | |
403 | | /** Constant-time helpers **/ |
404 | | // Helper function to implement constant-time modular inverse. |
405 | | // Best-effort constant time function that computes: |
406 | | // if idx == 0 { |
407 | | // *tbl0 = Int256::ONE |
408 | | // } else { |
409 | | // *tbl0 = tbl[idx - 1] |
410 | | // } |
411 | 133k | fn set_zero_to_idx(tbl0: &mut Int256, tbl: &[Int256; 15], idx: u32) { |
412 | 133k | *tbl0 = Int256::ONE; |
413 | 2.13M | for i in 1u32..16 { |
414 | 2.00M | tbl0.conditional_assign(&tbl[(i - 1) as usize], i.ct_eq(&idx)); |
415 | 2.00M | } |
416 | 133k | } |
417 | | |
418 | | /** Arithmetic operations: modular exponentiation **/ |
419 | 2.08k | pub fn modpow(&self, power: &Int256, modd: &Int256) -> Int256 { |
420 | 2.08k | let mut tbl0 = Int256::ZERO; |
421 | 2.08k | let mut tbl = [Int256::ZERO; 15]; |
422 | 2.08k | // tbl[i-1] = self^i |
423 | 2.08k | tbl[0] = *self; |
424 | 31.3k | for i in 1..15 { |
425 | 29.2k | tbl[i] = Int256::modmul(&tbl[i - 1], self, modd); |
426 | 29.2k | } |
427 | | |
428 | 2.08k | let mut result = Int256::ONE; |
429 | 133k | for j in (0..256).step_by(4) { |
430 | 133k | let i = 256 - j; |
431 | 133k | result = Int256::modmul(&result, &result, modd); |
432 | 133k | result = Int256::modmul(&result, &result, modd); |
433 | 133k | result = Int256::modmul(&result, &result, modd); |
434 | 133k | result = Int256::modmul(&result, &result, modd); |
435 | 133k | |
436 | 133k | let idx = power.bit(i - 1) << 3 |
437 | 133k | | power.bit(i - 2) << 2 |
438 | 133k | | power.bit(i - 3) << 1 |
439 | 133k | | power.bit(i - 4); |
440 | 133k | |
441 | 133k | Int256::set_zero_to_idx(&mut tbl0, &tbl, idx); // tbl0 = tbl[idx-1]; |
442 | 133k | tbl0 = Int256::modmul(&tbl0, &result, modd); |
443 | 133k | result.conditional_assign(&tbl0, !idx.ct_eq(&0)); |
444 | 133k | } |
445 | | |
446 | 2.08k | result |
447 | 2.08k | } |
448 | | |
449 | | /** Arithmetic operations: modular inverse **/ |
450 | | // Variable time function to compute modular inverse. This uses Euclid's theorem. |
451 | | #[cfg(test)] |
452 | | #[allow(clippy::many_single_char_names)] |
453 | | pub fn modinv_vartime(&self, modd: &Int256) -> Int256 { |
454 | | let mut r = Int256::ZERO; |
455 | | let mut s = Int256::ONE; |
456 | | let mut u = *modd; |
457 | | let mut v = *self; |
458 | | |
459 | | loop { |
460 | | if u.is_even() { |
461 | | u = u.shr1(0); |
462 | | if r.is_even() { |
463 | | r = r.shr1(0); |
464 | | } else { |
465 | | let (rr, highbit) = &r + modd; |
466 | | r = rr.shr1(highbit); |
467 | | } |
468 | | } else if v.is_even() { |
469 | | v = v.shr1(0); |
470 | | if s.is_even() { |
471 | | s = s.shr1(0); |
472 | | } else { |
473 | | let (ss, highbit) = &s + modd; |
474 | | s = ss.shr1(highbit); |
475 | | } |
476 | | } else { |
477 | | let (w, borrow) = &v - &u; |
478 | | if borrow == 0 { |
479 | | v = w; |
480 | | let (ss, borrow) = &s - &r; |
481 | | s = if borrow != 0 { (&ss + modd).0 } else { ss }; |
482 | | if bool::from(v.is_zero()) { |
483 | | break; |
484 | | } |
485 | | } else { |
486 | | u = (&u - &v).0; |
487 | | let (rr, borrow) = &r - &s; |
488 | | r = if borrow != 0 { (&rr + modd).0 } else { rr }; |
489 | | } |
490 | | } |
491 | | } |
492 | | |
493 | | r.modd(modd) |
494 | | } |
495 | | |
496 | | /** Comparison between field elements. **/ |
497 | | // Best-effort constant-time less-than operation. |
498 | | // FIXME: This code is currently required because subtle only supports constant-time equality |
499 | | // comparisons. This should be removed once |
500 | | // https://github.com/dalek-cryptography/subtle/issues/61 is fixed |
501 | 38.3k | pub fn ct_lt(&self, other: &Int256) -> Choice { |
502 | 38.3k | let mut borrow: SignedDoubleDigit = 0; |
503 | | |
504 | 344k | for i in 0..NDIGITS { |
505 | 306k | // The following statement updates the borrow according to this table. |
506 | 306k | // +-------------------------------------+----------------+------------------+ |
507 | 306k | // | self.digits[i].cmp(other.digits[i]) | borrow += ? | resulting borrow | |
508 | 306k | // +-------------------------------------+----------------+------------------+ |
509 | 306k | // | Less | ffffffff_xx... | ffffffff_yy... | |
510 | 306k | // | Equal | 0 | unchanged | |
511 | 306k | // | Greater | 00000000_xx... | 00000000_yy... | |
512 | 306k | // +-------------------------------------+----------------+------------------+ |
513 | 306k | borrow += |
514 | 306k | (self.digits[i] as SignedDoubleDigit) - (other.digits[i] as SignedDoubleDigit); |
515 | 306k | // This is a signed shift. After this operation, the borrow can take two values: |
516 | 306k | // - 00...00 (so far, self >= other) |
517 | 306k | // - ff...ff (so far, self < other) |
518 | 306k | borrow >>= BITS_PER_DIGIT; |
519 | 306k | } |
520 | | |
521 | 38.3k | Choice::from((borrow & 1) as u8) |
522 | 38.3k | } |
523 | | |
524 | | // Best-effort constant time comparison. |
525 | | // * 0 = equal |
526 | | // * 1 = self > other |
527 | | // * -1 = self < other |
528 | | #[cfg(test)] |
529 | | pub fn compare(&self, other: &Int256) -> u32 { |
530 | | let mut borrow: SignedDoubleDigit = 0; |
531 | | let mut notzero: Digit = 0; |
532 | | |
533 | | for i in 0..NDIGITS { |
534 | | borrow += |
535 | | (self.digits[i] as SignedDoubleDigit) - (other.digits[i] as SignedDoubleDigit); |
536 | | notzero |= (borrow as Digit != 0) as Digit; |
537 | | borrow >>= BITS_PER_DIGIT; |
538 | | } |
539 | | |
540 | | (borrow as Digit) | notzero |
541 | | } |
542 | | |
543 | | #[cfg(test)] |
544 | | fn compare_vartime(&self, other: &Int256) -> u32 { |
545 | | use core::cmp::Ordering; |
546 | | |
547 | | for i in 0..NDIGITS { |
548 | | match self.digits[NDIGITS - i - 1].cmp(&other.digits[NDIGITS - i - 1]) { |
549 | | Ordering::Equal => continue, |
550 | | Ordering::Greater => return 1, |
551 | | Ordering::Less => return 0xffffffff, |
552 | | } |
553 | | } |
554 | | 0 |
555 | | } |
556 | | } |
557 | | |
558 | | /** Addition with carry **/ |
559 | | impl Add for &Int256 { |
560 | | type Output = (Int256, Digit); |
561 | | |
562 | | // Returns sum and carry (0 or 1). |
563 | | #[allow(clippy::suspicious_arithmetic_impl)] |
564 | 2.77k | fn add(self, other: &Int256) -> (Int256, Digit) { |
565 | 2.77k | let mut digits = [0; NDIGITS]; |
566 | 2.77k | let mut carry: DoubleDigit = 0; |
567 | | |
568 | 22.1k | for (i, digit) in digits.iter_mut().enumerate() { |
569 | 22.1k | carry += (self.digits[i] as DoubleDigit) + (other.digits[i] as DoubleDigit); |
570 | 22.1k | *digit = carry as Digit; |
571 | 22.1k | carry >>= BITS_PER_DIGIT; |
572 | 22.1k | } |
573 | | |
574 | 2.77k | (Int256 { digits }, carry as Digit) |
575 | 2.77k | } |
576 | | } |
577 | | |
578 | | impl AddAssign<&Int256> for Int256 { |
579 | | // Adds to self, ignoring carry. |
580 | | #[allow(clippy::suspicious_op_assign_impl)] |
581 | 0 | fn add_assign(&mut self, other: &Int256) { |
582 | 0 | let mut carry: DoubleDigit = 0; |
583 | 0 | for i in 0..NDIGITS { |
584 | 0 | carry += (self.digits[i] as DoubleDigit) + (other.digits[i] as DoubleDigit); |
585 | 0 | self.digits[i] = carry as Digit; |
586 | 0 | carry >>= BITS_PER_DIGIT; |
587 | 0 | } |
588 | 0 | } |
589 | | } |
590 | | |
591 | | impl Add<Digit> for &Int256 { |
592 | | type Output = (Int256, Digit); |
593 | | |
594 | | // Returns sum and carry (0 or 1). |
595 | | #[allow(clippy::suspicious_arithmetic_impl)] |
596 | 122k | fn add(self, digit: Digit) -> (Int256, Digit) { |
597 | 122k | let mut digits = [0; NDIGITS]; |
598 | 122k | let mut carry = digit as DoubleDigit; |
599 | | |
600 | 980k | for (i, digit) in digits.iter_mut().enumerate() { |
601 | 980k | carry += self.digits[i] as DoubleDigit; |
602 | 980k | *digit = carry as Digit; |
603 | 980k | carry >>= BITS_PER_DIGIT; |
604 | 980k | } |
605 | | |
606 | 122k | (Int256 { digits }, carry as Digit) |
607 | 122k | } |
608 | | } |
609 | | |
610 | | /** Substraction with borrow **/ |
611 | | impl Sub for &Int256 { |
612 | | type Output = (Int256, Digit); |
613 | | |
614 | | // Returns difference and borrow (0 or -1). |
615 | | #[allow(clippy::suspicious_arithmetic_impl)] |
616 | 1.26k | fn sub(self, other: &Int256) -> (Int256, Digit) { |
617 | 1.26k | let mut digits = [0; NDIGITS]; |
618 | 1.26k | let mut borrow: SignedDoubleDigit = 0; |
619 | | |
620 | 10.1k | for (i, digit) in digits.iter_mut().enumerate() { |
621 | 10.1k | borrow += |
622 | 10.1k | (self.digits[i] as SignedDoubleDigit) - (other.digits[i] as SignedDoubleDigit); |
623 | 10.1k | *digit = borrow as Digit; |
624 | 10.1k | borrow >>= BITS_PER_DIGIT; |
625 | 10.1k | } |
626 | | |
627 | 1.26k | (Int256 { digits }, borrow as Digit) |
628 | 1.26k | } |
629 | | } |
630 | | |
631 | | impl SubAssign<&Int256> for Int256 { |
632 | | // Substract from self, ignoring carry. |
633 | | #[allow(clippy::suspicious_op_assign_impl)] |
634 | 0 | fn sub_assign(&mut self, other: &Int256) { |
635 | 0 | let mut borrow: SignedDoubleDigit = 0; |
636 | 0 | for i in 0..NDIGITS { |
637 | 0 | borrow += |
638 | 0 | (self.digits[i] as SignedDoubleDigit) - (other.digits[i] as SignedDoubleDigit); |
639 | 0 | self.digits[i] = borrow as Digit; |
640 | 0 | borrow >>= BITS_PER_DIGIT; |
641 | 0 | } |
642 | 0 | } |
643 | | } |
644 | | |
645 | | impl core::fmt::Debug for Int256 { |
646 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
647 | 0 | write!(f, "Int256 {{ digits: {:08x?} }}", self.digits) |
648 | 0 | } |
649 | | } |
650 | | |
651 | | #[cfg(test)] |
652 | | pub mod test { |
653 | | use super::super::montgomery::Montgomery; |
654 | | use super::*; |
655 | | |
656 | | /** Extra constants for tests **/ |
657 | | const TWO: Int256 = Int256 { |
658 | | digits: [2, 0, 0, 0, 0, 0, 0, 0], |
659 | | }; |
660 | | const P_MIN_1: Int256 = Int256 { |
661 | | digits: [ |
662 | | 0xfffffffe, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000001, |
663 | | 0xffffffff, |
664 | | ], |
665 | | }; |
666 | | const P_MIN_2: Int256 = Int256 { |
667 | | digits: [ |
668 | | 0xfffffffd, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000001, |
669 | | 0xffffffff, |
670 | | ], |
671 | | }; |
672 | | |
673 | | // Generate all 256-bit integers that have exactly one bit set to 1. |
674 | | pub fn get_1bit_one_test_values() -> Vec<Int256> { |
675 | | let mut values = Vec::new(); |
676 | | for &byte in &[0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80] { |
677 | | for &int in &[byte, byte << 8, byte << 16, byte << 24] { |
678 | | values.push(Int256 { |
679 | | digits: [int, 0, 0, 0, 0, 0, 0, 0], |
680 | | }); |
681 | | values.push(Int256 { |
682 | | digits: [0, int, 0, 0, 0, 0, 0, 0], |
683 | | }); |
684 | | values.push(Int256 { |
685 | | digits: [0, 0, int, 0, 0, 0, 0, 0], |
686 | | }); |
687 | | values.push(Int256 { |
688 | | digits: [0, 0, 0, int, 0, 0, 0, 0], |
689 | | }); |
690 | | values.push(Int256 { |
691 | | digits: [0, 0, 0, 0, int, 0, 0, 0], |
692 | | }); |
693 | | values.push(Int256 { |
694 | | digits: [0, 0, 0, 0, 0, int, 0, 0], |
695 | | }); |
696 | | values.push(Int256 { |
697 | | digits: [0, 0, 0, 0, 0, 0, int, 0], |
698 | | }); |
699 | | values.push(Int256 { |
700 | | digits: [0, 0, 0, 0, 0, 0, 0, int], |
701 | | }); |
702 | | } |
703 | | } |
704 | | values |
705 | | } |
706 | | |
707 | | // Generate all 256-bit integers that have exactly one bit set to 0. |
708 | | pub fn get_1bit_zero_test_values() -> Vec<Int256> { |
709 | | let values: Vec<Int256> = get_1bit_one_test_values() |
710 | | .iter() |
711 | | .map(|x| { |
712 | | let mut digits = [Default::default(); NDIGITS]; |
713 | | for i in 0..NDIGITS { |
714 | | digits[i] = !x.digits[i]; |
715 | | } |
716 | | Int256 { digits } |
717 | | }) |
718 | | .collect(); |
719 | | values |
720 | | } |
721 | | |
722 | | pub fn get_nonzero_test_values() -> Vec<Int256> { |
723 | | let mut values: Vec<Int256> = Montgomery::PRECOMPUTED |
724 | | .iter() |
725 | | .flatten() |
726 | | .flatten() |
727 | | .map(|x| x.montgomery_to_field().to_int()) |
728 | | .collect(); |
729 | | values.append(&mut get_1bit_one_test_values()); |
730 | | values.append(&mut get_1bit_zero_test_values()); |
731 | | values.push(Int256::B); |
732 | | values.push(P_MIN_1); |
733 | | values.push(P_MIN_2); |
734 | | values |
735 | | } |
736 | | |
737 | | fn get_test_values() -> Vec<Int256> { |
738 | | let mut values = get_nonzero_test_values(); |
739 | | values.push(Int256::ZERO); |
740 | | values |
741 | | } |
742 | | |
743 | | #[test] |
744 | | fn test_1bit_one() { |
745 | | let values = get_1bit_one_test_values(); |
746 | | assert_eq!(values.len(), 256); |
747 | | for x in &values { |
748 | | assert_eq!(x.hamming_weight(), 1); |
749 | | } |
750 | | } |
751 | | |
752 | | #[test] |
753 | | fn test_1bit_zero() { |
754 | | let values = get_1bit_zero_test_values(); |
755 | | assert_eq!(values.len(), 256); |
756 | | for x in &values { |
757 | | assert_eq!(x.hamming_weight(), 255); |
758 | | } |
759 | | } |
760 | | |
761 | | /** Serialization **/ |
762 | | #[test] |
763 | | fn test_to_bin_from_bin() { |
764 | | for &x in &get_test_values() { |
765 | | let mut buf = [Default::default(); NBYTES]; |
766 | | x.to_bin(&mut buf); |
767 | | assert_eq!(Int256::from_bin(&buf), x); |
768 | | } |
769 | | } |
770 | | |
771 | | #[test] |
772 | | fn test_minimal_encoding_zero() { |
773 | | let test_int = Int256::ZERO; |
774 | | let expected_encoding = vec![0x00]; |
775 | | |
776 | | assert_eq!(test_int.to_minimal_encoding(), expected_encoding); |
777 | | } |
778 | | |
779 | | #[test] |
780 | | fn test_minimal_encoding_one() { |
781 | | let test_int = Int256::ONE; |
782 | | let expected_encoding = vec![0x01]; |
783 | | |
784 | | assert_eq!(test_int.to_minimal_encoding(), expected_encoding); |
785 | | } |
786 | | |
787 | | #[test] |
788 | | fn test_minimal_encoding_one_full_byte() { |
789 | | let bytes = [ |
790 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
791 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
792 | | 0x00, 0x00, 0x00, 0xFF, |
793 | | ]; |
794 | | let test_int = Int256::from_bin(&bytes); |
795 | | let expected_encoding = vec![0x00, 0xFF]; |
796 | | |
797 | | assert_eq!(test_int.to_minimal_encoding(), expected_encoding); |
798 | | } |
799 | | |
800 | | #[test] |
801 | | fn test_minimal_encoding_most_bytes_full() { |
802 | | let bytes = [ |
803 | | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
804 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
805 | | 0xFF, 0xFF, 0xFF, 0xFF, |
806 | | ]; |
807 | | let test_int = Int256::from_bin(&bytes); |
808 | | let expected_encoding = bytes.to_vec(); |
809 | | |
810 | | assert_eq!(test_int.to_minimal_encoding(), expected_encoding); |
811 | | } |
812 | | |
813 | | #[test] |
814 | | fn test_minimal_encoding_no_leading_byte() { |
815 | | let bytes = [ |
816 | | 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
817 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
818 | | 0xFF, 0xFF, 0xFF, 0xFF, |
819 | | ]; |
820 | | let test_int = Int256::from_bin(&bytes); |
821 | | let expected_encoding = bytes.to_vec(); |
822 | | |
823 | | assert_eq!(test_int.to_minimal_encoding(), expected_encoding); |
824 | | } |
825 | | |
826 | | #[test] |
827 | | fn test_minimal_encoding_with_leading_byte() { |
828 | | let bytes = [ |
829 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
830 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
831 | | 0xFF, 0xFF, 0xFF, 0xFF, |
832 | | ]; |
833 | | let test_int = Int256::from_bin(&bytes); |
834 | | let mut expected_encoding = vec![0x00]; |
835 | | expected_encoding.extend(&bytes); |
836 | | |
837 | | assert_eq!(test_int.to_minimal_encoding(), expected_encoding); |
838 | | } |
839 | | |
840 | | #[test] |
841 | | fn test_from_bin_is_big_endian_bits_with_little_endian_words() { |
842 | | let buf = b"\x01\x23\x45\x67\x89\xab\xcd\xef\ |
843 | | \x12\x34\x56\x78\x9a\xbc\xde\xf0\ |
844 | | \x23\x45\x67\x89\xab\xcd\xef\x01\ |
845 | | \x34\x56\x78\x9a\xbc\xde\xf0\x12"; |
846 | | assert_eq!( |
847 | | Int256::from_bin(&buf), |
848 | | Int256 { |
849 | | digits: [ |
850 | | 0xbcdef012, 0x3456789a, 0xabcdef01, 0x23456789, 0x9abcdef0, 0x12345678, |
851 | | 0x89abcdef, 0x01234567, |
852 | | ] |
853 | | } |
854 | | ); |
855 | | } |
856 | | |
857 | | /** Useful getters **/ |
858 | | #[test] |
859 | | fn test_is_zero() { |
860 | | assert!(bool::from(Int256::ZERO.is_zero())); |
861 | | for x in get_nonzero_test_values() { |
862 | | assert!(!bool::from(x.is_zero())); |
863 | | } |
864 | | } |
865 | | |
866 | | #[test] |
867 | | fn test_is_even() { |
868 | | assert!(Int256::ZERO.is_even()); |
869 | | assert!(!Int256::ONE.is_even()); |
870 | | assert!(TWO.is_even()); |
871 | | assert!(!Int256::N.is_even()); |
872 | | assert!(!Int256::P.is_even()); |
873 | | assert!(!Int256::B.is_even()); |
874 | | } |
875 | | |
876 | | /** Arithmetic operations: bit shifts **/ |
877 | | #[test] |
878 | | fn test_shift_zero() { |
879 | | for i in 1..BITS_PER_DIGIT { |
880 | | assert_eq!(Int256::ZERO.shl(i), (Int256::ZERO, 0)); |
881 | | } |
882 | | for i in 1..BITS_PER_DIGIT { |
883 | | assert_eq!(Int256::ZERO.shr(i), Int256::ZERO); |
884 | | } |
885 | | } |
886 | | |
887 | | #[test] |
888 | | fn test_shifts() { |
889 | | let mut a = Int256::ONE; |
890 | | |
891 | | // Shift left. |
892 | | for i in 0..255 { |
893 | | assert_eq!(a.bit(i), 1); |
894 | | assert!(!bool::from(a.is_zero())); |
895 | | let (shifted, carry) = a.shl(1); |
896 | | assert_eq!(carry, 0); |
897 | | a = shifted; |
898 | | assert_eq!(a.bit(i), 0); |
899 | | assert_eq!(a.count_ones(), 1); |
900 | | } |
901 | | |
902 | | assert_eq!(a.bit(255), 1); |
903 | | assert!(!bool::from(a.is_zero())); |
904 | | let (shifted, carry) = a.shl(1); |
905 | | assert_eq!(carry, 1); |
906 | | assert_eq!(shifted.bit(255), 0); |
907 | | assert!(bool::from(shifted.is_zero())); |
908 | | |
909 | | // Shift right. |
910 | | for i in (1..256).rev() { |
911 | | assert_eq!(a.bit(i), 1); |
912 | | assert!(!bool::from(a.is_zero())); |
913 | | a = a.shr(1); |
914 | | assert_eq!(a.bit(i), 0); |
915 | | assert_eq!(a.count_ones(), 1); |
916 | | } |
917 | | |
918 | | assert_eq!(a.bit(0), 1); |
919 | | assert!(!bool::from(a.is_zero())); |
920 | | a = a.shr(1); |
921 | | assert_eq!(a.bit(0), 0); |
922 | | assert!(bool::from(a.is_zero())); |
923 | | } |
924 | | |
925 | | #[test] |
926 | | fn test_shl_shr1() { |
927 | | for x in &get_test_values() { |
928 | | let (shifted, carry) = x.shl(1); |
929 | | assert_eq!(&shifted.shr1(carry), x); |
930 | | } |
931 | | } |
932 | | |
933 | | #[test] |
934 | | fn test_shr1_is_shr_one() { |
935 | | for x in &get_test_values() { |
936 | | assert_eq!(x.shr(1), x.shr1(0)); |
937 | | } |
938 | | for x in &get_test_values() { |
939 | | let mut y = *x; |
940 | | for i in 1..BITS_PER_DIGIT { |
941 | | y = y.shr1(0); |
942 | | assert_eq!(x.shr(i), y); |
943 | | } |
944 | | } |
945 | | } |
946 | | |
947 | | /** Constant-time helpers **/ |
948 | | #[test] |
949 | | fn test_set_zero_to_idx() { |
950 | | let mut tbl = [Int256::ZERO; 15]; |
951 | | for (i, x) in tbl.iter_mut().enumerate() { |
952 | | *x = Int256 { |
953 | | digits: [i as u32; NDIGITS], |
954 | | }; |
955 | | } |
956 | | |
957 | | for i in 0..16 { |
958 | | let mut tbl0 = Int256::ZERO; |
959 | | Int256::set_zero_to_idx(&mut tbl0, &tbl, i as u32); |
960 | | if i == 0 { |
961 | | assert_eq!(tbl0, Int256::ONE); |
962 | | } else { |
963 | | assert_eq!(tbl0, tbl[i - 1]); |
964 | | } |
965 | | } |
966 | | } |
967 | | |
968 | | /** Arithmetic: constant-time conditional addition/substraction **/ |
969 | | #[test] |
970 | | fn test_add_conditional() { |
971 | | for x in &get_test_values() { |
972 | | for y in &get_test_values() { |
973 | | let mut z = *x; |
974 | | let carry = Int256::add_conditional(&mut z.digits, y, 0, Choice::from(0u8)); |
975 | | assert_eq!(carry, 0); |
976 | | assert_eq!(z, *x); |
977 | | let carry = Int256::add_conditional(&mut z.digits, y, 0, Choice::from(1u8)); |
978 | | assert_eq!((z, carry), x + y); |
979 | | } |
980 | | } |
981 | | } |
982 | | |
983 | | #[test] |
984 | | fn test_sub_conditional() { |
985 | | for x in &get_test_values() { |
986 | | for y in &get_test_values() { |
987 | | let mut z = *x; |
988 | | let borrow = Int256::sub_conditional(&mut z.digits, y, 0, Choice::from(0u8)); |
989 | | assert_eq!(bool::from(borrow), false); |
990 | | assert_eq!(z, *x); |
991 | | let borrow = Int256::sub_conditional(&mut z.digits, y, 0, Choice::from(1u8)); |
992 | | assert_eq!((z, Digit::conditional_select(&0, &!0, borrow)), x - y); |
993 | | } |
994 | | } |
995 | | } |
996 | | |
997 | | /** Arithmetic operators **/ |
998 | | #[test] |
999 | | fn test_add_sub() { |
1000 | | for x in &get_test_values() { |
1001 | | for y in &get_test_values() { |
1002 | | let (sum, carry) = x + y; |
1003 | | let (diff, borrow) = &sum - y; |
1004 | | assert_eq!(diff, *x); |
1005 | | assert_eq!(carry.wrapping_add(borrow), 0); |
1006 | | } |
1007 | | } |
1008 | | } |
1009 | | |
1010 | | #[test] |
1011 | | fn test_sub_add() { |
1012 | | for x in &get_test_values() { |
1013 | | for y in &get_test_values() { |
1014 | | let (diff, borrow) = x - y; |
1015 | | let (sum, carry) = &diff + y; |
1016 | | assert_eq!(sum, *x); |
1017 | | assert_eq!(carry.wrapping_add(borrow), 0); |
1018 | | } |
1019 | | } |
1020 | | } |
1021 | | |
1022 | | /** Arithmetic: modular exponentiation **/ |
1023 | | #[test] |
1024 | | fn test_modpow() { |
1025 | | const MODULUS: Int256 = Int256::P; |
1026 | | for x in &get_test_values() { |
1027 | | let mut result = Int256::ONE; |
1028 | | let mut power = Int256::ZERO; |
1029 | | |
1030 | | // This test is super slow with debug assertions enabled. |
1031 | | #[cfg(not(debug_assertions))] |
1032 | | const ITERATIONS: u32 = 100; |
1033 | | #[cfg(debug_assertions)] |
1034 | | const ITERATIONS: u32 = 5; |
1035 | | |
1036 | | for _ in 0..ITERATIONS { |
1037 | | assert_eq!(x.modpow(&power, &MODULUS), result); |
1038 | | result = Int256::modmul(&result, x, &MODULUS); |
1039 | | power += &Int256::ONE; |
1040 | | } |
1041 | | } |
1042 | | } |
1043 | | |
1044 | | #[test] |
1045 | | fn test_self_times_modinv_is_one() { |
1046 | | const MODULUS: Int256 = Int256::P; |
1047 | | for x in &get_nonzero_test_values() { |
1048 | | let inv = x.modinv_vartime(&MODULUS); |
1049 | | let product = Int256::modmul(&x, &inv, &MODULUS); |
1050 | | assert_eq!(product, Int256::ONE); |
1051 | | } |
1052 | | } |
1053 | | |
1054 | | #[test] |
1055 | | fn test_modinv_modinv() { |
1056 | | const MODULUS: Int256 = Int256::P; |
1057 | | for &x in &get_nonzero_test_values() { |
1058 | | // By construction, this test only works if x is less than the modulus. |
1059 | | if x.compare(&MODULUS) != 0xffffffff { |
1060 | | continue; |
1061 | | } |
1062 | | assert_eq!(x.modinv_vartime(&MODULUS).modinv_vartime(&MODULUS), x); |
1063 | | } |
1064 | | } |
1065 | | |
1066 | | /** Other arithmetic **/ |
1067 | | #[test] |
1068 | | fn test_add_digit() { |
1069 | | for x in &get_test_values() { |
1070 | | for y in &get_test_values() { |
1071 | | for &digit in &y.digits { |
1072 | | assert_eq!( |
1073 | | x + digit, |
1074 | | x + &Int256 { |
1075 | | digits: [digit, 0, 0, 0, 0, 0, 0, 0] |
1076 | | } |
1077 | | ); |
1078 | | } |
1079 | | } |
1080 | | } |
1081 | | } |
1082 | | |
1083 | | #[test] |
1084 | | fn test_add_assign() { |
1085 | | for x in &get_test_values() { |
1086 | | for y in &get_test_values() { |
1087 | | let mut z = *x; |
1088 | | z += y; |
1089 | | assert_eq!(z, (x + y).0); |
1090 | | } |
1091 | | } |
1092 | | } |
1093 | | |
1094 | | #[test] |
1095 | | fn test_sub_assign() { |
1096 | | for x in &get_test_values() { |
1097 | | for y in &get_test_values() { |
1098 | | let mut z = *x; |
1099 | | z -= y; |
1100 | | assert_eq!(z, (x - y).0); |
1101 | | } |
1102 | | } |
1103 | | } |
1104 | | |
1105 | | #[test] |
1106 | | fn test_mul_add() { |
1107 | | for x in &get_test_values() { |
1108 | | for y in &get_test_values() { |
1109 | | let mut result = *x; |
1110 | | let mut carries = 0; |
1111 | | |
1112 | | // This test is super slow with debug assertions enabled. |
1113 | | #[cfg(not(debug_assertions))] |
1114 | | const ITERATIONS: u32 = 1000; |
1115 | | #[cfg(debug_assertions)] |
1116 | | const ITERATIONS: u32 = 5; |
1117 | | |
1118 | | for factor in 0..ITERATIONS { |
1119 | | let mut z = *x; |
1120 | | let ma_carry = Int256::mul_add(&mut z.digits, y, factor); |
1121 | | assert_eq!(ma_carry, carries); |
1122 | | assert_eq!(z, result); |
1123 | | |
1124 | | let (sum, carry) = &result + y; |
1125 | | result = sum; |
1126 | | carries += carry; |
1127 | | } |
1128 | | } |
1129 | | } |
1130 | | } |
1131 | | |
1132 | | /** Comparison between field elements. **/ |
1133 | | #[test] |
1134 | | fn test_compare() { |
1135 | | for x in &get_test_values() { |
1136 | | for y in &get_test_values() { |
1137 | | let cmp = x.compare(y); |
1138 | | assert!(cmp == 0 || cmp == 1 || cmp == 0xffffffff); |
1139 | | assert_eq!(cmp, x.compare_vartime(y)); |
1140 | | } |
1141 | | } |
1142 | | } |
1143 | | |
1144 | | #[test] |
1145 | | fn test_compare_is_reflexive() { |
1146 | | for x in &get_test_values() { |
1147 | | assert_eq!(x.compare(x), 0); |
1148 | | } |
1149 | | } |
1150 | | |
1151 | | #[test] |
1152 | | fn test_compare_is_antisymetric() { |
1153 | | for x in &get_test_values() { |
1154 | | for y in &get_test_values() { |
1155 | | let a = x.compare(y); |
1156 | | let b = y.compare(x); |
1157 | | assert_eq!(a.wrapping_add(b), 0); |
1158 | | } |
1159 | | } |
1160 | | } |
1161 | | |
1162 | | #[test] |
1163 | | fn test_lt() { |
1164 | | for x in &get_test_values() { |
1165 | | for y in &get_test_values() { |
1166 | | let ct_lt = bool::from(x.ct_lt(y)); |
1167 | | let lt = x.compare_vartime(y) == 0xffffffff; |
1168 | | assert_eq!(ct_lt, lt); |
1169 | | } |
1170 | | } |
1171 | | } |
1172 | | |
1173 | | #[test] |
1174 | | fn test_lt_is_antireflexive() { |
1175 | | for x in &get_test_values() { |
1176 | | assert!(!bool::from(x.ct_lt(x))); |
1177 | | } |
1178 | | } |
1179 | | |
1180 | | #[test] |
1181 | | fn test_lt_is_antisymetric() { |
1182 | | for x in &get_test_values() { |
1183 | | for y in &get_test_values() { |
1184 | | let a = x.ct_lt(y).unwrap_u8(); |
1185 | | let b = y.ct_lt(x).unwrap_u8(); |
1186 | | let c = (x == y) as u8; |
1187 | | assert_eq!(a + b + c, 1); |
1188 | | } |
1189 | | } |
1190 | | } |
1191 | | |
1192 | | // TODO: more tests |
1193 | | } |