/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 | | } |