Coverage Report

Created: 2025-07-01 06:46

/rust/registry/src/index.crates.io-6f17d22bba15001f/ring-0.17.14/src/digest.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2015-2019 Brian Smith.
2
//
3
// Permission to use, copy, modify, and/or distribute this software for any
4
// purpose with or without fee is hereby granted, provided that the above
5
// copyright notice and this permission notice appear in all copies.
6
//
7
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15
//! SHA-2 and the legacy SHA-1 digest algorithm.
16
//!
17
//! If all the data is available in a single contiguous slice then the `digest`
18
//! function should be used. Otherwise, the digest can be calculated in
19
//! multiple steps using `Context`.
20
21
use self::{
22
    dynstate::DynState,
23
    sha2::{SHA256_BLOCK_LEN, SHA512_BLOCK_LEN},
24
};
25
use crate::{
26
    bits::{BitLength, FromByteLen as _},
27
    cpu, debug, error,
28
    polyfill::{self, slice, sliceutil},
29
};
30
use core::num::Wrapping;
31
32
pub(crate) use self::finish_error::FinishError;
33
34
mod dynstate;
35
mod sha1;
36
mod sha2;
37
38
#[derive(Clone)]
39
pub(crate) struct BlockContext {
40
    state: DynState,
41
42
    // Note that SHA-512 has a 128-bit input bit counter, but this
43
    // implementation only supports up to 2^64-1 input bits for all algorithms,
44
    // so a 64-bit counter is more than sufficient.
45
    completed_bytes: u64,
46
47
    /// The context's algorithm.
48
    pub algorithm: &'static Algorithm,
49
}
50
51
impl BlockContext {
52
0
    pub(crate) fn new(algorithm: &'static Algorithm) -> Self {
53
0
        Self {
54
0
            state: algorithm.initial_state.clone(),
55
0
            completed_bytes: 0,
56
0
            algorithm,
57
0
        }
58
0
    }
59
60
    /// Processes all the full blocks in `input`, returning the partial block
61
    /// at the end, which may be empty.
62
0
    pub(crate) fn update<'i>(&mut self, input: &'i [u8], cpu_features: cpu::Features) -> &'i [u8] {
63
0
        let (completed_bytes, leftover) = self.block_data_order(input, cpu_features);
64
0
        // Using saturated addition here allows `update` to be infallible and
65
0
        // panic-free. If we were to reach the maximum value here then `finish`
66
0
        // will detect that we processed too much data when it converts this to
67
0
        // a bit length.
68
0
        self.completed_bytes = self
69
0
            .completed_bytes
70
0
            .saturating_add(polyfill::u64_from_usize(completed_bytes));
71
0
        leftover
72
0
    }
73
74
    // On input, `block[..num_pending]` is the (possibly-empty) last *partial*
75
    // chunk of input. It *must* be partial; that is, it is required that
76
    // `num_pending < self.algorithm.block_len`.
77
    //
78
    // `block` may be arbitrarily overwritten.
79
0
    pub(crate) fn try_finish(
80
0
        mut self,
81
0
        block: &mut [u8; MAX_BLOCK_LEN],
82
0
        num_pending: usize,
83
0
        cpu_features: cpu::Features,
84
0
    ) -> Result<Digest, FinishError> {
85
0
        let completed_bits = self
86
0
            .completed_bytes
87
0
            .checked_add(polyfill::u64_from_usize(num_pending))
88
0
            .ok_or_else(|| {
89
0
                // Choosing self.completed_bytes here is lossy & somewhat arbitrary.
90
0
                InputTooLongError::new(self.completed_bytes)
91
0
            })
92
0
            .and_then(BitLength::from_byte_len)
93
0
            .map_err(FinishError::input_too_long)?;
94
95
0
        let block_len = self.algorithm.block_len();
96
0
        let block = &mut block[..block_len];
97
98
0
        let padding = match block.get_mut(num_pending..) {
99
0
            Some([separator, padding @ ..]) => {
100
0
                *separator = 0x80;
101
0
                padding
102
            }
103
            // Precondition violated.
104
0
            unreachable => {
105
0
                return Err(FinishError::pending_not_a_partial_block(
106
0
                    unreachable.as_deref(),
107
0
                ));
108
            }
109
        };
110
111
0
        let padding = match padding
112
0
            .len()
113
0
            .checked_sub(self.algorithm.block_len.len_len())
114
        {
115
0
            Some(_) => padding,
116
            None => {
117
0
                padding.fill(0);
118
0
                let (completed_bytes, leftover) = self.block_data_order(block, cpu_features);
119
0
                debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0));
120
                // We don't increase |self.completed_bytes| because the padding
121
                // isn't data, and so it isn't included in the data length.
122
0
                &mut block[..]
123
            }
