constant_time_eq/lib.rs
1//! Compares two equal-sized byte strings in constant time.
2//!
3//! The time of the comparison does not depend on:
4//!
5//! * The contents of the inputs;
6//! * The position of the difference(s) between the inputs.
7//!
8//! The time of the comparison can depend on:
9//!
10//! * The memory addresses of the inputs;
11//! * The length of the inputs.
12
13#![cfg_attr(not(feature = "std"), no_std)]
14#![deny(clippy::undocumented_unsafe_blocks)]
15
16#[doc(hidden)]
17pub mod generic;
18
19#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2", not(miri)))]
20mod sse2;
21
22#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2", not(miri)))]
23use sse2 as simd;
24
25#[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
26mod neon;
27
28#[cfg(not(any(
29 all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2", not(miri)),
30 all(target_arch = "aarch64", target_feature = "neon", not(miri))
31)))]
32use generic as simd;
33#[cfg(all(target_arch = "aarch64", target_feature = "neon", not(miri)))]
34use neon as simd;
35
36#[cfg(all(target_arch = "aarch64", not(miri)))]
37#[doc(hidden)]
38pub mod dit;
39
40#[cfg(all(target_arch = "aarch64", not(miri)))]
41use dit::with_dit;
42
43/// Runs code with the hardware DIT feature or equivalent enabled when possible.
44#[cfg(any(not(target_arch = "aarch64"), miri))]
45#[inline(always)]
46pub(crate) fn with_dit<T, F>(f: F) -> T
47where
48 F: FnOnce() -> T,
49{
50 f()
51}
52
53/// Compares two equal-sized byte strings in constant time.
54///
55/// # Examples
56///
57/// ```
58/// use constant_time_eq::constant_time_eq;
59///
60/// assert!(constant_time_eq(b"foo", b"foo"));
61/// assert!(!constant_time_eq(b"foo", b"bar"));
62/// assert!(!constant_time_eq(b"bar", b"baz"));
63/// # assert!(constant_time_eq(b"", b""));
64///
65/// // Not equal-sized, so won't take constant time.
66/// assert!(!constant_time_eq(b"foo", b""));
67/// assert!(!constant_time_eq(b"foo", b"quux"));
68/// ```
69#[must_use]
70pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
71 simd::constant_time_eq(a, b)
72}
73
74// Fixed-size array variant.
75
76/// Compares two fixed-size byte strings in constant time.
77///
78/// # Examples
79///
80/// ```
81/// use constant_time_eq::constant_time_eq_n;
82///
83/// assert!(constant_time_eq_n(&[3; 20], &[3; 20]));
84/// assert!(!constant_time_eq_n(&[3; 20], &[7; 20]));
85/// ```
86#[must_use]
87pub fn constant_time_eq_n<const N: usize>(a: &[u8; N], b: &[u8; N]) -> bool {
88 simd::constant_time_eq_n(a, b)
89}
90
91// Fixed-size variants for the most common sizes.
92
93/// Compares two 128-bit byte strings in constant time.
94///
95/// # Examples
96///
97/// ```
98/// use constant_time_eq::constant_time_eq_16;
99///
100/// assert!(constant_time_eq_16(&[3; 16], &[3; 16]));
101/// assert!(!constant_time_eq_16(&[3; 16], &[7; 16]));
102/// ```
103#[inline]
104#[must_use]
105pub fn constant_time_eq_16(a: &[u8; 16], b: &[u8; 16]) -> bool {
106 constant_time_eq_n(a, b)
107}
108
109/// Compares two 256-bit byte strings in constant time.
110///
111/// # Examples
112///
113/// ```
114/// use constant_time_eq::constant_time_eq_32;
115///
116/// assert!(constant_time_eq_32(&[3; 32], &[3; 32]));
117/// assert!(!constant_time_eq_32(&[3; 32], &[7; 32]));
118/// ```
119#[inline]
120#[must_use]
121pub fn constant_time_eq_32(a: &[u8; 32], b: &[u8; 32]) -> bool {
122 constant_time_eq_n(a, b)
123}
124
125/// Compares two 512-bit byte strings in constant time.
126///
127/// # Examples
128///
129/// ```
130/// use constant_time_eq::constant_time_eq_64;
131///
132/// assert!(constant_time_eq_64(&[3; 64], &[3; 64]));
133/// assert!(!constant_time_eq_64(&[3; 64], &[7; 64]));
134/// ```
135#[inline]
136#[must_use]
137pub fn constant_time_eq_64(a: &[u8; 64], b: &[u8; 64]) -> bool {
138 constant_time_eq_n(a, b)
139}