chiark / gitweb /
math/gfx-sqr.c: Use bithacking rather than a table for squaring.
[catacomb] / symm / rijndael-arm-crypto.S
1 /// -*- mode: asm; asm-comment-char: ?/ -*-
2 ///
3 /// ARM crypto-extension-based implementation of Rijndael
4 ///
5 /// (c) 2016 Straylight/Edgeware
6 ///
7
8 ///----- Licensing notice ---------------------------------------------------
9 ///
10 /// This file is part of Catacomb.
11 ///
12 /// Catacomb is free software; you can redistribute it and/or modify
13 /// it under the terms of the GNU Library General Public License as
14 /// published by the Free Software Foundation; either version 2 of the
15 /// License, or (at your option) any later version.
16 ///
17 /// Catacomb is distributed in the hope that it will be useful,
18 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 /// GNU Library General Public License for more details.
21 ///
22 /// You should have received a copy of the GNU Library General Public
23 /// License along with Catacomb; if not, write to the Free
24 /// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 /// MA 02111-1307, USA.
26
27 ///--------------------------------------------------------------------------
28 /// Preliminaries.
29
30 #include "config.h"
31 #include "asm-common.h"
32
33         .arch   armv8-a
34         .fpu    crypto-neon-fp-armv8
35
36         .extern F(abort)
37         .extern F(rijndael_rcon)
38
39         .text
40
41 ///--------------------------------------------------------------------------
42 /// Main code.
43
44 /// The ARM crypto extension implements a little-endian version of AES
45 /// (though the manual doesn't actually spell this out and you have to
46 /// experiment), but Catacomb's internal interface presents as big-endian so
47 /// as to work better with things like GCM.  We therefore maintain the round
48 /// keys in little-endian form, and have to end-swap blocks in and out.
49 ///
50 /// For added amusement, the crypto extension doesn't implement the larger-
51 /// block versions of Rijndael, so we have to end-swap the keys if we're
52 /// preparing for one of those.
53
54         // Useful constants.
55         .equ    maxrounds, 16           // maximum number of rounds
56         .equ    maxblksz, 32            // maximum block size, in bytes
57         .equ    kbufsz, maxblksz*(maxrounds + 1) // size of key-sched buffer
58
59         // Context structure.
60         .equ    nr, 0                   // number of rounds
61         .equ    w, nr + 4               // encryption key words
62         .equ    wi, w + kbufsz          // decryption key words
63
64 ///--------------------------------------------------------------------------
65 /// Key setup.
66
67 FUNC(rijndael_setup_arm_crypto)
68
69         // Arguments:
70         //      r0 = pointer to context
71         //      r1 = block size in words
72         //      r2 = pointer to key material
73         //      r3 = key size in words
74
75         pushreg r4-r9, r14
76
77         // The initial round key material is taken directly from the input
78         // key, so copy it over.  Unfortunately, the key material is not
79         // guaranteed to be aligned in any especially useful way, so we must
80         // sort this out.
81         add     r9, r0, #w
82         mov     r14, r3
83         ands    r6, r2, #3
84         beq     1f
85         mov     r6, r6, lsl #3
86         rsb     r7, r6, #32
87         bic     r2, r2, #3
88         ldr     r4, [r2], #4
89
90 0:      ldr     r5, [r2], #4
91         mov     r4, r4, lsr r6
92         orr     r4, r5, lsl r7
93         str     r4, [r9], #4
94         subs    r14, r14, #1
95         movhi   r4, r5
96         bhi     0b
97         b       9f
98
99 1:      ldr     r4, [r2], #4
100         str     r4, [r9], #4
101         subs    r14, r14, #1
102         bhi     1b
103
104         // Find out other useful things and prepare for the main loop.
105 9:      ldr     r7, [r0, #nr]           // number of rounds
106         mla     r2, r1, r7, r1          // total key size in words
107         leaextq r5, rijndael_rcon       // round constants
108         sub     r8, r2, r3              // minus what we've copied already
109         vmov.i32 q1, #0                 // all-zero register for the key
110         add     r8, r9, r8, lsl #2      // limit of the key buffer
111         mov     r12, #0                 // position in current cycle
112
113         // Main key expansion loop.  Dispatch according to the position in
114         // the cycle.
115 0:      ldr     r6, [r9, -r3, lsl #2]   // word from previous cycle
116         cmp     r12, #0                 // first word of the cycle?
117         beq     1f
118         cmp     r12, #4                 // fourth word of the cycle?
119         bne     2f
120         cmp     r3, #7                  // seven or eight words of key?
121         bcc     2f
122
123         // Fourth word of the cycle, seven or eight words of key.  We must do
124         // the byte substitution.
125         vdup.32 q0, r4
126         aese.8  q0, q1                  // effectively, just SubBytes
127         vmov.32 r4, d0[0]
128         b       2f
129
130         // First word of the cycle.  Byte substitution, rotation, and round
131         // constant.
132 1:      ldrb    r14, [r5], #1           // next round constant
133         vdup.32 q0, r4
134         aese.8  q0, q1                  // effectively, just SubBytes
135         vmov.32 r4, d0[0]
136         eor     r4, r14, r4, ror #8
137
138         // Common ending: mix in the word from the previous cycle and store.
139 2:      eor     r4, r4, r6
140         str     r4, [r9], #4
141
142         // Prepare for the next iteration.  If we're done, then stop; if
143         // we've finished a cycle then reset the counter.
144         add     r12, r12, #1
145         cmp     r9, r8
146         bcs     9f
147         cmp     r12, r3
148         movcs   r12, #0
149         b       0b
150
151         // Next job is to construct the decryption keys.  The keys for the
152         // first and last rounds don't need to be mangled, but the remaining
153         // ones do -- and they all need to be reordered too.
154         //
155         // The plan of action, then, is to copy the final encryption round's
156         // keys into place first, then to do each of the intermediate rounds
157         // in reverse order, and finally do the first round.
158         //
159         // Do all the heavy lifting with NEON registers.  The order we're
160         // doing this in means that it's OK if we read or write too much, and
161         // there's easily enough buffer space for the over-enthusiastic reads
162         // and writes because the context has space for 32-byte blocks, which
163         // is our maximum and an exact fit for two Q-class registers.
164 9:      add     r5, r0, #wi
165         add     r4, r0, #w
166         add     r4, r4, r2, lsl #2
167         sub     r4, r4, r1, lsl #2              // last round's keys
168
169         // Copy the last encryption round's keys.
170         teq     r1, #4
171         vldmiaeq r4, {d0, d1}
172         vldmiane r4, {d0-d3}
173         vstmiaeq r5, {d0, d1}
174         vstmiane r5, {d0-d3}
175
176         // Update the loop variables and stop if we've finished.
177 0:      sub     r4, r4, r1, lsl #2
178         add     r5, r5, r1, lsl #2
179         subs    r7, r7, #1
180         beq     9f
181
182         // Do another middle round's keys...
183         teq     r1, #4
184         vldmiaeq r4, {d0, d1}
185         vldmiane r4, {d0-d3}
186         aesimc.8 q0, q0
187         vstmiaeq r5, {d0, d1}
188         beq     0b
189         aesimc.8 q1, q1
190         vstmia  r5, {d0-d3}
191         b       0b
192
193         // Finally do the first encryption round.
194 9:      teq     r1, #4
195         vldmiaeq r4, {d0, d1}
196         vldmiane r4, {d0-d3}
197         vstmiaeq r5, {d0, d1}
198         vstmiane r5, {d0-d3}
199
200         // If the block size is not exactly four words then we must end-swap
201         // everything.  We can use fancy NEON toys for this.
202         beq     9f
203
204         // End-swap the encryption keys.
205         add     r1, r0, #w
206         bl      endswap_block
207
208         // And the decryption keys
209         add     r1, r0, #wi
210         bl      endswap_block
211
212         // All done.
213 9:      popreg  r4-r9, pc
214
215 ENDFUNC
216
217 INTFUNC(endswap_block)
218         // End-swap R2 words starting at R1.  R1 is clobbered; R2 is not.
219         // It's OK to work in 16-byte chunks.
220
221         mov     r4, r2
222 0:      vldmia  r1, {d0, d1}
223         vrev32.8 q0, q0
224         vstmia  r1!, {d0, d1}
225         subs    r4, r4, #4
226         bhi     0b
227         bx      r14
228
229 ENDFUNC
230
231 ///--------------------------------------------------------------------------
232 /// Encrypting and decrypting blocks.
233
234 .macro  encdec  op, aes, mc, koff
235   FUNC(rijndael_\op\()_arm_crypto)
236
237         // Arguments:
238         //      r0 = pointer to context
239         //      r1 = pointer to input block
240         //      r2 = pointer to output block
241
242         // Set things up ready.
243         ldr     r3, [r0, #nr]
244         add     r0, r0, #\koff
245         vldmia  r1, {d0, d1}
246         vrev32.8 q0, q0
247
248         // Check the number of rounds and dispatch.
249         sub     r3, r3, #10
250         cmp     r3, #5
251         addlo   pc, pc, r3, lsl #2
252         callext F(abort)
253
254         b       10f
255         b       11f
256         b       12f
257         b       13f
258         b       14f
259
260         // Eleven rounds.
261 11:     vldmia  r0!, {d16, d17}
262         \aes\().8 q0, q8
263         \mc\().8 q0, q0
264         b       10f
265
266         // Twelve rounds.
267 12:     vldmia  r0!, {d16-d19}
268         \aes\().8 q0, q8
269         \mc\().8 q0, q0
270         \aes\().8 q0, q9
271         \mc\().8 q0, q0
272         b       10f
273
274         // Thirteen rounds.
275 13:     vldmia  r0!, {d16-d21}
276         \aes\().8 q0, q8
277         \mc\().8 q0, q0
278         \aes\().8 q0, q9
279         \mc\().8 q0, q0
280         \aes\().8 q0, q10
281         \mc\().8 q0, q0
282         b       10f
283
284         // Fourteen rounds.  (Drops through to the ten round case because
285         // this is the next most common.)
286 14:     vldmia  r0!, {d16-d23}
287         \aes\().8 q0, q8
288         \mc\().8 q0, q0
289         \aes\().8 q0, q9
290         \mc\().8 q0, q0
291         \aes\().8 q0, q10
292         \mc\().8 q0, q0
293         \aes\().8 q0, q11
294         \mc\().8 q0, q0
295         // Drop through...
296
297         // Ten rounds.
298 10:     vldmia  r0!, {d16-d25}
299         \aes\().8 q0, q8
300         \mc\().8 q0, q0
301         \aes\().8 q0, q9
302         \mc\().8 q0, q0
303         \aes\().8 q0, q10
304         \mc\().8 q0, q0
305         \aes\().8 q0, q11
306         \mc\().8 q0, q0
307         \aes\().8 q0, q12
308         \mc\().8 q0, q0
309
310         vldmia  r0!, {d16-d27}
311         \aes\().8 q0, q8
312         \mc\().8 q0, q0
313         \aes\().8 q0, q9
314         \mc\().8 q0, q0
315         \aes\().8 q0, q10
316         \mc\().8 q0, q0
317         \aes\().8 q0, q11
318         \mc\().8 q0, q0
319
320         // Final round has no MixColumns, but is followed by final whitening.
321         \aes\().8 q0, q12
322         veor    q0, q0, q13
323
324         // All done.
325         vrev32.8 q0, q0
326         vstmia  r2, {d0, d1}
327         bx      r14
328
329   ENDFUNC
330 .endm
331
332         encdec  eblk, aese, aesmc, w
333         encdec  dblk, aesd, aesimc, wi
334
335 ///----- That's all, folks --------------------------------------------------