124
        };
125
126
0
        let (to_zero, len) = padding.split_at_mut(padding.len() - 8);
127
0
        to_zero.fill(0);
128
0
        len.copy_from_slice(&completed_bits.to_be_bytes());
129
0
130
0
        let (completed_bytes, leftover) = self.block_data_order(block, cpu_features);
131
0
        debug_assert_eq!((completed_bytes, leftover.len()), (block_len, 0));
132
133
0
        Ok(Digest {
134
0
            algorithm: self.algorithm,
135
0
            value: self.state.format_output(),
136
0
        })
137
0
    }
138
139
    #[must_use]
140
0
    fn block_data_order<'d>(
141
0
        &mut self,
142
0
        data: &'d [u8],
143
0
        cpu_features: cpu::Features,
144
0
    ) -> (usize, &'d [u8]) {
145
0
        (self.algorithm.block_data_order)(&mut self.state, data, cpu_features)
146
0
    }
147
}
148
149
pub(crate) type InputTooLongError = error::InputTooLongError<u64>;
150
151
cold_exhaustive_error! {
152
    enum finish_error::FinishError {
153
        input_too_long => InputTooLong(InputTooLongError),
154
        pending_not_a_partial_block_inner => PendingNotAPartialBlock(usize),
155
    }
156
}
157
158
impl FinishError {
159
    #[cold]
160
    #[inline(never)]
161
0
    fn pending_not_a_partial_block(padding: Option<&[u8]>) -> Self {
162
0
        match padding {
163
0
            None => Self::pending_not_a_partial_block_inner(0),
164
0
            Some(padding) => Self::pending_not_a_partial_block_inner(padding.len()),
165
        }
166
0
    }
167
}
168
169
/// A context for multi-step (Init-Update-Finish) digest calculations.
170
///
171
/// # Examples
172
///
173
/// ```
174
/// use ring::digest;
175
///
176
/// let one_shot = digest::digest(&digest::SHA384, b"hello, world");
177
///
178
/// let mut ctx = digest::Context::new(&digest::SHA384);
179
/// ctx.update(b"hello");
180
/// ctx.update(b", ");
181
/// ctx.update(b"world");
182
/// let multi_part = ctx.finish();
183
///
184
/// assert_eq!(&one_shot.as_ref(), &multi_part.as_ref());
185
/// ```
186
#[derive(Clone)]
187
pub struct Context {
188
    block: BlockContext,
189
    // TODO: More explicitly force 64-bit alignment for |pending|.
190
    pending: [u8; MAX_BLOCK_LEN],
191
192
    // Invariant: `self.num_pending < self.block.algorithm.block_len`.
193
    num_pending: usize,
194
}
195
196
impl Context {
197
    /// Constructs a new context.
198
0
    pub fn new(algorithm: &'static Algorithm) -> Self {
199
0
        Self {
200
0
            block: BlockContext::new(algorithm),
201
0
            pending: [0u8; MAX_BLOCK_LEN],
202
0
            num_pending: 0,
203
0
        }
204
0
    }
205
206
0
    pub(crate) fn clone_from(block: &BlockContext) -> Self {
207
0
        Self {
208
0
            block: block.clone(),
209
0
            pending: [0u8; MAX_BLOCK_LEN],
210
0
            num_pending: 0,
211
0
        }
212
0
    }
213
214
    /// Updates the digest with all the data in `data`.
215
0
    pub fn update(&mut self, data: &[u8]) {
216
0
        let cpu_features = cpu::features();
217
0
218
0
        let block_len = self.block.algorithm.block_len();
219
0
        let buffer = &mut self.pending[..block_len];
220
221
0
        let to_digest = if self.num_pending == 0 {
222
0
            data
223
        } else {
224
0
            let buffer_to_fill = match buffer.get_mut(self.num_pending..) {
225
0
                Some(buffer_to_fill) => buffer_to_fill,
226
                None => {
227
                    // Impossible because of the invariant.
228
0
                    unreachable!();
229
                }
230
            };
231
0
            sliceutil::overwrite_at_start(buffer_to_fill, data);
232
0
            match slice::split_at_checked(data, buffer_to_fill.len()) {
233
0
                Some((just_copied, to_digest)) => {
234
0
                    debug_assert_eq!(buffer_to_fill.len(), just_copied.len());
235
0
                    debug_assert_eq!(self.num_pending + just_copied.len(), block_len);
236
0
                    let leftover = self.block.update(buffer, cpu_features);
237
0
                    debug_assert_eq!(leftover.len(), 0);
238
0
                    self.num_pending = 0;
239
0
                    to_digest
240
                }
241
                None => {
242
0
                    self.num_pending += data.len();
243
0
                    // If `data` isn't enough to complete a block, buffer it and stop.
244
0
                    debug_assert!(self.num_pending < block_len);
245
0
                    return;
246
                }
247
            }
248
        };
249
250
0
        let leftover = self.block.update(to_digest, cpu_features);
251
0
        sliceutil::overwrite_at_start(buffer, leftover);
252
0
        self.num_pending = leftover.len();
253
0
        debug_assert!(self.num_pending < block_len);
254
0
    }
255
256
    /// Finalizes the digest calculation and returns the digest value.
257
    ///
258
    /// `finish` consumes the context so it cannot be (mis-)used after `finish`
259
    /// has been called.
260
0
    pub fn finish(self) -> Digest {
261
0
        let cpu = cpu::features();
262
0
        self.try_finish(cpu)
263
0
            .map_err(error::erase::<InputTooLongError>)
264
0
            .unwrap()
265
0
    }
266
267
0
    pub(crate) fn try_finish(
268
0
        mut self,
269
0
        cpu_features: cpu::Features,
270
0
    ) -> Result<Digest, InputTooLongError> {
271
0
        self.block
272
0
            .try_finish(&mut self.pending, self.num_pending, cpu_features)
273
0
            .map_err(|err| match err {
274
0
                FinishError::InputTooLong(i) => i,
275
                FinishError::PendingNotAPartialBlock(_) => {
276
                    // Due to invariant.
277
0
                    unreachable!()
278
                }
279
0
            })
280
0
    }
281
282
    /// The algorithm that this context is using.
283
    #[inline(always)]
284
0
    pub fn algorithm(&self) -> &'static Algorithm {
285
0
        self.block.algorithm
286
0
    }
