Coverage Report

Created: 2026-02-14 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rfc6979-0.4.0/src/ct_cmp.rs
Line
Count
Source
1
//! Constant-time comparison helpers for [`ByteArray`].
2
3
use crate::{ArrayLength, ByteArray};
4
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
5
6
/// Constant-time equals.
7
3.16k
pub(crate) fn ct_eq<N: ArrayLength<u8>>(a: &ByteArray<N>, b: &ByteArray<N>) -> Choice {
8
3.16k
    let mut ret = Choice::from(1);
9
10
101k
    for (a, b) in a.iter().zip(b.iter()) {
11
101k
        ret.conditional_assign(&Choice::from(0), !a.ct_eq(b));
12
101k
    }
13
14
3.16k
    ret
15
3.16k
}
16
17
/// Constant-time less than.
18
///
19
/// Inputs are interpreted as big endian integers.
20
3.16k
pub(crate) fn ct_lt<N: ArrayLength<u8>>(a: &ByteArray<N>, b: &ByteArray<N>) -> Choice {
21
3.16k
    let mut borrow = 0;
22
23
    // Perform subtraction with borrow a byte-at-a-time, interpreting a
24
    // no-borrow condition as the less-than case
25
101k
    for (&a, &b) in a.iter().zip(b.iter()).rev() {
26
101k
        let c = (b as u16).wrapping_add(borrow >> (u8::BITS - 1));
27
101k
        borrow = (a as u16).wrapping_sub(c) >> u8::BITS as u8;
28
101k
    }
29
30
3.16k
    !borrow.ct_eq(&0)
31
3.16k
}
32
33
#[cfg(test)]
34
mod tests {
35
    const A: [u8; 4] = [0, 0, 0, 0];
36
    const B: [u8; 4] = [0, 0, 0, 1];
37
    const C: [u8; 4] = [0xFF, 0, 0, 0];
38
    const D: [u8; 4] = [0xFF, 0, 0, 1];
39
    const E: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFE];
40
    const F: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF];
41
42
    #[test]
43
    fn ct_eq() {
44
        use super::ct_eq;
45
46
        assert_eq!(ct_eq(&A.into(), &A.into()).unwrap_u8(), 1);
47
        assert_eq!(ct_eq(&B.into(), &B.into()).unwrap_u8(), 1);
48
        assert_eq!(ct_eq(&C.into(), &C.into()).unwrap_u8(), 1);
49
        assert_eq!(ct_eq(&D.into(), &D.into()).unwrap_u8(), 1);
50
        assert_eq!(ct_eq(&E.into(), &E.into()).unwrap_u8(), 1);
51
        assert_eq!(ct_eq(&F.into(), &F.into()).unwrap_u8(), 1);
52
53
        assert_eq!(ct_eq(&A.into(), &B.into()).unwrap_u8(), 0);
54
        assert_eq!(ct_eq(&C.into(), &D.into()).unwrap_u8(), 0);
55
        assert_eq!(ct_eq(&E.into(), &F.into()).unwrap_u8(), 0);
56
    }
57
58
    #[test]
59
    fn ct_lt() {
60
        use super::ct_lt;
61
62
        assert_eq!(ct_lt(&A.into(), &A.into()).unwrap_u8(), 0);
63
        assert_eq!(ct_lt(&B.into(), &B.into()).unwrap_u8(), 0);
64
        assert_eq!(ct_lt(&C.into(), &C.into()).unwrap_u8(), 0);
65
        assert_eq!(ct_lt(&D.into(), &D.into()).unwrap_u8(), 0);
66
        assert_eq!(ct_lt(&E.into(), &E.into()).unwrap_u8(), 0);
67
        assert_eq!(ct_lt(&F.into(), &F.into()).unwrap_u8(), 0);
68
69
        assert_eq!(ct_lt(&A.into(), &B.into()).unwrap_u8(), 1);
70
        assert_eq!(ct_lt(&A.into(), &C.into()).unwrap_u8(), 1);
71
        assert_eq!(ct_lt(&B.into(), &A.into()).unwrap_u8(), 0);
72
        assert_eq!(ct_lt(&C.into(), &A.into()).unwrap_u8(), 0);
73
74
        assert_eq!(ct_lt(&B.into(), &C.into()).unwrap_u8(), 1);
75
        assert_eq!(ct_lt(&B.into(), &D.into()).unwrap_u8(), 1);
76
        assert_eq!(ct_lt(&C.into(), &B.into()).unwrap_u8(), 0);
77
        assert_eq!(ct_lt(&D.into(), &B.into()).unwrap_u8(), 0);
78
79
        assert_eq!(ct_lt(&C.into(), &D.into()).unwrap_u8(), 1);
80
        assert_eq!(ct_lt(&C.into(), &E.into()).unwrap_u8(), 1);
81
        assert_eq!(ct_lt(&D.into(), &C.into()).unwrap_u8(), 0);
82
        assert_eq!(ct_lt(&E.into(), &C.into()).unwrap_u8(), 0);
83
84
        assert_eq!(ct_lt(&E.into(), &F.into()).unwrap_u8(), 1);
85
        assert_eq!(ct_lt(&F.into(), &E.into()).unwrap_u8(), 0);
86
    }
87
}