1use super::{block::BLOCK_LEN, Tag, TAG_LEN};
19use crate::{c, cpu};
20
21pub(super) struct Key {
23 key_and_nonce: [u8; KEY_LEN],
24 cpu_features: cpu::Features,
25}
26
27const KEY_LEN: usize = 2 * BLOCK_LEN;
28
29impl Key {
30 #[inline]
31 pub(super) fn new(key_and_nonce: [u8; KEY_LEN], cpu_features: cpu::Features) -> Self {
32 Self {
33 key_and_nonce,
34 cpu_features,
35 }
36 }
37}
38
39pub struct Context {
40 state: poly1305_state,
41 #[allow(dead_code)]
42 cpu_features: cpu::Features,
43}
44
45#[repr(C, align(64))]
50struct poly1305_state([u8; OPAQUE_LEN]);
51const OPAQUE_LEN: usize = 512;
52
53macro_rules! dispatch {
56 ( $features:expr =>
57 ( $f:ident | $neon_f:ident )
58 ( $( $p:ident : $t:ty ),+ )
59 ( $( $a:expr ),+ ) ) => {
60 match () {
61 #[cfg(all(target_arch = "arm", not(target_vendor = "apple")))]
63 () if cpu::arm::NEON.available($features) => {
64 extern "C" {
65 fn $neon_f( $( $p : $t ),+ );
66 }
67 unsafe { $neon_f( $( $a ),+ ) }
68 }
69 () => {
70 extern "C" {
71 fn $f( $( $p : $t ),+ );
72 }
73 unsafe { $f( $( $a ),+ ) }
74 }
75 }
76 }
77}
78
79impl Context {
80 #[inline]
81 pub(super) fn from_key(
82 Key {
83 key_and_nonce,
84 cpu_features,
85 }: Key,
86 ) -> Self {
87 let mut ctx = Self {
88 state: poly1305_state([0u8; OPAQUE_LEN]),
89 cpu_features,
90 };
91
92 dispatch!(
93 cpu_features =>
94 (GFp_poly1305_init | GFp_poly1305_init_neon)
95 (statep: &mut poly1305_state, key: &[u8; KEY_LEN])
96 (&mut ctx.state, &key_and_nonce));
97
98 ctx
99 }
100
101 #[inline(always)]
102 pub fn update(&mut self, input: &[u8]) {
103 dispatch!(
104 self.cpu_features =>
105 (GFp_poly1305_update | GFp_poly1305_update_neon)
106 (statep: &mut poly1305_state, input: *const u8, in_len: c::size_t)
107 (&mut self.state, input.as_ptr(), input.len()));
108 }
109
110 pub(super) fn finish(mut self) -> Tag {
111 let mut tag = Tag([0u8; TAG_LEN]);
112 dispatch!(
113 self.cpu_features =>
114 (GFp_poly1305_finish | GFp_poly1305_finish_neon)
115 (statep: &mut poly1305_state, mac: &mut [u8; TAG_LEN])
116 (&mut self.state, &mut tag.0));
117 tag
118 }
119}
120
121pub(super) fn sign(key: Key, input: &[u8]) -> Tag {
126 let mut ctx = Context::from_key(key);
127 ctx.update(input);
128 ctx.finish()
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use crate::test;
135 use core::convert::TryInto;
136
137 #[test]
139 pub fn test_poly1305() {
140 let cpu_features = cpu::features();
141 test::run(test_file!("poly1305_test.txt"), |section, test_case| {
142 assert_eq!(section, "");
143 let key = test_case.consume_bytes("Key");
144 let key: &[u8; BLOCK_LEN * 2] = key.as_slice().try_into().unwrap();
145 let input = test_case.consume_bytes("Input");
146 let expected_mac = test_case.consume_bytes("MAC");
147 let key = Key::new(*key, cpu_features);
148 let Tag(actual_mac) = sign(key, &input);
149 assert_eq!(expected_mac, actual_mac.as_ref());
150
151 Ok(())
152 })
153 }
154}