287
}
288
289
/// Returns the digest of `data` using the given digest algorithm.
290
0
pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest {
291
0
    let cpu = cpu::features();
292
0
    Digest::compute_from(algorithm, data, cpu)
293
0
        .map_err(error::erase::<InputTooLongError>)
294
0
        .unwrap()
295
0
}
296
297
/// A calculated digest value.
298
///
299
/// Use [`Self::as_ref`] to get the value as a `&[u8]`.
300
#[derive(Clone, Copy)]
301
pub struct Digest {
302
    value: Output,
303
    algorithm: &'static Algorithm,
304
}
305
306
impl Digest {
307
0
    pub(crate) fn compute_from(
308
0
        algorithm: &'static Algorithm,
309
0
        data: &[u8],
310
0
        cpu: cpu::Features,
311
0
    ) -> Result<Self, InputTooLongError> {
312
0
        let mut ctx = Context::new(algorithm);
313
0
        ctx.update(data);
314
0
        ctx.try_finish(cpu)
315
0
    }
316
317
    /// The algorithm that was used to calculate the digest value.
318
    #[inline(always)]
319
0
    pub fn algorithm(&self) -> &'static Algorithm {
320
0
        self.algorithm
321
0
    }
322
}
323
324
impl AsRef<[u8]> for Digest {
325
    #[inline(always)]
326
0
    fn as_ref(&self) -> &[u8] {
327
0
        &self.value.0[..self.algorithm.output_len()]
328
0
    }
329
}
330
331
impl core::fmt::Debug for Digest {
332
0
    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
333
0
        write!(fmt, "{:?}:", self.algorithm)?;
334
0
        debug::write_hex_bytes(fmt, self.as_ref())
335
0
    }
