ring/aead/
poly1305.rs
1use super::{Tag, TAG_LEN};
18#[cfg(all(target_arch = "arm", target_endian = "little"))]
19use crate::cpu::GetFeature as _;
20use crate::{cpu, polyfill::slice::AsChunks};
21
22mod ffi_arm_neon;
23mod ffi_fallback;
24
25pub(super) struct Key {
27 key_and_nonce: [u8; KEY_LEN],
28}
29
30pub(super) const BLOCK_LEN: usize = 16;
31pub(super) const KEY_LEN: usize = 2 * BLOCK_LEN;
32
33impl Key {
34 #[inline]
35 pub(super) fn new(key_and_nonce: [u8; KEY_LEN]) -> Self {
36 Self { key_and_nonce }
37 }
38}
39
40pub(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
46impl Context {
47 #[inline]
48 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 let _: cpu::Features = cpu;
54 ffi_fallback::State::new_context(key)
55 }
56
57 pub fn update_block(&mut self, input: [u8; BLOCK_LEN]) {
58 self.update(AsChunks::from_ref(&input))
59 }
60
61 pub fn update(&mut self, input: AsChunks<u8, BLOCK_LEN>) {
62 self.update_internal(input.as_flattened());
63 }
64
65 fn update_internal(&mut self, input: &[u8]) {
66 match self {
67 #[cfg(all(target_arch = "arm", target_endian = "little"))]
68 Self::ArmNeon(state) => state.update_internal(input),
69 Self::Fallback(state) => state.update_internal(input),
70 }
71 }
72
73 pub(super) fn finish(mut self, input: &[u8]) -> Tag {
74 self.update_internal(input);
75 match self {
76 #[cfg(all(target_arch = "arm", target_endian = "little"))]
77 Self::ArmNeon(state) => state.finish(),
78 Self::Fallback(state) => state.finish(),
79 }
80 }
81}
82
83pub(super) fn sign(key: Key, input: &[u8], cpu_features: cpu::Features) -> Tag {
88 let ctx = Context::from_key(key, cpu_features);
89 ctx.finish(input)
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::testutil as test;
96
97 #[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}