2 # Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
4 # Licensed under the OpenSSL license (the "License"). You may not use
5 # this file except in compliance with the License. You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
10 # ====================================================================
11 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
12 # project. The module is, however, dual licensed under OpenSSL and
13 # CRYPTOGAMS licenses depending on where you obtain it. For further
14 # details see http://www.openssl.org/~appro/cryptogams/.
15 # ====================================================================
21 # Performance in cycles per byte out of large buffer.
23 # IALU/gcc-4.4 1xNEON 3xNEON+1xIALU
25 # Cortex-A5 19.3(*)/+95% 21.8 14.1
26 # Cortex-A8 10.5(*)/+160% 13.9 6.35
27 # Cortex-A9 12.9(**)/+110% 14.3 6.50
28 # Cortex-A15 11.0/+40% 16.0 5.00
29 # Snapdragon S4 11.5/+125% 13.6 4.90
31 # (*) most "favourable" result for aligned data on little-endian
32 # processor, result for misaligned data is 10-15% lower;
33 # (**) this result is a trade-off: it can be improved by 20%,
34 # but then Snapdragon S4 and Cortex-A8 results get
38 if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
39 else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
41 if ($flavour && $flavour ne "void") {
42 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
43 ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
44 ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
45 die "can't locate arm-xlate.pl";
47 open STDOUT,"| \"$^X\" $xlate $flavour $output";
49 open STDOUT,">$output";
52 sub AUTOLOAD() # thunk [simplified] x86-style perlasm
53 { my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
55 $arg = "#$arg" if ($arg*1 eq $arg);
56 $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
59 my @x=map("r$_",(0..7,"x","x","x","x",12,"x",14,"x"));
60 my @t=map("r$_",(8..11));
63 my ($a0,$b0,$c0,$d0)=@_;
64 my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
65 my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
66 my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
68 my ($xc,$xc_) = (@t[0..1]);
69 my ($xd,$xd_) = $odd ? (@t[2],@x[$d1]) : (@x[$d0],@t[2]);
72 # Consider order in which variables are addressed by their
77 # 0 4 8 12 < even round
81 # 0 5 10 15 < odd round
86 # 'a', 'b' are permanently allocated in registers, @x[0..7],
87 # while 'c's and pair of 'd's are maintained in memory. If
88 # you observe 'c' column, you'll notice that pair of 'c's is
89 # invariant between rounds. This means that we have to reload
90 # them once per round, in the middle. This is why you'll see
91 # bunch of 'c' stores and loads in the middle, but none in
92 # the beginning or end. If you observe 'd' column, you'll
93 # notice that 15 and 13 are reused in next pair of rounds.
94 # This is why these two are chosen for offloading to memory,
95 # to make loads count more.
97 "&add (@x[$a0],@x[$a0],@x[$b0])",
98 "&mov ($xd,$xd,'ror#16')",
99 "&add (@x[$a1],@x[$a1],@x[$b1])",
100 "&mov ($xd_,$xd_,'ror#16')",
101 "&eor ($xd,$xd,@x[$a0],'ror#16')",
102 "&eor ($xd_,$xd_,@x[$a1],'ror#16')",
104 "&add ($xc,$xc,$xd)",
105 "&mov (@x[$b0],@x[$b0],'ror#20')",
106 "&add ($xc_,$xc_,$xd_)",
107 "&mov (@x[$b1],@x[$b1],'ror#20')",
108 "&eor (@x[$b0],@x[$b0],$xc,'ror#20')",
109 "&eor (@x[$b1],@x[$b1],$xc_,'ror#20')",
111 "&add (@x[$a0],@x[$a0],@x[$b0])",
112 "&mov ($xd,$xd,'ror#24')",
113 "&add (@x[$a1],@x[$a1],@x[$b1])",
114 "&mov ($xd_,$xd_,'ror#24')",
115 "&eor ($xd,$xd,@x[$a0],'ror#24')",
116 "&eor ($xd_,$xd_,@x[$a1],'ror#24')",
118 "&add ($xc,$xc,$xd)",
119 "&mov (@x[$b0],@x[$b0],'ror#25')" );
121 "&str ($xd,'[sp,#4*(16+$d0)]')",
122 "&ldr ($xd,'[sp,#4*(16+$d2)]')" ) if ($odd);
124 "&add ($xc_,$xc_,$xd_)",
125 "&mov (@x[$b1],@x[$b1],'ror#25')" );
127 "&str ($xd_,'[sp,#4*(16+$d1)]')",
128 "&ldr ($xd_,'[sp,#4*(16+$d3)]')" ) if (!$odd);
130 "&eor (@x[$b0],@x[$b0],$xc,'ror#25')",
131 "&eor (@x[$b1],@x[$b1],$xc_,'ror#25')" );
133 $xd=@x[$d2] if (!$odd);
134 $xd_=@x[$d3] if ($odd);
136 "&str ($xc,'[sp,#4*(16+$c0)]')",
137 "&ldr ($xc,'[sp,#4*(16+$c2)]')",
138 "&add (@x[$a2],@x[$a2],@x[$b2])",
139 "&mov ($xd,$xd,'ror#16')",
140 "&str ($xc_,'[sp,#4*(16+$c1)]')",
141 "&ldr ($xc_,'[sp,#4*(16+$c3)]')",
142 "&add (@x[$a3],@x[$a3],@x[$b3])",
143 "&mov ($xd_,$xd_,'ror#16')",
144 "&eor ($xd,$xd,@x[$a2],'ror#16')",
145 "&eor ($xd_,$xd_,@x[$a3],'ror#16')",
147 "&add ($xc,$xc,$xd)",
148 "&mov (@x[$b2],@x[$b2],'ror#20')",
149 "&add ($xc_,$xc_,$xd_)",
150 "&mov (@x[$b3],@x[$b3],'ror#20')",
151 "&eor (@x[$b2],@x[$b2],$xc,'ror#20')",
152 "&eor (@x[$b3],@x[$b3],$xc_,'ror#20')",
154 "&add (@x[$a2],@x[$a2],@x[$b2])",
155 "&mov ($xd,$xd,'ror#24')",
156 "&add (@x[$a3],@x[$a3],@x[$b3])",
157 "&mov ($xd_,$xd_,'ror#24')",
158 "&eor ($xd,$xd,@x[$a2],'ror#24')",
159 "&eor ($xd_,$xd_,@x[$a3],'ror#24')",
161 "&add ($xc,$xc,$xd)",
162 "&mov (@x[$b2],@x[$b2],'ror#25')",
163 "&add ($xc_,$xc_,$xd_)",
164 "&mov (@x[$b3],@x[$b3],'ror#25')",
165 "&eor (@x[$b2],@x[$b2],$xc,'ror#25')",
166 "&eor (@x[$b3],@x[$b3],$xc_,'ror#25')" );
172 #include "arm_arch.h"
175 #if defined(__thumb2__) || defined(__clang__)
178 #if defined(__thumb2__)
184 #if defined(__thumb2__) || defined(__clang__)
185 #define ldrhsb ldrbhs
190 .long 0x61707865,0x3320646e,0x79622d32,0x6b206574 @ endian-neutral
193 #if __ARM_MAX_ARCH__>=7
195 .word OPENSSL_armcap_P-.LChaCha20_ctr32
200 .globl ChaCha20_ctr32
201 .type ChaCha20_ctr32,%function
205 ldr r12,[sp,#0] @ pull pointer to counter and nonce
206 stmdb sp!,{r0-r2,r4-r11,lr}
207 #if __ARM_ARCH__<7 && !defined(__thumb2__)
208 sub r14,pc,#16 @ ChaCha20_ctr32
210 adr r14,.LChaCha20_ctr32
218 #if __ARM_MAX_ARCH__>=7
219 cmp r2,#192 @ test len
230 ldmia r12,{r4-r7} @ load counter and nonce
231 sub sp,sp,#4*(16) @ off-load area
232 sub r14,r14,#64 @ .Lsigma
233 stmdb sp!,{r4-r7} @ copy counter and nonce
234 ldmia r3,{r4-r11} @ load key
235 ldmia r14,{r0-r3} @ load sigma
236 stmdb sp!,{r4-r11} @ copy key
237 stmdb sp!,{r0-r3} @ copy sigma
238 str r10,[sp,#4*(16+10)] @ off-load "@x[10]"
239 str r11,[sp,#4*(16+11)] @ off-load "@x[11]"
244 ldmia sp,{r0-r9} @ load key material
245 str @t[3],[sp,#4*(32+2)] @ save len
246 str r12, [sp,#4*(32+1)] @ save inp
247 str r14, [sp,#4*(32+0)] @ save out
249 ldr @t[3], [sp,#4*(15)]
250 ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
251 ldr @t[2], [sp,#4*(13)]
252 ldr @x[14],[sp,#4*(14)]
253 str @t[3], [sp,#4*(16+15)]
261 foreach (&ROUND(0, 4, 8,12)) { eval; }
262 foreach (&ROUND(0, 5,10,15)) { eval; }
266 ldr @t[3],[sp,#4*(32+2)] @ load len
268 str @t[0], [sp,#4*(16+8)] @ modulo-scheduled store
269 str @t[1], [sp,#4*(16+9)]
270 str @x[12],[sp,#4*(16+12)]
271 str @t[2], [sp,#4*(16+13)]
272 str @x[14],[sp,#4*(16+14)]
274 @ at this point we have first half of 512-bit result in
275 @ @x[0-7] and second half at sp+4*(16+8)
277 cmp @t[3],#64 @ done yet?
281 addlo r12,sp,#4*(0) @ shortcut or ...
282 ldrhs r12,[sp,#4*(32+1)] @ ... load inp
283 addlo r14,sp,#4*(0) @ shortcut or ...
284 ldrhs r14,[sp,#4*(32+0)] @ ... load out
286 ldr @t[0],[sp,#4*(0)] @ load key material
287 ldr @t[1],[sp,#4*(1)]
289 #if __ARM_ARCH__>=6 || !defined(__ARMEB__)
292 tst @t[2],#3 @ are input and output aligned?
293 ldr @t[2],[sp,#4*(2)]
295 cmp @t[3],#64 @ restore flags
297 ldr @t[2],[sp,#4*(2)]
299 ldr @t[3],[sp,#4*(3)]
301 add @x[0],@x[0],@t[0] @ accumulate key material
302 add @x[1],@x[1],@t[1]
306 ldrhs @t[0],[r12],#16 @ load input
307 ldrhs @t[1],[r12,#-12]
309 add @x[2],@x[2],@t[2]
310 add @x[3],@x[3],@t[3]
314 ldrhs @t[2],[r12,#-8]
315 ldrhs @t[3],[r12,#-4]
316 # if __ARM_ARCH__>=6 && defined(__ARMEB__)
325 eorhs @x[0],@x[0],@t[0] @ xor with input
326 eorhs @x[1],@x[1],@t[1]
328 str @x[0],[r14],#16 @ store output
332 eorhs @x[2],@x[2],@t[2]
333 eorhs @x[3],@x[3],@t[3]
334 ldmia @t[0],{@t[0]-@t[3]} @ load key material
339 add @x[4],@x[4],@t[0] @ accumulate key material
340 add @x[5],@x[5],@t[1]
344 ldrhs @t[0],[r12],#16 @ load input
345 ldrhs @t[1],[r12,#-12]
346 add @x[6],@x[6],@t[2]
347 add @x[7],@x[7],@t[3]
351 ldrhs @t[2],[r12,#-8]
352 ldrhs @t[3],[r12,#-4]
353 # if __ARM_ARCH__>=6 && defined(__ARMEB__)
362 eorhs @x[4],@x[4],@t[0]
363 eorhs @x[5],@x[5],@t[1]
365 str @x[4],[r14],#16 @ store output
369 eorhs @x[6],@x[6],@t[2]
370 eorhs @x[7],@x[7],@t[3]
372 ldmia @t[0],{@t[0]-@t[3]} @ load key material
374 add @x[0],sp,#4*(16+8)
377 ldmia @x[0],{@x[0]-@x[7]} @ load second half
379 add @x[0],@x[0],@t[0] @ accumulate key material
380 add @x[1],@x[1],@t[1]
384 ldrhs @t[0],[r12],#16 @ load input
385 ldrhs @t[1],[r12,#-12]
389 strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]" while at it
390 strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]" while at it
391 add @x[2],@x[2],@t[2]
392 add @x[3],@x[3],@t[3]
396 ldrhs @t[2],[r12,#-8]
397 ldrhs @t[3],[r12,#-4]
398 # if __ARM_ARCH__>=6 && defined(__ARMEB__)
407 eorhs @x[0],@x[0],@t[0]
408 eorhs @x[1],@x[1],@t[1]
410 str @x[0],[r14],#16 @ store output
414 eorhs @x[2],@x[2],@t[2]
415 eorhs @x[3],@x[3],@t[3]
417 ldmia @t[0],{@t[0]-@t[3]} @ load key material
421 add @x[4],@x[4],@t[0] @ accumulate key material
422 add @x[5],@x[5],@t[1]
426 addhi @t[0],@t[0],#1 @ next counter value
427 strhi @t[0],[sp,#4*(12)] @ save next counter value
431 ldrhs @t[0],[r12],#16 @ load input
432 ldrhs @t[1],[r12,#-12]
433 add @x[6],@x[6],@t[2]
434 add @x[7],@x[7],@t[3]
438 ldrhs @t[2],[r12,#-8]
439 ldrhs @t[3],[r12,#-4]
440 # if __ARM_ARCH__>=6 && defined(__ARMEB__)
449 eorhs @x[4],@x[4],@t[0]
450 eorhs @x[5],@x[5],@t[1]
454 ldrne @t[0],[sp,#4*(32+2)] @ re-load len
458 eorhs @x[6],@x[6],@t[2]
459 eorhs @x[7],@x[7],@t[3]
460 str @x[4],[r14],#16 @ store output
465 subhs @t[3],@t[0],#64 @ len-=64
475 .Lunaligned: @ unaligned endian-neutral path
476 cmp @t[3],#64 @ restore flags
480 ldr @t[3],[sp,#4*(3)]
482 for ($i=0;$i<16;$i+=4) {
485 $code.=<<___ if ($i==4);
486 add @x[0],sp,#4*(16+8)
488 $code.=<<___ if ($i==8);
489 ldmia @x[0],{@x[0]-@x[7]} @ load second half
493 strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]"
494 strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]"
497 add @x[$j+0],@x[$j+0],@t[0] @ accumulate key material
499 $code.=<<___ if ($i==12);
503 addhi @t[0],@t[0],#1 @ next counter value
504 strhi @t[0],[sp,#4*(12)] @ save next counter value
507 add @x[$j+1],@x[$j+1],@t[1]
508 add @x[$j+2],@x[$j+2],@t[2]
512 eorlo @t[0],@t[0],@t[0] @ zero or ...
513 ldrhsb @t[0],[r12],#16 @ ... load input
514 eorlo @t[1],@t[1],@t[1]
515 ldrhsb @t[1],[r12,#-12]
517 add @x[$j+3],@x[$j+3],@t[3]
521 eorlo @t[2],@t[2],@t[2]
522 ldrhsb @t[2],[r12,#-8]
523 eorlo @t[3],@t[3],@t[3]
524 ldrhsb @t[3],[r12,#-4]
526 eor @x[$j+0],@t[0],@x[$j+0] @ xor with input (or zero)
527 eor @x[$j+1],@t[1],@x[$j+1]
531 ldrhsb @t[0],[r12,#-15] @ load more input
532 ldrhsb @t[1],[r12,#-11]
533 eor @x[$j+2],@t[2],@x[$j+2]
534 strb @x[$j+0],[r14],#16 @ store output
535 eor @x[$j+3],@t[3],@x[$j+3]
539 ldrhsb @t[2],[r12,#-7]
540 ldrhsb @t[3],[r12,#-3]
541 strb @x[$j+1],[r14,#-12]
542 eor @x[$j+0],@t[0],@x[$j+0],lsr#8
543 strb @x[$j+2],[r14,#-8]
544 eor @x[$j+1],@t[1],@x[$j+1],lsr#8
548 ldrhsb @t[0],[r12,#-14] @ load more input
549 ldrhsb @t[1],[r12,#-10]
550 strb @x[$j+3],[r14,#-4]
551 eor @x[$j+2],@t[2],@x[$j+2],lsr#8
552 strb @x[$j+0],[r14,#-15]
553 eor @x[$j+3],@t[3],@x[$j+3],lsr#8
557 ldrhsb @t[2],[r12,#-6]
558 ldrhsb @t[3],[r12,#-2]
559 strb @x[$j+1],[r14,#-11]
560 eor @x[$j+0],@t[0],@x[$j+0],lsr#8
561 strb @x[$j+2],[r14,#-7]
562 eor @x[$j+1],@t[1],@x[$j+1],lsr#8
566 ldrhsb @t[0],[r12,#-13] @ load more input
567 ldrhsb @t[1],[r12,#-9]
568 strb @x[$j+3],[r14,#-3]
569 eor @x[$j+2],@t[2],@x[$j+2],lsr#8
570 strb @x[$j+0],[r14,#-14]
571 eor @x[$j+3],@t[3],@x[$j+3],lsr#8
575 ldrhsb @t[2],[r12,#-5]
576 ldrhsb @t[3],[r12,#-1]
577 strb @x[$j+1],[r14,#-10]
578 strb @x[$j+2],[r14,#-6]
579 eor @x[$j+0],@t[0],@x[$j+0],lsr#8
580 strb @x[$j+3],[r14,#-2]
581 eor @x[$j+1],@t[1],@x[$j+1],lsr#8
582 strb @x[$j+0],[r14,#-13]
583 eor @x[$j+2],@t[2],@x[$j+2],lsr#8
584 strb @x[$j+1],[r14,#-9]
585 eor @x[$j+3],@t[3],@x[$j+3],lsr#8
586 strb @x[$j+2],[r14,#-5]
587 strb @x[$j+3],[r14,#-1]
589 $code.=<<___ if ($i<12);
590 add @t[0],sp,#4*(4+$i)
591 ldmia @t[0],{@t[0]-@t[3]} @ load key material
598 ldrne @t[0],[sp,#4*(32+2)] @ re-load len
602 subhs @t[3],@t[0],#64 @ len-=64
609 ldr r12,[sp,#4*(32+1)] @ load inp
611 ldr r14,[sp,#4*(32+0)] @ load out
614 ldrb @t[2],[@t[1]],#1 @ read buffer on stack
615 ldrb @t[3],[r12],#1 @ read input
617 eor @t[3],@t[3],@t[2]
618 strb @t[3],[r14],#1 @ store output
624 ldmia sp!,{r4-r11,pc}
625 .size ChaCha20_ctr32,.-ChaCha20_ctr32
629 my ($a0,$b0,$c0,$d0,$a1,$b1,$c1,$d1,$a2,$b2,$c2,$d2,$t0,$t1,$t2,$t3) =
634 my ($a,$b,$c,$d,$t)=@_;
637 "&vadd_i32 ($a,$a,$b)",
639 "&vrev32_16 ($d,$d)", # vrot ($d,16)
641 "&vadd_i32 ($c,$c,$d)",
643 "&vshr_u32 ($b,$t,20)",
644 "&vsli_32 ($b,$t,12)",
646 "&vadd_i32 ($a,$a,$b)",
648 "&vshr_u32 ($d,$t,24)",
649 "&vsli_32 ($d,$t,8)",
651 "&vadd_i32 ($c,$c,$d)",
653 "&vshr_u32 ($b,$t,25)",
654 "&vsli_32 ($b,$t,7)",
656 "&vext_8 ($c,$c,$c,8)",
657 "&vext_8 ($b,$b,$b,$odd?12:4)",
658 "&vext_8 ($d,$d,$d,$odd?4:12)"
663 #if __ARM_MAX_ARCH__>=7
667 .type ChaCha20_neon,%function
670 ldr r12,[sp,#0] @ pull pointer to counter and nonce
671 stmdb sp!,{r0-r2,r4-r11,lr}
674 vstmdb sp!,{d8-d15} @ ABI spec says so
677 vld1.32 {$b0-$c0},[r3] @ load key
678 ldmia r3,{r4-r11} @ load key
681 vld1.32 {$d0},[r12] @ load counter and nonce
683 ldmia r14,{r0-r3} @ load sigma
684 vld1.32 {$a0},[r14]! @ load sigma
685 vld1.32 {$t0},[r14] @ one
686 vst1.32 {$c0-$d0},[r12] @ copy 1/2key|counter|nonce
687 vst1.32 {$a0-$b0},[sp] @ copy sigma|1/2key
689 str r10,[sp,#4*(16+10)] @ off-load "@x[10]"
690 str r11,[sp,#4*(16+11)] @ off-load "@x[11]"
691 vshl.i32 $t1#lo,$t0#lo,#1 @ two
692 vstr $t0#lo,[sp,#4*(16+0)]
693 vshl.i32 $t2#lo,$t0#lo,#2 @ four
694 vstr $t1#lo,[sp,#4*(16+2)]
696 vstr $t2#lo,[sp,#4*(16+4)]
704 ldmia sp,{r0-r9} @ load key material
705 cmp @t[3],#64*2 @ if len<=64*2
706 bls .Lbreak_neon @ switch to integer-only
708 str @t[3],[sp,#4*(32+2)] @ save len
710 str r12, [sp,#4*(32+1)] @ save inp
712 str r14, [sp,#4*(32+0)] @ save out
715 ldr @t[3], [sp,#4*(15)]
716 vadd.i32 $d1,$d0,$t0 @ counter+1
717 ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
719 ldr @t[2], [sp,#4*(13)]
721 ldr @x[14],[sp,#4*(14)]
722 vadd.i32 $d2,$d1,$t0 @ counter+2
723 str @t[3], [sp,#4*(16+15)]
725 add @x[12],@x[12],#3 @ counter+3
732 my @thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,0);
733 my @thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,0);
734 my @thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,0);
735 my @thread3=&ROUND(0,4,8,12);
738 eval; eval(shift(@thread3));
739 eval(shift(@thread1)); eval(shift(@thread3));
740 eval(shift(@thread2)); eval(shift(@thread3));
743 @thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,1);
744 @thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,1);
745 @thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,1);
746 @thread3=&ROUND(0,5,10,15);
749 eval; eval(shift(@thread3));
750 eval(shift(@thread1)); eval(shift(@thread3));
751 eval(shift(@thread2)); eval(shift(@thread3));
757 vld1.32 {$t0-$t1},[sp] @ load key material
758 vld1.32 {$t2-$t3},[@t[3]]
760 ldr @t[3],[sp,#4*(32+2)] @ load len
762 str @t[0], [sp,#4*(16+8)] @ modulo-scheduled store
763 str @t[1], [sp,#4*(16+9)]
764 str @x[12],[sp,#4*(16+12)]
765 str @t[2], [sp,#4*(16+13)]
766 str @x[14],[sp,#4*(16+14)]
768 @ at this point we have first half of 512-bit result in
769 @ @x[0-7] and second half at sp+4*(16+8)
771 ldr r12,[sp,#4*(32+1)] @ load inp
772 ldr r14,[sp,#4*(32+0)] @ load out
774 vadd.i32 $a0,$a0,$t0 @ accumulate key material
777 vldr $t0#lo,[sp,#4*(16+0)] @ one
782 vldr $t1#lo,[sp,#4*(16+2)] @ two
787 vadd.i32 $d1#lo,$d1#lo,$t0#lo @ counter+1
788 vadd.i32 $d2#lo,$d2#lo,$t1#lo @ counter+2
797 vld1.8 {$t0-$t1},[r12]! @ load input
799 vld1.8 {$t2-$t3},[r12]!
800 veor $a0,$a0,$t0 @ xor with input
802 vld1.8 {$t0-$t1},[r12]!
805 vld1.8 {$t2-$t3},[r12]!
808 vst1.8 {$a0-$b0},[r14]! @ store output
810 vld1.8 {$t0-$t1},[r12]!
812 vst1.8 {$c0-$d0},[r14]!
814 vld1.8 {$t2-$t3},[r12]!
817 vld1.32 {$a0-$b0},[@t[3]]! @ load for next iteration
818 veor $t0#hi,$t0#hi,$t0#hi
819 vldr $t0#lo,[sp,#4*(16+4)] @ four
821 vld1.32 {$c0-$d0},[@t[3]]
823 vst1.8 {$a1-$b1},[r14]!
825 vst1.8 {$c1-$d1},[r14]!
827 vadd.i32 $d0#lo,$d0#lo,$t0#lo @ next counter value
828 vldr $t0#lo,[sp,#4*(16+0)] @ one
830 ldmia sp,{@t[0]-@t[3]} @ load key material
831 add @x[0],@x[0],@t[0] @ accumulate key material
832 ldr @t[0],[r12],#16 @ load input
833 vst1.8 {$a2-$b2},[r14]!
834 add @x[1],@x[1],@t[1]
836 vst1.8 {$c2-$d2},[r14]!
837 add @x[2],@x[2],@t[2]
839 add @x[3],@x[3],@t[3]
847 eor @x[0],@x[0],@t[0] @ xor with input
849 eor @x[1],@x[1],@t[1]
850 str @x[0],[r14],#16 @ store output
851 eor @x[2],@x[2],@t[2]
853 eor @x[3],@x[3],@t[3]
854 ldmia @t[0],{@t[0]-@t[3]} @ load key material
858 add @x[4],@x[4],@t[0] @ accumulate key material
859 ldr @t[0],[r12],#16 @ load input
860 add @x[5],@x[5],@t[1]
862 add @x[6],@x[6],@t[2]
864 add @x[7],@x[7],@t[3]
872 eor @x[4],@x[4],@t[0]
874 eor @x[5],@x[5],@t[1]
875 str @x[4],[r14],#16 @ store output
876 eor @x[6],@x[6],@t[2]
878 eor @x[7],@x[7],@t[3]
879 ldmia @t[0],{@t[0]-@t[3]} @ load key material
881 add @x[0],sp,#4*(16+8)
884 ldmia @x[0],{@x[0]-@x[7]} @ load second half
886 add @x[0],@x[0],@t[0] @ accumulate key material
887 ldr @t[0],[r12],#16 @ load input
888 add @x[1],@x[1],@t[1]
893 strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]" while at it
894 add @x[2],@x[2],@t[2]
899 strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]" while at it
900 add @x[3],@x[3],@t[3]
908 eor @x[0],@x[0],@t[0]
910 eor @x[1],@x[1],@t[1]
911 str @x[0],[r14],#16 @ store output
912 eor @x[2],@x[2],@t[2]
914 eor @x[3],@x[3],@t[3]
915 ldmia @t[0],{@t[0]-@t[3]} @ load key material
919 add @x[4],@x[4],@t[0] @ accumulate key material
920 add @t[0],@t[0],#4 @ next counter value
921 add @x[5],@x[5],@t[1]
922 str @t[0],[sp,#4*(12)] @ save next counter value
923 ldr @t[0],[r12],#16 @ load input
924 add @x[6],@x[6],@t[2]
925 add @x[4],@x[4],#3 @ counter+3
927 add @x[7],@x[7],@t[3]
936 eor @x[4],@x[4],@t[0]
940 ldrhi @t[0],[sp,#4*(32+2)] @ re-load len
941 eor @x[5],@x[5],@t[1]
942 eor @x[6],@x[6],@t[2]
943 str @x[4],[r14],#16 @ store output
944 eor @x[7],@x[7],@t[3]
946 sub @t[3],@t[0],#64*4 @ len-=64*4
955 @ harmonize NEON and integer-only stack frames: load data
956 @ from NEON frame, but save to integer-only one; distance
957 @ between the two is 4*(32+4+16-32)=4*(20).
959 str @t[3], [sp,#4*(20+32+2)] @ save len
960 add @t[3],sp,#4*(32+4)
961 str r12, [sp,#4*(20+32+1)] @ save inp
962 str r14, [sp,#4*(20+32+0)] @ save out
964 ldr @x[12],[sp,#4*(16+10)]
965 ldr @x[14],[sp,#4*(16+11)]
966 vldmia @t[3],{d8-d15} @ fulfill ABI requirement
967 str @x[12],[sp,#4*(20+16+10)] @ copy "@x[10]"
968 str @x[14],[sp,#4*(20+16+11)] @ copy "@x[11]"
970 ldr @t[3], [sp,#4*(15)]
971 ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
972 ldr @t[2], [sp,#4*(13)]
973 ldr @x[14],[sp,#4*(14)]
974 str @t[3], [sp,#4*(20+16+15)]
976 vst1.32 {$a0-$b0},[@t[3]]! @ copy key
977 add sp,sp,#4*(20) @ switch frame
978 vst1.32 {$c0-$d0},[@t[3]]
980 b .Loop @ go integer-only
985 bhs .L192_or_more_neon
987 bhs .L128_or_more_neon
989 bhs .L64_or_more_neon
992 vst1.8 {$a0-$b0},[sp]
994 vst1.8 {$c0-$d0},[@t[0]]
999 vld1.8 {$t0-$t1},[r12]!
1000 vld1.8 {$t2-$t3},[r12]!
1005 vst1.8 {$a0-$b0},[r14]!
1006 vst1.8 {$c0-$d0},[r14]!
1011 vst1.8 {$a1-$b1},[sp]
1013 vst1.8 {$c1-$d1},[@t[0]]
1014 sub @t[3],@t[3],#64*1 @ len-=64*1
1019 vld1.8 {$t0-$t1},[r12]!
1020 vld1.8 {$t2-$t3},[r12]!
1023 vld1.8 {$t0-$t1},[r12]!
1026 vld1.8 {$t2-$t3},[r12]!
1030 vst1.8 {$a0-$b0},[r14]!
1032 vst1.8 {$c0-$d0},[r14]!
1034 vst1.8 {$a1-$b1},[r14]!
1035 vst1.8 {$c1-$d1},[r14]!
1040 vst1.8 {$a2-$b2},[sp]
1042 vst1.8 {$c2-$d2},[@t[0]]
1043 sub @t[3],@t[3],#64*2 @ len-=64*2
1048 vld1.8 {$t0-$t1},[r12]!
1049 vld1.8 {$t2-$t3},[r12]!
1052 vld1.8 {$t0-$t1},[r12]!
1055 vld1.8 {$t2-$t3},[r12]!
1059 vld1.8 {$t0-$t1},[r12]!
1061 vst1.8 {$a0-$b0},[r14]!
1063 vld1.8 {$t2-$t3},[r12]!
1066 vst1.8 {$c0-$d0},[r14]!
1068 vst1.8 {$a1-$b1},[r14]!
1070 vst1.8 {$c1-$d1},[r14]!
1072 vst1.8 {$a2-$b2},[r14]!
1073 vst1.8 {$c2-$d2},[r14]!
1077 ldmia sp,{@t[0]-@t[3]} @ load key material
1078 add @x[0],@x[0],@t[0] @ accumulate key material
1080 add @x[1],@x[1],@t[1]
1081 add @x[2],@x[2],@t[2]
1082 add @x[3],@x[3],@t[3]
1083 ldmia @t[0],{@t[0]-@t[3]} @ load key material
1085 add @x[4],@x[4],@t[0] @ accumulate key material
1087 add @x[5],@x[5],@t[1]
1088 add @x[6],@x[6],@t[2]
1089 add @x[7],@x[7],@t[3]
1090 ldmia @t[0],{@t[0]-@t[3]} @ load key material
1101 stmia sp,{@x[0]-@x[7]}
1102 add @x[0],sp,#4*(16+8)
1104 ldmia @x[0],{@x[0]-@x[7]} @ load second half
1106 add @x[0],@x[0],@t[0] @ accumulate key material
1107 add @t[0],sp,#4*(12)
1108 add @x[1],@x[1],@t[1]
1109 add @x[2],@x[2],@t[2]
1110 add @x[3],@x[3],@t[3]
1111 ldmia @t[0],{@t[0]-@t[3]} @ load key material
1113 add @x[4],@x[4],@t[0] @ accumulate key material
1115 add @x[5],@x[5],@t[1]
1116 add @x[4],@x[4],#3 @ counter+3
1117 add @x[6],@x[6],@t[2]
1118 add @x[7],@x[7],@t[3]
1119 ldr @t[3],[sp,#4*(32+2)] @ re-load len
1130 stmia @t[0],{@x[0]-@x[7]}
1132 sub @t[3],@t[3],#64*3 @ len-=64*3
1135 ldrb @t[0],[@t[2]],#1 @ read buffer on stack
1136 ldrb @t[1],[r12],#1 @ read input
1138 eor @t[0],@t[0],@t[1]
1139 strb @t[0],[r14],#1 @ store output
1146 ldmia sp!,{r4-r11,pc}
1147 .size ChaCha20_neon,.-ChaCha20_neon
1148 .comm OPENSSL_armcap_P,4,4
1153 foreach (split("\n",$code)) {
1154 s/\`([^\`]*)\`/eval $1/geo;
1156 s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;