336
}
337
338
/// A digest algorithm.
339
pub struct Algorithm {
340
    output_len: OutputLen,
341
    chaining_len: usize,
342
    block_len: BlockLen,
343
344
    /// `block_data_order` processes all the full blocks of data in `data`. It
345
    /// returns the number of bytes processed and the unprocessed data, which
346
    /// is guaranteed to be less than `block_len` bytes long.
347
    block_data_order: for<'d> fn(
348
        state: &mut DynState,
349
        data: &'d [u8],
350
        cpu_features: cpu::Features,
351
    ) -> (usize, &'d [u8]),
352
353
    initial_state: DynState,
354
355
    id: AlgorithmID,
356
}
357
358
#[derive(Debug, Eq, PartialEq)]
359
enum AlgorithmID {
360
    SHA1,
361
    SHA256,
362
    SHA384,
363
    SHA512,
364
    SHA512_256,
365
}
366
367
impl PartialEq for Algorithm {
368
0
    fn eq(&self, other: &Self) -> bool {
369
0
        self.id == other.id
370
0
    }
371
}
372
373
impl Eq for Algorithm {}
374
375
derive_debug_via_id!(Algorithm);
376
377
impl Algorithm {
378
    /// The internal block length.
379
0
    pub fn block_len(&self) -> usize {
380
0
        self.block_len.into()
381
0
    }
382
383
    /// The size of the chaining value of the digest function, in bytes.
384
    ///
385
    /// For non-truncated algorithms (SHA-1, SHA-256, SHA-512), this is equal
386
    /// to [`Self::output_len()`]. For truncated algorithms (e.g. SHA-384,
387
    /// SHA-512/256), this is equal to the length before truncation. This is
388
    /// mostly helpful for determining the size of an HMAC key that is
389
    /// appropriate for the digest algorithm.
390
0
    pub fn chaining_len(&self) -> usize {
391
0
        self.chaining_len
392
0
    }
393
394
    /// The length of a finalized digest.
395
0
    pub fn output_len(&self) -> usize {
396
0
        self.output_len.into()
397
0
    }
398
}
399
400
/// SHA-1 as specified in [FIPS 180-4]. Deprecated.
401
///
402
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
403
pub static SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
404
    output_len: sha1::OUTPUT_LEN,
405
    chaining_len: sha1::CHAINING_LEN,
406
    block_len: sha1::BLOCK_LEN,
407
    block_data_order: dynstate::sha1_block_data_order,
408
    initial_state: DynState::new32([
409
        Wrapping(0x67452301u32),
410
        Wrapping(0xefcdab89u32),
411
        Wrapping(0x98badcfeu32),
412
        Wrapping(0x10325476u32),
413
        Wrapping(0xc3d2e1f0u32),
414
        Wrapping(0),
415
        Wrapping(0),
416
        Wrapping(0),
417
    ]),
418
    id: AlgorithmID::SHA1,
