Coverage Report

Created: 2025-10-10 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ring-0.17.14/src/aead/poly1305.rs
Line
Count
Source
1
// Copyright 2015-2025 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
// TODO: enforce maximum input length.
16
17
use super::{Tag, TAG_LEN};
18
#[cfg(all(target_arch = "arm", target_endian = "little"))]
19
use crate::cpu::GetFeature as _;
20
use crate::{cpu, polyfill::slice::AsChunks};
21
22
mod ffi_arm_neon;
23
mod ffi_fallback;
24
25
/// A Poly1305 key.
26
pub(super) struct Key {
27
    key_and_nonce: [u8; KEY_LEN],
28
}
29
30
pub(super) const BLOCK_LEN: usize = 16;
31
pub(super) const KEY_LEN: usize = 2 * BLOCK_LEN;
32
33
impl Key {
34
    #[inline]
35
0
    pub(super) fn new(key_and_nonce: [u8; KEY_LEN]) -> Self {
36
0
        Self { key_and_nonce }
37
0
    }
38
}
39
40
pub(super) enum Context {
41
    #[cfg(all(target_arch = "arm", target_endian = "little"))]
42
    ArmNeon(ffi_arm_neon::State),
43
    Fallback(ffi_fallback::State),
44
}
45
46
impl Context {
47
    #[inline]
48
0
    pub(super) fn from_key(key: Key, cpu: cpu::Features) -> Self {
49
        #[cfg(all(target_arch = "arm", target_endian = "little"))]
50
        if let Some(cpu) = cpu.get_feature() {
51
            return ffi_arm_neon::State::new_context(key, cpu);
52
        }
53
0
        let _: cpu::Features = cpu;
54
0
        ffi_fallback::State::new_context(key)
55
0
    }
56
57
0
    pub fn update_block(&mut self, input: [u8; BLOCK_LEN]) {
58
0
        self.update(AsChunks::from_ref(&input))
59
0
    }
60
61
0
    pub fn update(&mut self, input: AsChunks<u8, BLOCK_LEN>) {
62
0
        self.update_internal(input.as_flattened());
63
0
    }
64
65
0
    fn update_internal(&mut self, input: &[u8]) {
66
0
        match self {
67
            #[cfg(all(target_arch = "arm", target_endian = "little"))]
68
            Self::ArmNeon(state) => state.update_internal(input),
69
0
            Self::Fallback(state) => state.update_internal(input),
70
        }
71
0
    }
72
73
0
    pub(super) fn finish(mut self, input: &[u8]) -> Tag {
74
0
        self.update_internal(input);
75
0
        match self {
76
            #[cfg(all(target_arch = "arm", target_endian = "little"))]
77
            Self::ArmNeon(state) => state.finish(),
78
0
            Self::Fallback(state) => state.finish(),
79
        }
80
0
    }
81
}
82
83
/// Implements the original, non-IETF padding semantics.
84
///
85
/// This is used by chacha20_poly1305_openssh and the standalone
86
/// poly1305 test vectors.
87
0
pub(super) fn sign(key: Key, input: &[u8], cpu_features: cpu::Features) -> Tag {
88
0
    let ctx = Context::from_key(key, cpu_features);
89
0
    ctx.finish(input)
90
0
}
91
92
#[cfg(test)]
93
mod tests {
94
    use super::*;
95
    use crate::testutil as test;
96
97
    // Adapted from BoringSSL's crypto/poly1305/poly1305_test.cc.
98
    #[test]
99
    pub fn test_poly1305() {
100
        let cpu_features = cpu::features();
101
        test::run(
102
            test_vector_file!("poly1305_test.txt"),
103
            |section, test_case| {
104
                assert_eq!(section, "");
105
                let key = test_case.consume_bytes("Key");
106
                let key: &[u8; KEY_LEN] = key.as_slice().try_into().unwrap();
107
                let input = test_case.consume_bytes("Input");
108
                let expected_mac = test_case.consume_bytes("MAC");
109
                let key = Key::new(*key);
110
                let Tag(actual_mac) = sign(key, &input, cpu_features);
111
                assert_eq!(expected_mac, actual_mac.as_ref());
112
113
                Ok(())
114
            },
115
        )
116
    }
117
}