Coverage Report

Created: 2024-06-18 06:18

/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
}