419
};
420
421
/// SHA-256 as specified in [FIPS 180-4].
422
///
423
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
424
pub static SHA256: Algorithm = Algorithm {
425
    output_len: OutputLen::_256,
426
    chaining_len: SHA256_OUTPUT_LEN,
427
    block_len: SHA256_BLOCK_LEN,
428
    block_data_order: dynstate::sha256_block_data_order,
429
    initial_state: DynState::new32([
430
        Wrapping(0x6a09e667u32),
431
        Wrapping(0xbb67ae85u32),
432
        Wrapping(0x3c6ef372u32),
433
        Wrapping(0xa54ff53au32),
434
        Wrapping(0x510e527fu32),
435
        Wrapping(0x9b05688cu32),
436
        Wrapping(0x1f83d9abu32),
437
        Wrapping(0x5be0cd19u32),
438
    ]),
439
    id: AlgorithmID::SHA256,
440
};
441
442
/// SHA-384 as specified in [FIPS 180-4].
443
///
444
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
445
pub static SHA384: Algorithm = Algorithm {
446
    output_len: OutputLen::_384,
447
    chaining_len: SHA512_OUTPUT_LEN,
448
    block_len: SHA512_BLOCK_LEN,
449
    block_data_order: dynstate::sha512_block_data_order,
450
    initial_state: DynState::new64([
451
        Wrapping(0xcbbb9d5dc1059ed8),
452
        Wrapping(0x629a292a367cd507),
453
        Wrapping(0x9159015a3070dd17),
454
        Wrapping(0x152fecd8f70e5939),
455
        Wrapping(0x67332667ffc00b31),
456
        Wrapping(0x8eb44a8768581511),
457
        Wrapping(0xdb0c2e0d64f98fa7),
458
        Wrapping(0x47b5481dbefa4fa4),
459
    ]),
460
    id: AlgorithmID::SHA384,
461
};
462
463
/// SHA-512 as specified in [FIPS 180-4].
464
///
465
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
466
pub static SHA512: Algorithm = Algorithm {
467
    output_len: OutputLen::_512,
468
    chaining_len: SHA512_OUTPUT_LEN,
469
    block_len: SHA512_BLOCK_LEN,
470
    block_data_order: dynstate::sha512_block_data_order,
471
    initial_state: DynState::new64([
472
        Wrapping(0x6a09e667f3bcc908),
473
        Wrapping(0xbb67ae8584caa73b),
474
        Wrapping(0x3c6ef372fe94f82b),
475
        Wrapping(0xa54ff53a5f1d36f1),
476
        Wrapping(0x510e527fade682d1),
477
        Wrapping(0x9b05688c2b3e6c1f),
478
        Wrapping(0x1f83d9abfb41bd6b),
479
        Wrapping(0x5be0cd19137e2179),
480
    ]),
481
    id: AlgorithmID::SHA512,
482
};
483
484
/// SHA-512/256 as specified in [FIPS 180-4].
485
///
486
/// This is *not* the same as just truncating the output of SHA-512, as
487
/// SHA-512/256 has its own initial state distinct from SHA-512's initial
488
/// state.
489
///
490
/// [FIPS 180-4]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
491
pub static SHA512_256: Algorithm = Algorithm {
492
    output_len: OutputLen::_256,
493
    chaining_len: SHA512_OUTPUT_LEN,
494
    block_len: SHA512_BLOCK_LEN,
495
    block_data_order: dynstate::sha512_block_data_order,
496
    initial_state: DynState::new64([
497
        Wrapping(0x22312194fc2bf72c),
498
        Wrapping(0x9f555fa3c84c64c2),
499
        Wrapping(0x2393b86b6f53b151),
500
        Wrapping(0x963877195940eabd),
501
        Wrapping(0x96283ee2a88effe3),
502
        Wrapping(0xbe5e1e2553863992),
503
        Wrapping(0x2b0199fc2c85b8aa),
504
        Wrapping(0x0eb72ddc81c52ca2),
505
    ]),
506
    id: AlgorithmID::SHA512_256,
507
};
508
509
#[derive(Clone, Copy)]
510
struct Output([u8; MAX_OUTPUT_LEN]);
511
512
/// The maximum block length ([`Algorithm::block_len()`]) of all the algorithms
513
/// in this module.
514
pub const MAX_BLOCK_LEN: usize = BlockLen::MAX.into();
515
516
/// The maximum output length ([`Algorithm::output_len()`]) of all the
517
/// algorithms in this module.
518
pub const MAX_OUTPUT_LEN: usize = OutputLen::MAX.into();
519
520
/// The maximum chaining length ([`Algorithm::chaining_len()`]) of all the
521
/// algorithms in this module.
522
pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
523
524
#[inline]
525
0
fn format_output<T, F, const N: usize>(input: [Wrapping<T>; sha2::CHAINING_WORDS], f: F) -> Output
526
0
where
527
0
    F: Fn(T) -> [u8; N],
528
0
    T: Copy,
