Add "teaser" AES module for ARMv8.
[oweals/openssl.git] / crypto / aes / asm / aesv8-armx.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # This module implements support for ARMv8 AES instructions. The
11 # module is endian-agnostic in sense that it supports both big- and
12 # little-endian cases. As does it support both 32- and 64-bit modes
13 # of operation. Latter is achieved by limiting amount of utilized
14 # registers to 16, which implies additional instructions. This has
15 # no effect on mighty Apple A7, as results are literally equal to
16 # the theoretical estimates. It remains to be seen how does it
17 # affect other platforms...
18 #
19 # Performance in cycles per byte processed with 128-bit key:
20 #
21 #               CBC enc         CBC dec
22 # Apple A7      2.39            1.20
23
24 $flavour = shift;
25 $prefix="AES";
26
27 $code=".text\n";
28 $code.=".arch   armv8-a+crypto\n"       if ($flavour =~ /64/);
29 $code.=".fpu    neon\n.code     32\n"   if ($flavour !~ /64/);
30
31 # Assembler mnemonics are an eclectic mix of 32- and 64-bit syntax,
32 # NEON is mostly 32-bit mnemonics, integer - mostly 64. Goal is to
33 # maintain both 32- and 64-bit codes within single module and
34 # transliterate common code to either flavour with regex vodoo.
35 #
36 {{{
37 my ($inp,$bits,$out,$ptr,$rounds)=("x0","w1","x2","x3","w12");
38 my ($zero,$rcon,$mask,$in0,$in1,$tmp,$key)=
39         $flavour=~/64/? map("q$_",(0..6)) : map("q$_",(0..3,8..10));
40
41
42 $code.=<<___;
43 .align  5
44 rcon:
45 .long   0x01,0x01,0x01,0x01
46 .long   0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d     // rotate-n-splat
47 .long   0x1b,0x1b,0x1b,0x1b
48
49 .globl  ${prefix}_set_encrypt_key
50 .type   ${prefix}_set_encrypt_key,%function
51 .align  5
52 ${prefix}_set_encrypt_key:
53 .Lenc_key:
54 ___
55 $code.=<<___    if ($flavour =~ /64/);
56         stp     x29,x30,[sp,#-16]!
57         add     x29,sp,#0
58 ___
59 $code.=<<___;
60         adr     $ptr,rcon
61         cmp     $bits,#192
62
63         veor    $zero,$zero,$zero
64         vld1.8  {$in0},[$inp],#16
65         mov     $bits,#8                // reuse $bits
66         vld1.32 {$rcon,$mask},[$ptr],#32
67
68         b.lt    .Loop128
69         b.eq    .L192
70         b       .L256
71
72 .align  4
73 .Loop128:
74         vtbl.8  $key,{$in0},$mask
75         vext.8  $tmp,$zero,$in0,#12
76         vst1.32 {$in0},[$out],#16
77         aese    $key,$zero
78         subs    $bits,$bits,#1
79
80         veor    $in0,$in0,$tmp
81         vext.8  $tmp,$zero,$tmp,#12
82         veor    $in0,$in0,$tmp
83         vext.8  $tmp,$zero,$tmp,#12
84          veor   $key,$key,$rcon
85         veor    $in0,$in0,$tmp
86         vshl.u8 $rcon,$rcon,#1
87         veor    $in0,$in0,$key
88         b.ne    .Loop128
89
90         vld1.32 {$rcon},[$ptr]
91
92         vtbl.8  $key,{$in0},$mask
93         vext.8  $tmp,$zero,$in0,#12
94         vst1.32 {$in0},[$out],#16
95         aese    $key,$zero
96
97         veor    $in0,$in0,$tmp
98         vext.8  $tmp,$zero,$tmp,#12
99         veor    $in0,$in0,$tmp
100         vext.8  $tmp,$zero,$tmp,#12
101          veor   $key,$key,$rcon
102         veor    $in0,$in0,$tmp
103         vshl.u8 $rcon,$rcon,#1
104         veor    $in0,$in0,$key
105
106         vtbl.8  $key,{$in0},$mask
107         vext.8  $tmp,$zero,$in0,#12
108         vst1.32 {$in0},[$out],#16
109         aese    $key,$zero
110
111         veor    $in0,$in0,$tmp
112         vext.8  $tmp,$zero,$tmp,#12
113         veor    $in0,$in0,$tmp
114         vext.8  $tmp,$zero,$tmp,#12
115          veor   $key,$key,$rcon
116         veor    $in0,$in0,$tmp
117         veor    $in0,$in0,$key
118         vst1.32 {$in0},[$out]
119         add     $out,$out,#0x50
120
121         mov     $rounds,#10
122         b       .Ldone
123
124 .align  4
125 .L192:
126         vld1.8  {$in1},[$inp],#8
127         vmov.i8 $key,#8                 // borrow $key
128         vst1.32 {$in0},[$out],#16
129         vsub.i8 $mask,$mask,$key        // adjust the mask
130
131 .Loop192:
132         vtbl.8  $key,{$in1},$mask
133         vext.8  $tmp,$zero,$in0,#12
134         vst1.32 {$in1},[$out],#8
135         aese    $key,$zero
136         subs    $bits,$bits,#1
137
138         veor    $in0,$in0,$tmp
139         vext.8  $tmp,$zero,$tmp,#12
140         veor    $in0,$in0,$tmp
141         vext.8  $tmp,$zero,$tmp,#12
142         veor    $in0,$in0,$tmp
143
144         vdup.32 $tmp,${in0}[3]
145         veor    $tmp,$tmp,$in1
146          veor   $key,$key,$rcon
147         vext.8  $in1,$zero,$in1,#12
148         vshl.u8 $rcon,$rcon,#1
149         veor    $in1,$in1,$tmp
150         veor    $in0,$in0,$key
151         veor    $in1,$in1,$key
152         vst1.32 {$in0},[$out],#16
153         b.ne    .Loop192
154
155         mov     $rounds,#12
156         add     $out,$out,#0x20
157         b       .Ldone
158
159 .align  4
160 .L256:
161         vld1.8  {$in1},[$inp]
162         mov     $bits,#7
163         mov     $rounds,#14
164         vst1.32 {$in0},[$out],#16
165
166 .Loop256:
167         vtbl.8  $key,{$in1},$mask
168         vext.8  $tmp,$zero,$in0,#12
169         vst1.32 {$in1},[$out],#16
170         aese    $key,$zero
171         subs    $bits,$bits,#1
172
173         veor    $in0,$in0,$tmp
174         vext.8  $tmp,$zero,$tmp,#12
175         veor    $in0,$in0,$tmp
176         vext.8  $tmp,$zero,$tmp,#12
177          veor   $key,$key,$rcon
178         veor    $in0,$in0,$tmp
179         vshl.u8 $rcon,$rcon,#1
180         veor    $in0,$in0,$key
181         vst1.32 {$in0},[$out],#16
182         b.eq    .Ldone
183
184         vdup.32 $key,${in0}[3]          // just splat
185         vext.8  $tmp,$zero,$in1,#12
186         aese    $key,$zero
187
188         veor    $in1,$in1,$tmp
189         vext.8  $tmp,$zero,$tmp,#12
190         veor    $in1,$in1,$tmp
191         vext.8  $tmp,$zero,$tmp,#12
192         veor    $in1,$in1,$tmp
193
194         veor    $in1,$in1,$key
195         b       .Loop256
196
197 .Ldone:
198         str     $rounds,[$out]
199
200         eor     x0,x0,x0                // return value
201         `"ldr   x29,[sp],#16"           if ($flavour =~ /64/)`
202         ret
203 .size   ${prefix}_set_encrypt_key,.-${prefix}_set_encrypt_key
204
205 .globl  ${prefix}_set_decrypt_key
206 .type   ${prefix}_set_decrypt_key,%function
207 .align  5
208 ${prefix}_set_decrypt_key:
209 ___
210 $code.=<<___    if ($flavour =~ /64/);
211         stp     x29,x30,[sp,#-16]!
212         add     x29,sp,#0
213 ___
214 $code.=<<___    if ($flavour !~ /64/);
215         stmdb   sp!,{r4,lr}
216 ___
217 $code.=<<___;
218         bl      .Lenc_key
219
220         sub     $out,$out,#240          // restore original $out
221         mov     x4,#-16
222         add     $inp,$out,x12,lsl#4     // end of key schedule
223
224         vld1.32 {v0.16b},[$out]
225         vld1.32 {v1.16b},[$inp]
226         vst1.32 {v0.16b},[$inp],x4
227         vst1.32 {v1.16b},[$out],#16
228
229 .Loop_imc:
230         vld1.32 {v0.16b},[$out]
231         vld1.32 {v1.16b},[$inp]
232         aesimc  v0.16b,v0.16b
233         aesimc  v1.16b,v1.16b
234         vst1.32 {v0.16b},[$inp],x4
235         vst1.32 {v1.16b},[$out],#16
236         cmp     $inp,$out
237         b.hi    .Loop_imc
238
239         vld1.32 {v0.16b},[$out]
240         aesimc  v0.16b,v0.16b
241         vst1.32 {v0.16b},[$inp]
242
243         eor     x0,x0,x0                // return value
244 ___
245 $code.=<<___    if ($flavour !~ /64/);
246         ldmia   sp!,{r4,pc}
247 ___
248 $code.=<<___    if ($flavour =~ /64/);
249         ldp     x29,x30,[sp],#16
250         ret
251 ___
252 $code.=<<___;
253 .size   ${prefix}_set_decrypt_key,.-${prefix}_set_decrypt_key
254 ___
255 }}}
256 {{{
257 sub gen_block () {
258 my $dir = shift;
259 my ($e,$mc) = $dir eq "en" ? ("e","mc") : ("d","imc");
260 my ($inp,$out,$key)=map("x$_",(0..2));
261 my $rounds="w3";
262 my ($rndkey0,$rndkey1,$inout)=map("q$_",(0..3));
263
264 $code.=<<___;
265 .globl  ${prefix}_${dir}crypt
266 .type   ${prefix}_${dir}crypt,%function
267 .align  5
268 ${prefix}_${dir}crypt:
269         ldr     $rounds,[$key,#240]
270         vld1.32 {$rndkey0},[$key],#16
271         vld1.8  {$inout},[$inp]
272         sub     $rounds,$rounds,#2
273         vld1.32 {$rndkey1},[$key],#16
274
275 .Loop_${dir}c:
276         aes$e   $inout,$rndkey0
277         aes$mc  $inout,$inout
278         vld1.32 {$rndkey0},[$key],#16
279         subs    $rounds,$rounds,#2
280         aes$e   $inout,$rndkey1
281         aes$mc  $inout,$inout
282         vld1.32 {$rndkey1},[$key],#16
283         b.gt    .Loop_${dir}c
284
285         aes$e   $inout,$rndkey0
286         aes$mc  $inout,$inout
287         vld1.32 {$rndkey0},[$key]
288         aes$e   $inout,$rndkey1
289         veor    $inout,$inout,$rndkey0
290
291         vst1.8  {$inout},[$out]
292         ret
293 .size   ${prefix}_${dir}crypt,.-${prefix}_${dir}crypt
294 ___
295 }
296 &gen_block("en");
297 &gen_block("de");
298 }}}
299 {{{
300 my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); my $enc="w5";
301 my ($rounds,$cnt,$key_,$step)=($enc,"w6","x7","x8");
302 my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7));
303
304 my ($dat,$tmp,$rndzero_n_last)=($dat0,$tmp0,$tmp1);
305
306 ### q8-q15      preloaded key schedule
307
308 $code.=<<___;
309 .globl  ${prefix}_cbc_encrypt
310 .type   ${prefix}_cbc_encrypt,%function
311 .align  5
312 ${prefix}_cbc_encrypt:
313 ___
314 $code.=<<___    if ($flavour =~ /64/);
315         stp     x29,x30,[sp,#-16]!
316         add     x29,sp,#0
317 ___
318 $code.=<<___    if ($flavour !~ /64/);
319         mov     ip,sp
320         stmdb   sp!,{r4-r8,lr}
321         vstmdb  sp!,{d8-d15}            @ ABI specification says so
322         ldmia   ip,{r4-r5}              @ load remaining args
323 ___
324 $code.=<<___;
325         subs    $len,$len,#16
326         mov     $step,#16
327         b.lo    .Lcbc_abort
328         cclr    $step,eq
329
330         cmp     $enc,#0                 // en- or decrypting?
331         ldr     $rounds,[$key,#240]
332         and     $len,$len,#-16
333         vld1.8  {$ivec},[$ivp]
334         vld1.8  {$dat},[$inp],$step
335
336         vld1.32 {q8-q9},[$key]          // load key schedule...
337         sub     $rounds,$rounds,#6
338         add     $key_,$key,x5,lsl#4     // pointer to last 7 round keys
339         sub     $rounds,$rounds,#2
340         vld1.32 {q10-q11},[$key_],#32
341         vld1.32 {q12-q13},[$key_],#32
342         vld1.32 {q14-q15},[$key_],#32
343         vld1.32 {$rndlast},[$key_]
344
345         add     $key_,$key,#32
346         mov     $cnt,$rounds
347         b.eq    .Lcbc_dec
348
349         veor    $dat,$dat,$ivec
350         veor    $rndzero_n_last,q8,$rndlast
351 .Loop_cbc_enc:
352         aese    $dat,q8
353         aesmc   $dat,$dat
354         vld1.32 {q8},[$key_],#16
355         subs    $cnt,$cnt,#2
356         aese    $dat,q9
357         aesmc   $dat,$dat
358         vld1.32 {q9},[$key_],#16
359         b.gt    .Loop_cbc_enc
360
361         aese    $dat,q8
362         aesmc   $dat,$dat
363          subs   $len,$len,#16
364         aese    $dat,q9
365         aesmc   $dat,$dat
366          cclr   $step,eq
367         aese    $dat,q10
368         aesmc   $dat,$dat
369          add    $key_,$key,#16
370         aese    $dat,q11
371         aesmc   $dat,$dat
372          vld1.8 {q8},[$inp],$step
373         aese    $dat,q12
374         aesmc   $dat,$dat
375          veor   q8,q8,$rndzero_n_last
376         aese    $dat,q13
377         aesmc   $dat,$dat
378          vld1.32 {q9},[$key_],#16       // re-pre-load rndkey[1]
379         aese    $dat,q14
380         aesmc   $dat,$dat
381         aese    $dat,q15
382
383          mov    $cnt,$rounds
384         veor    $ivec,$dat,$rndlast
385         vst1.8  {$ivec},[$out],#16
386         b.hs    .Loop_cbc_enc
387
388         b       .Lcbc_done
389
390 .align  5
391 .Lcbc_dec:
392         subs    $len,$len,#16
393         vorr    $in0,$dat,$dat
394         b.lo    .Lcbc_dec_tail
395
396         cclr    $step,eq
397         vld1.8  {$dat1},[$inp],$step
398         vorr    $in1,$dat1,$dat1
399
400 .Loop2x_cbc_dec:
401         aesd    $dat0,q8
402         aesd    $dat1,q8
403         aesimc  $dat0,$dat0
404         aesimc  $dat1,$dat1
405         vld1.64 {q8},[$key_],#16
406         subs    $cnt,$cnt,#2
407         aesd    $dat0,q9
408         aesd    $dat1,q9
409         aesimc  $dat0,$dat0
410         aesimc  $dat1,$dat1
411         vld1.64 {q9},[$key_],#16
412         b.gt    .Loop2x_cbc_dec
413
414         aesd    $dat0,q8
415         aesd    $dat1,q8
416         aesimc  $dat0,$dat0
417          veor   $tmp0,$ivec,$rndlast
418         aesimc  $dat1,$dat1
419          veor   $tmp1,$in0,$rndlast
420         aesd    $dat0,q9
421         aesd    $dat1,q9
422         aesimc  $dat0,$dat0
423          vorr   $ivec,$in1,$in1
424         aesimc  $dat1,$dat1
425          subs   $len,$len,#32
426         aesd    $dat0,q10
427         aesd    $dat1,q10
428         aesimc  $dat0,$dat0
429          cclr   $step,lo
430         aesimc  $dat1,$dat1
431          mov    $key_,$key
432         aesd    $dat0,q11
433         aesd    $dat1,q11
434         aesimc  $dat0,$dat0
435          vld1.8 {$in0},[$inp],$step
436         aesimc  $dat1,$dat1
437          cclr   $step,ls
438         aesd    $dat0,q12
439         aesd    $dat1,q12
440         aesimc  $dat0,$dat0
441         aesimc  $dat1,$dat1
442          vld1.8 {$in1},[$inp],$step
443         aesd    $dat0,q13
444         aesd    $dat1,q13
445         aesimc  $dat0,$dat0
446         aesimc  $dat1,$dat1
447          vld1.32 {q8},[$key_],#16       // re-pre-load rndkey[0]
448         aesd    $dat0,q14
449         aesd    $dat1,q14
450         aesimc  $dat0,$dat0
451         aesimc  $dat1,$dat1
452          vld1.32 {q9},[$key_],#16       // re-pre-load rndkey[1]
453         aesd    $dat0,q15
454         aesd    $dat1,q15
455
456          mov    $cnt,$rounds
457         veor    $tmp0,$tmp0,$dat0
458          vorr   $dat0,$in0,$in0
459         veor    $tmp1,$tmp1,$dat1
460          vorr   $dat1,$in1,$in1
461         vst1.8  {$tmp0-$tmp1},[$out],#32
462         b.hs    .Loop2x_cbc_dec
463
464         adds    $len,$len,#32
465         b.eq    .Lcbc_done
466
467 .Lcbc_dec_tail:
468         aesd    $dat,q8
469         aesimc  $dat,$dat
470         vld1.64 {q8},[$key_],#16
471         subs    $cnt,$cnt,#2
472         aesd    $dat,q9
473         aesimc  $dat,$dat
474         vld1.64 {q9},[$key_],#16
475         b.gt    .Lcbc_dec_tail
476
477         aesd    $dat,q8
478         aesimc  $dat,$dat
479         aesd    $dat,q9
480         aesimc  $dat,$dat
481          veor   $tmp,$ivec,$rndlast
482         aesd    $dat,q10
483         aesimc  $dat,$dat
484          vorr   $ivec,$in0,$in0
485         aesd    $dat,q11
486         aesimc  $dat,$dat
487         aesd    $dat,q12
488         aesimc  $dat,$dat
489         aesd    $dat,q13
490         aesimc  $dat,$dat
491         aesd    $dat,q14
492         aesimc  $dat,$dat
493         aesd    $dat,q15
494
495         veor    $tmp,$tmp,$dat
496         vst1.8  {$tmp},[$out],#16
497
498 .Lcbc_done:
499         vst1.8  {$ivec},[$ivp]
500 .Lcbc_abort:
501 ___
502 $code.=<<___    if ($flavour !~ /64/);
503         vldmia  sp!,{d8-d15}
504         ldmia   sp!,{r4-r8,pc}
505 ___
506 $code.=<<___    if ($flavour =~ /64/);
507         ldr     x29,[sp],#16
508         ret
509 ___
510 $code.=<<___;
511 .size   ${prefix}_cbc_encrypt,.-${prefix}_cbc_encrypt
512 ___
513 }}}
514 ########################################
515 if ($flavour =~ /64/) {                 ######## 64-bit code
516     my %opcode = (
517         "aesd"  =>      0x4e285800,     "aese"  =>      0x4e284800,
518         "aesimc"=>      0x4e287800,     "aesmc" =>      0x4e286800      );
519
520     sub unaes {
521         my ($mnemonic,$arg)=@_;
522
523         $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o   &&
524         sprintf ".long\t0x%08x\t//%s %s",
525                         $opcode{$mnemonic}|$1|($2<<5),
526                         $mnemonic,$arg;
527     }
528
529     foreach(split("\n",$code)) {
530         s/\`([^\`]*)\`/eval($1)/geo;
531
532         s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo;  # old->new registers
533         s/@\s/\/\//o;                   # old->new style commentary
534
535         #s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo     or
536         s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel $1$2,$1zr,$1$2,$3/o     or
537         s/vmov\.i8/movi/o       or      # fix up legacy mnemonics
538         s/vext\.8/ext/o         or
539         s/vrev32\.8/rev32/o     or
540         s/vtst\.8/cmtst/o       or
541         s/vshr/ushr/o           or
542         s/^(\s+)v/$1/o          or      # strip off v prefix
543         s/\bbx\s+lr\b/ret/o;
544
545         # fix up remainig legacy suffixes
546         s/\.[ui]?8//o;
547         m/\],#8/o and s/\.16b/\.8b/go;
548         s/\.[ui]?32//o and s/\.16b/\.4s/go;
549         s/\.[ui]?64//o and s/\.16b/\.2d/go;
550         s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o;
551
552         print $_,"\n";
553     }
554 } else {                                ######## 32-bit code
555     my %opcode = (
556         "aesd"  =>      0xf3b00340,     "aese"  =>      0xf3b00300,
557         "aesimc"=>      0xf3b003c0,     "aesmc" =>      0xf3b00380      );
558
559     sub unaes {
560         my ($mnemonic,$arg)=@_;
561
562         $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o   &&
563         sprintf ".long\t0x%08x\t@ %s %s",
564                         $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
565                                           |(($2&7)<<1) |(($2&8)<<2),
566                         $mnemonic,$arg;
567     }
568
569     sub unvtbl {
570         my $arg=shift;
571
572         $arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o &&
573         sprintf "vtbl.8 d%d,{q%d},d%d\n\tvtbl.8 d%d,{q%d},d%d",2*$1,$2,2*$3,2*$1+1,$2,2*$3+1;   
574     }
575
576     sub unvdup32 {
577         my $arg=shift;
578
579         $arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o &&
580         sprintf "vdup.32        q%d,d%d[%d]",$1,2*$2+$3>>1,$3&1;        
581     }
582
583     foreach(split("\n",$code)) {
584         s/\`([^\`]*)\`/eval($1)/geo;
585
586         s/\b[wx]([0-9]+)\b/r$1/go;              # new->old registers
587         s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go;   # new->old registers
588         s/\/\/\s?/@ /o;                         # new->old style commentary
589
590         # fix up remainig new-style suffixes
591         s/\],#[0-9]+/]!/o;
592
593         s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo      or
594         s/cclr\s+([^,]+),\s*([a-z]+)/mov$2      $1,#0/o or
595         s/vtbl\.8\s+(.*)/unvtbl($1)/geo                 or
596         s/vdup\.32\s+(.*)/unvdup32($1)/geo              or
597         s/^(\s+)b\./$1b/o                               or
598         s/^(\s+)ret/$1bx\tlr/o;
599
600         print $_,"\n";
601     }
602 }
603
604 close STDOUT;