1#![no_std]
2
3use gimli_permutation::{ SIZE, gimli, state_with as with };
4
5#[derive(Clone)]
6pub struct GimliAead([u32; SIZE]);
7
8impl GimliAead {
9 pub fn new(key: &[u8; 32], nonce: &[u8; 16]) -> GimliAead {
10 let mut state = [0; SIZE];
11 with(&mut state, |state| {
12 state[..16].copy_from_slice(nonce);
13 state[16..].copy_from_slice(key);
14 });
15 gimli(&mut state);
16 GimliAead(state)
17 }
18
19 fn process_aad(&mut self, aad: &[u8]) {
20 let state = &mut self.0;
21
22 let mut iter = aad.chunks_exact(16);
23
24 for chunk in &mut iter {
25 with(state, |state| {
26 for i in 0..16 {
27 state[i] ^= chunk[i];
28 }
29 });
30 gimli(state);
31 }
32
33 with(state, |state| {
34 let chunk = iter.remainder();
35 for i in 0..chunk.len() {
36 state[i] ^= chunk[i];
37 }
38
39 state[chunk.len()] ^= 1;
40 state[47] ^= 1;
41 });
42 gimli(state);
43 }
44
45 pub fn encrypt(mut self, aad: &[u8], m: &mut [u8]) -> [u8; 16] {
46 self.process_aad(aad);
47
48 let state = &mut self.0;
49 let mut iter = m.chunks_exact_mut(16);
50
51 for chunk in &mut iter {
52 with(state, |state| {
53 for i in 0..16 {
54 state[i] ^= chunk[i];
55 }
56 chunk.copy_from_slice(&state[..16]);
57 });
58 gimli(state);
59 }
60
61 with(state, |state| {
62 let chunk = iter.into_remainder();
63 for i in 0..chunk.len() {
64 state[i] ^= chunk[i];
65 }
66 chunk.copy_from_slice(&state[..chunk.len()]);
67
68 state[chunk.len()] ^= 1;
69 state[47] ^= 1;
70 });
71 gimli(state);
72
73 let mut tag = [0; 16];
74 with(state, |state| tag.copy_from_slice(&state[..16]));
75 tag
76 }
77
78 pub fn decrypt(mut self, aad: &[u8], c: &mut [u8], tag: &[u8; 16]) -> bool {
79 self.process_aad(aad);
80
81 let state = &mut self.0;
82 let mut iter = c.chunks_exact_mut(16);
83
84 for chunk in &mut iter {
85 with(state, |state| {
86 for i in 0..16 {
87 let c = chunk[i];
88 chunk[i] = state[i] ^ c;
89 state[i] = c;
90 }
91 });
92 gimli(state);
93 }
94
95 with(state, |state| {
96 let chunk = iter.into_remainder();
97 for i in 0..chunk.len() {
98 let c = chunk[i];
99 chunk[i] = state[i] ^ c;
100 state[i] = c;
101 }
102
103 state[chunk.len()] ^= 1;
104 state[47] ^= 1;
105 });
106 gimli(state);
107
108 let mut result = 0;
109 with(state, |state| {
110 for i in 0..16 {
111 result |= state[i] ^ tag[i];
112 }
113 });
114
115 result == 0
116 }
117}