rfc6979/
ct_cmp.rs
1use crate::{ArrayLength, ByteArray};
4use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
5
6pub(crate) fn ct_eq<N: ArrayLength<u8>>(a: &ByteArray<N>, b: &ByteArray<N>) -> Choice {
8 let mut ret = Choice::from(1);
9
10 for (a, b) in a.iter().zip(b.iter()) {
11 ret.conditional_assign(&Choice::from(0), !a.ct_eq(b));
12 }
13
14 ret
15}
16
17pub(crate) fn ct_lt<N: ArrayLength<u8>>(a: &ByteArray<N>, b: &ByteArray<N>) -> Choice {
21 let mut borrow = 0;
22
23 for (&a, &b) in a.iter().zip(b.iter()).rev() {
26 let c = (b as u16).wrapping_add(borrow >> (u8::BITS - 1));
27 borrow = (a as u16).wrapping_sub(c) >> u8::BITS as u8;
28 }
29
30 !borrow.ct_eq(&0)
31}
32
33#[cfg(test)]
34mod 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}