529
0
{
530
0
    let mut output = Output([0; MAX_OUTPUT_LEN]);
531
0
    output
532
0
        .0
533
0
        .chunks_mut(N)
534
0
        .zip(input.iter().copied().map(|Wrapping(w)| f(w)))
Unexecuted instantiation: ring::digest::format_output::<u32, <u32>::to_be_bytes, 4>::{closure#0}
Unexecuted instantiation: ring::digest::format_output::<u64, <u64>::to_be_bytes, 8>::{closure#0}
535
0
        .for_each(|(o, i)| {
536
0
            o.copy_from_slice(&i);
537
0
        });
Unexecuted instantiation: ring::digest::format_output::<u32, <u32>::to_be_bytes, 4>::{closure#1}
Unexecuted instantiation: ring::digest::format_output::<u64, <u64>::to_be_bytes, 8>::{closure#1}
538
0
    output
539
0
}
Unexecuted instantiation: ring::digest::format_output::<u32, <u32>::to_be_bytes, 4>
Unexecuted instantiation: ring::digest::format_output::<u64, <u64>::to_be_bytes, 8>
540
541
/// The length of the output of SHA-1, in bytes.
542
pub const SHA1_OUTPUT_LEN: usize = sha1::OUTPUT_LEN.into();
543
544
/// The length of the output of SHA-256, in bytes.
545
pub const SHA256_OUTPUT_LEN: usize = OutputLen::_256.into();
546
547
/// The length of the output of SHA-384, in bytes.
548
pub const SHA384_OUTPUT_LEN: usize = OutputLen::_384.into();
549
550
/// The length of the output of SHA-512, in bytes.
551
pub const SHA512_OUTPUT_LEN: usize = OutputLen::_512.into();
552
553
/// The length of the output of SHA-512/256, in bytes.
554
pub const SHA512_256_OUTPUT_LEN: usize = OutputLen::_256.into();
555
556
#[derive(Clone, Copy)]
557
enum BlockLen {
558
    _512 = 512 / 8,
559
    _1024 = 1024 / 8, // MAX
560
}
561
562
impl BlockLen {
563
    const MAX: Self = Self::_1024;
564
    #[inline(always)]
565
0
    const fn into(self) -> usize {
566
0
        self as usize
567
0
    }
568
569
    #[inline(always)]
570
0
    const fn len_len(self) -> usize {
571
0
        let len_len = match self {
572
0
            BlockLen::_512 => LenLen::_64,
573
0
            BlockLen::_1024 => LenLen::_128,
574
        };
575
0
        len_len as usize
576
0
    }
577
}
578
579
#[derive(Clone, Copy)]
580
enum LenLen {
581
    _64 = 64 / 8,
582
    _128 = 128 / 8,
583
}
584
585
#[derive(Clone, Copy)]
586
enum OutputLen {
587
    _160 = 160 / 8,
588
    _256 = 256 / 8,
589
    _384 = 384 / 8,
590
    _512 = 512 / 8, // MAX
591
}
592
593
impl OutputLen {
594
    const MAX: Self = Self::_512;
595
596
    #[inline(always)]
597
0
    const fn into(self) -> usize {
598
0
        self as usize
599
0
    }
600
}
601
602
#[cfg(test)]
603
mod tests {
604
    mod max_input {
605
        extern crate alloc;
606
        use super::super::super::digest;
607
        use crate::polyfill::u64_from_usize;
608
        use alloc::vec;
609
610
        macro_rules! max_input_tests {
611
            ( $algorithm_name:ident ) => {
612
                mod $algorithm_name {
613
                    use super::super::super::super::digest;
614
615
                    #[test]
616
                    fn max_input_test() {
617
                        super::max_input_test(&digest::$algorithm_name);
618
                    }
619
620
                    #[test]
621
                    #[should_panic]
622
                    fn too_long_input_test_block() {
623
                        super::too_long_input_test_block(&digest::$algorithm_name);
624
                    }
625
626
                    #[test]
627
                    #[should_panic]
628
                    fn too_long_input_test_byte() {
629
                        super::too_long_input_test_byte(&digest::$algorithm_name);
630
                    }
631
                }
632
            };
633
        }
634
635
        fn max_input_test(alg: &'static digest::Algorithm) {
636
            let mut context = nearly_full_context(alg);
637
            let next_input = vec![0u8; alg.block_len() - 1];
638
            context.update(&next_input);
639
            let _ = context.finish(); // no panic
640
        }
641
642
        fn too_long_input_test_block(alg: &'static digest::Algorithm) {
643
            let mut context = nearly_full_context(alg);
644
            let next_input = vec![0u8; alg.block_len()];
645
            context.update(&next_input);
646
            let _ = context.finish(); // should panic
647
        }
648
649
        fn too_long_input_test_byte(alg: &'static digest::Algorithm) {
650
            let mut context = nearly_full_context(alg);
651
            let next_input = vec![0u8; alg.block_len() - 1];
652
            context.update(&next_input);
653
            context.update(&[0]);
654
            let _ = context.finish(); // should panic
655
        }
656
657
        fn nearly_full_context(alg: &'static digest::Algorithm) -> digest::Context {
658
            // All implementations currently support up to 2^64-1 bits
659
            // of input; according to the spec, SHA-384 and SHA-512
660
            // support up to 2^128-1, but that's not implemented yet.
661
            let max_bytes = 1u64 << (64 - 3);
662
            let max_blocks = max_bytes / u64_from_usize(alg.block_len());
663
            let completed_bytes = (max_blocks - 1) * u64_from_usize(alg.block_len());
664
            digest::Context {
665
                block: digest::BlockContext {
666
                    state: alg.initial_state.clone(),
667
                    completed_bytes,
668
                    algorithm: alg,
669
                },
670
                pending: [0u8; digest::MAX_BLOCK_LEN],
671
                num_pending: 0,
672
            }
673
        }
674
675
        max_input_tests!(SHA1_FOR_LEGACY_USE_ONLY);
676
        max_input_tests!(SHA256);
677
        max_input_tests!(SHA384);
678
        max_input_tests!(SHA512);
679
    }
680
}