1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Constant-time helpers usable across primitive modules.
//!
//! Centralises CT predicates that several primitives share (AEAD weak-key
//! check, KDF salt validation, ...) so each call site cannot accidentally
//! reach for the early-exiting `iter().all()` form. All functions here use
//! [`subtle::ConstantTimeEq`] under the hood.
use ConstantTimeEq;
/// Constant-time all-zero check for fixed-length byte arrays.
///
/// Prefer this over [`is_all_zero_bytes`] whenever the length is known
/// at compile time: the loop iteration count is `ceil(N / 32)` — a
/// constant — so the caller cannot accidentally pass a runtime-derived
/// length that would leak through timing. AEAD key validation (16-,
/// 24-, 32-byte keys) is the canonical call site.
///
/// Returns `false` when `N == 0` so a zero-length array cannot trigger
/// a false-positive weak-input rejection.
/// Returns `true` iff every byte of `bytes` is zero, in constant time
/// **with respect to byte contents**.
///
/// Empty slices return `false` so that a caller passing a zero-length
/// secret cannot trigger a false-positive weak-input rejection.
///
/// # Constant-time scope and a length-leak caveat
///
/// Runtime is independent of *which byte* is non-zero, so an attacker
/// who can time this function cannot learn the position of the first
/// difference. The loop, however, iterates `ceil(bytes.len() / 32)`
/// times — the iteration count itself is **not constant-time over the
/// input length**. For variable-length secret inputs (KDF output of
/// caller-chosen size, secret-length nonces, etc.) the timing leaks
/// the length.
///
/// **Production callers must validate `bytes.len()` before calling this
/// function** (which the current sole caller `aead::is_all_zero_key`
/// does, by way of the AEAD constructors' fixed-size key requirement).
/// For new fixed-length use sites, prefer the const-generic
/// [`is_all_zero`] above — its type signature makes the length-non-
/// secrecy precondition compile-time enforced.