ARMv4 assembly pack: implement support for Thumb2.
[openssl.git] / crypto / ec / asm / ecp_nistz256-armv4.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 # ECP_NISTZ256 module for ARMv4.
11 #
12 # October 2014.
13 #
14 # Original ECP_NISTZ256 submission targeting x86_64 is detailed in
15 # http://eprint.iacr.org/2013/816. In the process of adaptation
16 # original .c module was made 32-bit savvy in order to make this
17 # implementation possible.
18 #
19 #                       with/without -DECP_NISTZ256_ASM
20 # Cortex-A8             +53-170%
21 # Cortex-A9             +76-205%
22 # Cortex-A15            +100-316%
23 # Snapdragon S4         +66-187%
24 #
25 # Ranges denote minimum and maximum improvement coefficients depending
26 # on benchmark. Lower coefficients are for ECDSA sign, server-side
27 # operation. Keep in mind that +200% means 3x improvement.
28
29 $flavour = shift;
30 if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
31 else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
32
33 if ($flavour && $flavour ne "void") {
34     $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
35     ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
36     ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
37     die "can't locate arm-xlate.pl";
38
39     open STDOUT,"| \"$^X\" $xlate $flavour $output";
40 } else {
41     open STDOUT,">$output";
42 }
43
44 $code.=<<___;
45 #include "arm_arch.h"
46
47 .text
48 #if defined(__thumb2__) && !defined(__APPLE__)
49 .syntax unified
50 .thumb
51 #else
52 .code   32
53 #endif
54 ___
55 ########################################################################
56 # Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
57 #
58 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
59 open TABLE,"<ecp_nistz256_table.c"              or
60 open TABLE,"<${dir}../ecp_nistz256_table.c"     or
61 die "failed to open ecp_nistz256_table.c:",$!;
62
63 use integer;
64
65 foreach(<TABLE>) {
66         s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
67 }
68 close TABLE;
69
70 # See ecp_nistz256_table.c for explanation for why it's 64*16*37.
71 # 64*16*37-1 is because $#arr returns last valid index or @arr, not
72 # amount of elements.
73 die "insane number of elements" if ($#arr != 64*16*37-1);
74
75 $code.=<<___;
76 .globl  ecp_nistz256_precomputed
77 .type   ecp_nistz256_precomputed,%object
78 .align  12
79 ecp_nistz256_precomputed:
80 ___
81 ########################################################################
82 # this conversion smashes P256_POINT_AFFINE by individual bytes with
83 # 64 byte interval, similar to
84 #       1111222233334444
85 #       1234123412341234
86 for(1..37) {
87         @tbl = splice(@arr,0,64*16);
88         for($i=0;$i<64;$i++) {
89                 undef @line;
90                 for($j=0;$j<64;$j++) {
91                         push @line,(@tbl[$j*16+$i/4]>>(($i%4)*8))&0xff;
92                 }
93                 $code.=".byte\t";
94                 $code.=join(',',map { sprintf "0x%02x",$_} @line);
95                 $code.="\n";
96         }
97 }
98 $code.=<<___;
99 .size   ecp_nistz256_precomputed,.-ecp_nistz256_precomputed
100 .align  5
101 .LRR:   @ 2^512 mod P precomputed for NIST P256 polynomial
102 .long   0x00000003, 0x00000000, 0xffffffff, 0xfffffffb
103 .long   0xfffffffe, 0xffffffff, 0xfffffffd, 0x00000004
104 .Lone:
105 .long   1,0,0,0,0,0,0,0
106 .asciz  "ECP_NISTZ256 for ARMv4, CRYPTOGAMS by <appro\@openssl.org>"
107 .align  6
108 ___
109
110 ########################################################################
111 # common register layout, note that $t2 is link register, so that if
112 # internal subroutine uses $t2, then it has to offload lr...
113
114 ($r_ptr,$a_ptr,$b_ptr,$ff,$a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$t1,$t2)=
115                 map("r$_",(0..12,14));
116 ($t0,$t3)=($ff,$a_ptr);
117
118 $code.=<<___;
119 @ void  ecp_nistz256_to_mont(BN_ULONG r0[8],const BN_ULONG r1[8]);
120 .globl  ecp_nistz256_to_mont
121 .type   ecp_nistz256_to_mont,%function
122 ecp_nistz256_to_mont:
123         adr     $b_ptr,.LRR
124         b       .Lecp_nistz256_mul_mont
125 .size   ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
126
127 @ void  ecp_nistz256_from_mont(BN_ULONG r0[8],const BN_ULONG r1[8]);
128 .globl  ecp_nistz256_from_mont
129 .type   ecp_nistz256_from_mont,%function
130 ecp_nistz256_from_mont:
131         adr     $b_ptr,.Lone
132         b       .Lecp_nistz256_mul_mont
133 .size   ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
134
135 @ void  ecp_nistz256_mul_by_2(BN_ULONG r0[8],const BN_ULONG r1[8]);
136 .globl  ecp_nistz256_mul_by_2
137 .type   ecp_nistz256_mul_by_2,%function
138 .align  4
139 ecp_nistz256_mul_by_2:
140         stmdb   sp!,{r4-r12,lr}
141         bl      __ecp_nistz256_mul_by_2
142 #if __ARM_ARCH__>=5 || !defined(__thumb__)
143         ldmia   sp!,{r4-r12,pc}
144 #else
145         ldmia   sp!,{r4-r12,lr}
146         bx      lr                      @ interoperable with Thumb ISA:-)
147 #endif
148 .size   ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
149
150 .type   __ecp_nistz256_mul_by_2,%function
151 .align  4
152 __ecp_nistz256_mul_by_2:
153         ldr     $a0,[$a_ptr,#0]
154         ldr     $a1,[$a_ptr,#4]
155         ldr     $a2,[$a_ptr,#8]
156         adds    $a0,$a0,$a0             @ a[0:7]+=a[0:7], i.e. add with itself
157         ldr     $a3,[$a_ptr,#12]
158         adcs    $a1,$a1,$a1
159         ldr     $a4,[$a_ptr,#16]
160         adcs    $a2,$a2,$a2
161         ldr     $a5,[$a_ptr,#20]
162         adcs    $a3,$a3,$a3
163         ldr     $a6,[$a_ptr,#24]
164         adcs    $a4,$a4,$a4
165         ldr     $a7,[$a_ptr,#28]
166         adcs    $a5,$a5,$a5
167         adcs    $a6,$a6,$a6
168         mov     $ff,#0
169         adcs    $a7,$a7,$a7
170 #ifdef  __thumb2__
171         it      cs
172 #endif
173         movcs   $ff,#-1                 @ $ff = carry ? -1 : 0
174
175         b       .Lreduce_by_sub
176 .size   __ecp_nistz256_mul_by_2,.-__ecp_nistz256_mul_by_2
177
178 @ void  ecp_nistz256_add(BN_ULONG r0[8],const BN_ULONG r1[8],
179 @                                       const BN_ULONG r2[8]);
180 .globl  ecp_nistz256_add
181 .type   ecp_nistz256_add,%function
182 .align  4
183 ecp_nistz256_add:
184         stmdb   sp!,{r4-r12,lr}
185         bl      __ecp_nistz256_add
186 #if __ARM_ARCH__>=5 || !defined(__thumb__)
187         ldmia   sp!,{r4-r12,pc}
188 #else
189         ldmia   sp!,{r4-r12,lr}
190         bx      lr                      @ interoperable with Thumb ISA:-)
191 #endif
192 .size   ecp_nistz256_add,.-ecp_nistz256_add
193
194 .type   __ecp_nistz256_add,%function
195 .align  4
196 __ecp_nistz256_add:
197         str     lr,[sp,#-4]!            @ push lr
198
199         ldr     $a0,[$a_ptr,#0]
200         ldr     $a1,[$a_ptr,#4]
201         ldr     $a2,[$a_ptr,#8]
202         ldr     $a3,[$a_ptr,#12]
203         ldr     $a4,[$a_ptr,#16]
204          ldr    $t0,[$b_ptr,#0]
205         ldr     $a5,[$a_ptr,#20]
206          ldr    $t1,[$b_ptr,#4]
207         ldr     $a6,[$a_ptr,#24]
208          ldr    $t2,[$b_ptr,#8]
209         ldr     $a7,[$a_ptr,#28]
210          ldr    $t3,[$b_ptr,#12]
211         adds    $a0,$a0,$t0
212          ldr    $t0,[$b_ptr,#16]
213         adcs    $a1,$a1,$t1
214          ldr    $t1,[$b_ptr,#20]
215         adcs    $a2,$a2,$t2
216          ldr    $t2,[$b_ptr,#24]
217         adcs    $a3,$a3,$t3
218          ldr    $t3,[$b_ptr,#28]
219         adcs    $a4,$a4,$t0
220         adcs    $a5,$a5,$t1
221         adcs    $a6,$a6,$t2
222         mov     $ff,#0
223         adcs    $a7,$a7,$t3
224 #ifdef  __thumb2__
225         it      cs
226 #endif
227         movcs   $ff,#-1                 @ $ff = carry ? -1 : 0, "broadcast" carry
228         ldr     lr,[sp],#4              @ pop lr
229
230 .Lreduce_by_sub:
231
232         @ if a+b carries, subtract modulus.
233         @
234         @ Note that because mod has special form, i.e. consists of
235         @ 0xffffffff, 1 and 0s, we can conditionally synthesize it by
236         @ using value of broadcasted carry as a whole or extracting
237         @ single bit. Follow $ff register...
238
239         subs    $a0,$a0,$ff             @ subtract synthesized modulus
240         sbcs    $a1,$a1,$ff
241         str     $a0,[$r_ptr,#0]
242         sbcs    $a2,$a2,$ff
243         str     $a1,[$r_ptr,#4]
244         sbcs    $a3,$a3,#0
245         str     $a2,[$r_ptr,#8]
246         sbcs    $a4,$a4,#0
247         str     $a3,[$r_ptr,#12]
248         sbcs    $a5,$a5,#0
249         str     $a4,[$r_ptr,#16]
250         sbcs    $a6,$a6,$ff,lsr#31
251         str     $a5,[$r_ptr,#20]
252         sbcs    $a7,$a7,$ff
253         str     $a6,[$r_ptr,#24]
254         str     $a7,[$r_ptr,#28]
255
256         mov     pc,lr
257 .size   __ecp_nistz256_add,.-__ecp_nistz256_add
258
259 @ void  ecp_nistz256_mul_by_3(BN_ULONG r0[8],const BN_ULONG r1[8]);
260 .globl  ecp_nistz256_mul_by_3
261 .type   ecp_nistz256_mul_by_3,%function
262 .align  4
263 ecp_nistz256_mul_by_3:
264         stmdb   sp!,{r4-r12,lr}
265         bl      __ecp_nistz256_mul_by_3
266 #if __ARM_ARCH__>=5 || !defined(__thumb__)
267         ldmia   sp!,{r4-r12,pc}
268 #else
269         ldmia   sp!,{r4-r12,lr}
270         bx      lr                      @ interoperable with Thumb ISA:-)
271 #endif
272 .size   ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
273
274 .type   __ecp_nistz256_mul_by_3,%function
275 .align  4
276 __ecp_nistz256_mul_by_3:
277         str     lr,[sp,#-4]!            @ push lr
278
279         @ As multiplication by 3 is performed as 2*n+n, below are inline
280         @ copies of __ecp_nistz256_mul_by_2 and __ecp_nistz256_add, see
281         @ corresponding subroutines for details.
282
283         ldr     $a0,[$a_ptr,#0]
284         ldr     $a1,[$a_ptr,#4]
285         ldr     $a2,[$a_ptr,#8]
286         adds    $a0,$a0,$a0             @ a[0:7]+=a[0:7]
287         ldr     $a3,[$a_ptr,#12]
288         adcs    $a1,$a1,$a1
289         ldr     $a4,[$a_ptr,#16]
290         adcs    $a2,$a2,$a2
291         ldr     $a5,[$a_ptr,#20]
292         adcs    $a3,$a3,$a3
293         ldr     $a6,[$a_ptr,#24]
294         adcs    $a4,$a4,$a4
295         ldr     $a7,[$a_ptr,#28]
296         adcs    $a5,$a5,$a5
297         adcs    $a6,$a6,$a6
298         mov     $ff,#0
299         adcs    $a7,$a7,$a7
300 #ifdef  __thumb2__
301         it      cs
302 #endif
303         movcs   $ff,#-1                 @ $ff = carry ? -1 : 0, "broadcast" carry
304
305         subs    $a0,$a0,$ff             @ subtract synthesized modulus, see
306                                         @ .Lreduce_by_sub for details, except
307                                         @ that we don't write anything to
308                                         @ memory, but keep intermediate
309                                         @ results in registers...
310         sbcs    $a1,$a1,$ff
311         sbcs    $a2,$a2,$ff
312         sbcs    $a3,$a3,#0
313         sbcs    $a4,$a4,#0
314          ldr    $b_ptr,[$a_ptr,#0]
315         sbcs    $a5,$a5,#0
316          ldr    $t1,[$a_ptr,#4]
317         sbcs    $a6,$a6,$ff,lsr#31
318          ldr    $t2,[$a_ptr,#8]
319         sbcs    $a7,$a7,$ff
320
321         ldr     $t0,[$a_ptr,#12]
322         adds    $a0,$a0,$b_ptr          @ 2*a[0:7]+=a[0:7]
323         ldr     $b_ptr,[$a_ptr,#16]
324         adcs    $a1,$a1,$t1
325         ldr     $t1,[$a_ptr,#20]
326         adcs    $a2,$a2,$t2
327         ldr     $t2,[$a_ptr,#24]
328         adcs    $a3,$a3,$t0
329         ldr     $t3,[$a_ptr,#28]
330         adcs    $a4,$a4,$b_ptr
331         adcs    $a5,$a5,$t1
332         adcs    $a6,$a6,$t2
333         mov     $ff,#0
334         adcs    $a7,$a7,$t3
335 #ifdef  __thumb2__
336         it      cs
337 #endif
338         movcs   $ff,#-1                 @ $ff = carry ? -1 : 0, "broadcast" carry
339         ldr     lr,[sp],#4              @ pop lr
340
341         b       .Lreduce_by_sub
342 .size   ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
343
344 @ void  ecp_nistz256_div_by_2(BN_ULONG r0[8],const BN_ULONG r1[8]);
345 .globl  ecp_nistz256_div_by_2
346 .type   ecp_nistz256_div_by_2,%function
347 .align  4
348 ecp_nistz256_div_by_2:
349         stmdb   sp!,{r4-r12,lr}
350         bl      __ecp_nistz256_div_by_2
351 #if __ARM_ARCH__>=5 || !defined(__thumb__)
352         ldmia   sp!,{r4-r12,pc}
353 #else
354         ldmia   sp!,{r4-r12,lr}
355         bx      lr                      @ interoperable with Thumb ISA:-)
356 #endif
357 .size   ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
358
359 .type   __ecp_nistz256_div_by_2,%function
360 .align  4
361 __ecp_nistz256_div_by_2:
362         @ ret = (a is odd ? a+mod : a) >> 1
363
364         ldr     $a0,[$a_ptr,#0]
365         ldr     $a1,[$a_ptr,#4]
366         ldr     $a2,[$a_ptr,#8]
367         mov     $ff,$a0,lsl#31          @ place least significant bit to most
368                                         @ significant position, now arithmetic
369                                         @ right shift by 31 will produce -1 or
370                                         @ 0, while logical rigth shift 1 or 0,
371                                         @ this is how modulus is conditionally
372                                         @ synthesized in this case...
373         ldr     $a3,[$a_ptr,#12]
374         adds    $a0,$a0,$ff,asr#31
375         ldr     $a4,[$a_ptr,#16]
376         adcs    $a1,$a1,$ff,asr#31
377         ldr     $a5,[$a_ptr,#20]
378         adcs    $a2,$a2,$ff,asr#31
379         ldr     $a6,[$a_ptr,#24]
380         adcs    $a3,$a3,#0
381         ldr     $a7,[$a_ptr,#28]
382         adcs    $a4,$a4,#0
383          mov    $a0,$a0,lsr#1           @ a[0:7]>>=1, we can start early
384                                         @ because it doesn't affect flags
385         adcs    $a5,$a5,#0
386          orr    $a0,$a0,$a1,lsl#31
387         adcs    $a6,$a6,$ff,lsr#31
388         mov     $b_ptr,#0
389         adcs    $a7,$a7,$ff,asr#31
390          mov    $a1,$a1,lsr#1
391         adc     $b_ptr,$b_ptr,#0        @ top-most carry bit from addition
392
393         orr     $a1,$a1,$a2,lsl#31
394         mov     $a2,$a2,lsr#1
395         str     $a0,[$r_ptr,#0]
396         orr     $a2,$a2,$a3,lsl#31
397         mov     $a3,$a3,lsr#1
398         str     $a1,[$r_ptr,#4]
399         orr     $a3,$a3,$a4,lsl#31
400         mov     $a4,$a4,lsr#1
401         str     $a2,[$r_ptr,#8]
402         orr     $a4,$a4,$a5,lsl#31
403         mov     $a5,$a5,lsr#1
404         str     $a3,[$r_ptr,#12]
405         orr     $a5,$a5,$a6,lsl#31
406         mov     $a6,$a6,lsr#1
407         str     $a4,[$r_ptr,#16]
408         orr     $a6,$a6,$a7,lsl#31
409         mov     $a7,$a7,lsr#1
410         str     $a5,[$r_ptr,#20]
411         orr     $a7,$a7,$b_ptr,lsl#31   @ don't forget the top-most carry bit
412         str     $a6,[$r_ptr,#24]
413         str     $a7,[$r_ptr,#28]
414
415         mov     pc,lr
416 .size   __ecp_nistz256_div_by_2,.-__ecp_nistz256_div_by_2
417
418 @ void  ecp_nistz256_sub(BN_ULONG r0[8],const BN_ULONG r1[8],
419 @                                       const BN_ULONG r2[8]);
420 .globl  ecp_nistz256_sub
421 .type   ecp_nistz256_sub,%function
422 .align  4
423 ecp_nistz256_sub:
424         stmdb   sp!,{r4-r12,lr}
425         bl      __ecp_nistz256_sub
426 #if __ARM_ARCH__>=5 || !defined(__thumb__)
427         ldmia   sp!,{r4-r12,pc}
428 #else
429         ldmia   sp!,{r4-r12,lr}
430         bx      lr                      @ interoperable with Thumb ISA:-)
431 #endif
432 .size   ecp_nistz256_sub,.-ecp_nistz256_sub
433
434 .type   __ecp_nistz256_sub,%function
435 .align  4
436 __ecp_nistz256_sub:
437         str     lr,[sp,#-4]!            @ push lr
438
439         ldr     $a0,[$a_ptr,#0]
440         ldr     $a1,[$a_ptr,#4]
441         ldr     $a2,[$a_ptr,#8]
442         ldr     $a3,[$a_ptr,#12]
443         ldr     $a4,[$a_ptr,#16]
444          ldr    $t0,[$b_ptr,#0]
445         ldr     $a5,[$a_ptr,#20]
446          ldr    $t1,[$b_ptr,#4]
447         ldr     $a6,[$a_ptr,#24]
448          ldr    $t2,[$b_ptr,#8]
449         ldr     $a7,[$a_ptr,#28]
450          ldr    $t3,[$b_ptr,#12]
451         subs    $a0,$a0,$t0
452          ldr    $t0,[$b_ptr,#16]
453         sbcs    $a1,$a1,$t1
454          ldr    $t1,[$b_ptr,#20]
455         sbcs    $a2,$a2,$t2
456          ldr    $t2,[$b_ptr,#24]
457         sbcs    $a3,$a3,$t3
458          ldr    $t3,[$b_ptr,#28]
459         sbcs    $a4,$a4,$t0
460         sbcs    $a5,$a5,$t1
461         sbcs    $a6,$a6,$t2
462         sbcs    $a7,$a7,$t3
463         sbc     $ff,$ff,$ff             @ broadcast borrow bit
464         ldr     lr,[sp],#4              @ pop lr
465
466 .Lreduce_by_add:
467
468         @ if a-b borrows, add modulus.
469         @
470         @ Note that because mod has special form, i.e. consists of
471         @ 0xffffffff, 1 and 0s, we can conditionally synthesize it by
472         @ broadcasting borrow bit to a register, $ff, and using it as
473         @ a whole or extracting single bit.
474
475         adds    $a0,$a0,$ff             @ add synthesized modulus
476         adcs    $a1,$a1,$ff
477         str     $a0,[$r_ptr,#0]
478         adcs    $a2,$a2,$ff
479         str     $a1,[$r_ptr,#4]
480         adcs    $a3,$a3,#0
481         str     $a2,[$r_ptr,#8]
482         adcs    $a4,$a4,#0
483         str     $a3,[$r_ptr,#12]
484         adcs    $a5,$a5,#0
485         str     $a4,[$r_ptr,#16]
486         adcs    $a6,$a6,$ff,lsr#31
487         str     $a5,[$r_ptr,#20]
488         adcs    $a7,$a7,$ff
489         str     $a6,[$r_ptr,#24]
490         str     $a7,[$r_ptr,#28]
491
492         mov     pc,lr
493 .size   __ecp_nistz256_sub,.-__ecp_nistz256_sub
494
495 @ void  ecp_nistz256_neg(BN_ULONG r0[8],const BN_ULONG r1[8]);
496 .globl  ecp_nistz256_neg
497 .type   ecp_nistz256_neg,%function
498 .align  4
499 ecp_nistz256_neg:
500         stmdb   sp!,{r4-r12,lr}
501         bl      __ecp_nistz256_neg
502 #if __ARM_ARCH__>=5 || !defined(__thumb__)
503         ldmia   sp!,{r4-r12,pc}
504 #else
505         ldmia   sp!,{r4-r12,lr}
506         bx      lr                      @ interoperable with Thumb ISA:-)
507 #endif
508 .size   ecp_nistz256_neg,.-ecp_nistz256_neg
509
510 .type   __ecp_nistz256_neg,%function
511 .align  4
512 __ecp_nistz256_neg:
513         ldr     $a0,[$a_ptr,#0]
514         eor     $ff,$ff,$ff
515         ldr     $a1,[$a_ptr,#4]
516         ldr     $a2,[$a_ptr,#8]
517         subs    $a0,$ff,$a0
518         ldr     $a3,[$a_ptr,#12]
519         sbcs    $a1,$ff,$a1
520         ldr     $a4,[$a_ptr,#16]
521         sbcs    $a2,$ff,$a2
522         ldr     $a5,[$a_ptr,#20]
523         sbcs    $a3,$ff,$a3
524         ldr     $a6,[$a_ptr,#24]
525         sbcs    $a4,$ff,$a4
526         ldr     $a7,[$a_ptr,#28]
527         sbcs    $a5,$ff,$a5
528         sbcs    $a6,$ff,$a6
529         sbcs    $a7,$ff,$a7
530         sbc     $ff,$ff,$ff
531
532         b       .Lreduce_by_add
533 .size   __ecp_nistz256_neg,.-__ecp_nistz256_neg
534 ___
535 {
536 my @acc=map("r$_",(3..11));
537 my ($t0,$t1,$bj,$t2,$t3)=map("r$_",(0,1,2,12,14));
538
539 $code.=<<___;
540 @ void  ecp_nistz256_sqr_mont(BN_ULONG r0[8],const BN_ULONG r1[8]);
541 .globl  ecp_nistz256_sqr_mont
542 .type   ecp_nistz256_sqr_mont,%function
543 .align  4
544 ecp_nistz256_sqr_mont:
545         mov     $b_ptr,$a_ptr
546         b       .Lecp_nistz256_mul_mont
547 .size   ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
548
549 @ void  ecp_nistz256_mul_mont(BN_ULONG r0[8],const BN_ULONG r1[8],
550 @                                            const BN_ULONG r2[8]);
551 .globl  ecp_nistz256_mul_mont
552 .type   ecp_nistz256_mul_mont,%function
553 .align  4
554 ecp_nistz256_mul_mont:
555 .Lecp_nistz256_mul_mont:
556         stmdb   sp!,{r4-r12,lr}
557         bl      __ecp_nistz256_mul_mont
558 #if __ARM_ARCH__>=5 || !defined(__thumb__)
559         ldmia   sp!,{r4-r12,pc}
560 #else
561         ldmia   sp!,{r4-r12,lr}
562         bx      lr                      @ interoperable with Thumb ISA:-)
563 #endif
564 .size   ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
565
566 .type   __ecp_nistz256_mul_mont,%function
567 .align  4
568 __ecp_nistz256_mul_mont:
569         stmdb   sp!,{r0-r2,lr}                  @ make a copy of arguments too
570
571         ldr     $bj,[$b_ptr,#0]                 @ b[0]
572         ldmia   $a_ptr,{@acc[1]-@acc[8]}
573
574         umull   @acc[0],$t3,@acc[1],$bj         @ r[0]=a[0]*b[0]
575         stmdb   sp!,{$acc[1]-@acc[8]}           @ copy a[0-7] to stack, so
576                                                 @ that it can be addressed
577                                                 @ without spending register
578                                                 @ on address
579         umull   @acc[1],$t0,@acc[2],$bj         @ r[1]=a[1]*b[0]
580         umull   @acc[2],$t1,@acc[3],$bj
581         adds    @acc[1],@acc[1],$t3             @ accumulate high part of mult
582         umull   @acc[3],$t2,@acc[4],$bj
583         adcs    @acc[2],@acc[2],$t0
584         umull   @acc[4],$t3,@acc[5],$bj
585         adcs    @acc[3],@acc[3],$t1
586         umull   @acc[5],$t0,@acc[6],$bj
587         adcs    @acc[4],@acc[4],$t2
588         umull   @acc[6],$t1,@acc[7],$bj
589         adcs    @acc[5],@acc[5],$t3
590         umull   @acc[7],$t2,@acc[8],$bj
591         adcs    @acc[6],@acc[6],$t0
592         adcs    @acc[7],@acc[7],$t1
593         eor     $t3,$t3,$t3                     @ first overflow bit is zero
594         adc     @acc[8],$t2,#0
595 ___
596 for(my $i=1;$i<8;$i++) {
597 my $t4=@acc[0];
598
599         # Reduction iteration is normally performed by accumulating
600         # result of multiplication of modulus by "magic" digit [and
601         # omitting least significant word, which is guaranteed to
602         # be 0], but thanks to special form of modulus and "magic"
603         # digit being equal to least significant word, it can be
604         # performed with additions and subtractions alone. Indeed:
605         #
606         #        ffff.0001.0000.0000.0000.ffff.ffff.ffff
607         # *                                         abcd
608         # + xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.abcd
609         #
610         # Now observing that ff..ff*x = (2^n-1)*x = 2^n*x-x, we
611         # rewrite above as:
612         #
613         #   xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.abcd
614         # + abcd.0000.abcd.0000.0000.abcd.0000.0000.0000
615         # -      abcd.0000.0000.0000.0000.0000.0000.abcd
616         #
617         # or marking redundant operations:
618         #
619         #   xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.----
620         # + abcd.0000.abcd.0000.0000.abcd.----.----.----
621         # -      abcd.----.----.----.----.----.----.----
622
623 $code.=<<___;
624         @ multiplication-less reduction $i
625         adds    @acc[3],@acc[3],@acc[0]         @ r[3]+=r[0]
626          ldr    $bj,[sp,#40]                    @ restore b_ptr
627         adcs    @acc[4],@acc[4],#0              @ r[4]+=0
628         adcs    @acc[5],@acc[5],#0              @ r[5]+=0
629         adcs    @acc[6],@acc[6],@acc[0]         @ r[6]+=r[0]
630          ldr    $t1,[sp,#0]                     @ load a[0]
631         adcs    @acc[7],@acc[7],#0              @ r[7]+=0
632          ldr    $bj,[$bj,#4*$i]                 @ load b[i]
633         adcs    @acc[8],@acc[8],@acc[0]         @ r[8]+=r[0]
634          eor    $t0,$t0,$t0
635         adc     $t3,$t3,#0                      @ overflow bit
636         subs    @acc[7],@acc[7],@acc[0]         @ r[7]-=r[0]
637          ldr    $t2,[sp,#4]                     @ a[1]
638         sbcs    @acc[8],@acc[8],#0              @ r[8]-=0
639          umlal  @acc[1],$t0,$t1,$bj             @ "r[0]"+=a[0]*b[i]
640          eor    $t1,$t1,$t1
641         sbc     @acc[0],$t3,#0                  @ overflow bit, keep in mind
642                                                 @ that netto result is
643                                                 @ addition of a value which
644                                                 @ makes underflow impossible
645
646         ldr     $t3,[sp,#8]                     @ a[2]
647         umlal   @acc[2],$t1,$t2,$bj             @ "r[1]"+=a[1]*b[i]
648          str    @acc[0],[sp,#36]                @ temporarily offload overflow
649         eor     $t2,$t2,$t2
650         ldr     $t4,[sp,#12]                    @ a[3], $t4 is alias @acc[0]
651         umlal   @acc[3],$t2,$t3,$bj             @ "r[2]"+=a[2]*b[i]
652         eor     $t3,$t3,$t3
653         adds    @acc[2],@acc[2],$t0             @ accumulate high part of mult
654         ldr     $t0,[sp,#16]                    @ a[4]
655         umlal   @acc[4],$t3,$t4,$bj             @ "r[3]"+=a[3]*b[i]
656         eor     $t4,$t4,$t4
657         adcs    @acc[3],@acc[3],$t1
658         ldr     $t1,[sp,#20]                    @ a[5]
659         umlal   @acc[5],$t4,$t0,$bj             @ "r[4]"+=a[4]*b[i]
660         eor     $t0,$t0,$t0
661         adcs    @acc[4],@acc[4],$t2
662         ldr     $t2,[sp,#24]                    @ a[6]
663         umlal   @acc[6],$t0,$t1,$bj             @ "r[5]"+=a[5]*b[i]
664         eor     $t1,$t1,$t1
665         adcs    @acc[5],@acc[5],$t3
666         ldr     $t3,[sp,#28]                    @ a[7]
667         umlal   @acc[7],$t1,$t2,$bj             @ "r[6]"+=a[6]*b[i]
668         eor     $t2,$t2,$t2
669         adcs    @acc[6],@acc[6],$t4
670          ldr    @acc[0],[sp,#36]                @ restore overflow bit
671         umlal   @acc[8],$t2,$t3,$bj             @ "r[7]"+=a[7]*b[i]
672         eor     $t3,$t3,$t3
673         adcs    @acc[7],@acc[7],$t0
674         adcs    @acc[8],@acc[8],$t1
675         adcs    @acc[0],$acc[0],$t2
676         adc     $t3,$t3,#0                      @ new overflow bit
677 ___
678         push(@acc,shift(@acc));                 # rotate registers, so that
679                                                 # "r[i]" becomes r[i]
680 }
681 $code.=<<___;
682         @ last multiplication-less reduction
683         adds    @acc[3],@acc[3],@acc[0]
684         ldr     $r_ptr,[sp,#32]                 @ restore r_ptr
685         adcs    @acc[4],@acc[4],#0
686         adcs    @acc[5],@acc[5],#0
687         adcs    @acc[6],@acc[6],@acc[0]
688         adcs    @acc[7],@acc[7],#0
689         adcs    @acc[8],@acc[8],@acc[0]
690         adc     $t3,$t3,#0
691         subs    @acc[7],@acc[7],@acc[0]
692         sbcs    @acc[8],@acc[8],#0
693         sbc     @acc[0],$t3,#0                  @ overflow bit
694
695         @ Final step is "if result > mod, subtract mod", but we do it
696         @ "other way around", namely subtract modulus from result
697         @ and if it borrowed, add modulus back.
698
699         adds    @acc[1],@acc[1],#1              @ subs  @acc[1],@acc[1],#-1
700         adcs    @acc[2],@acc[2],#0              @ sbcs  @acc[2],@acc[2],#-1
701         adcs    @acc[3],@acc[3],#0              @ sbcs  @acc[3],@acc[3],#-1
702         sbcs    @acc[4],@acc[4],#0
703         sbcs    @acc[5],@acc[5],#0
704         sbcs    @acc[6],@acc[6],#0
705         sbcs    @acc[7],@acc[7],#1
706         adcs    @acc[8],@acc[8],#0              @ sbcs  @acc[8],@acc[8],#-1
707         ldr     lr,[sp,#44]                     @ restore lr
708         sbc     @acc[0],@acc[0],#0              @ broadcast borrow bit
709         add     sp,sp,#48
710
711         @ Note that because mod has special form, i.e. consists of
712         @ 0xffffffff, 1 and 0s, we can conditionally synthesize it by
713         @ broadcasting borrow bit to a register, @acc[0], and using it as
714         @ a whole or extracting single bit.
715
716         adds    @acc[1],@acc[1],@acc[0]         @ add modulus or zero
717         adcs    @acc[2],@acc[2],@acc[0]
718         str     @acc[1],[$r_ptr,#0]
719         adcs    @acc[3],@acc[3],@acc[0]
720         str     @acc[2],[$r_ptr,#4]
721         adcs    @acc[4],@acc[4],#0
722         str     @acc[3],[$r_ptr,#8]
723         adcs    @acc[5],@acc[5],#0
724         str     @acc[4],[$r_ptr,#12]
725         adcs    @acc[6],@acc[6],#0
726         str     @acc[5],[$r_ptr,#16]
727         adcs    @acc[7],@acc[7],@acc[0],lsr#31
728         str     @acc[6],[$r_ptr,#20]
729         adc     @acc[8],@acc[8],@acc[0]
730         str     @acc[7],[$r_ptr,#24]
731         str     @acc[8],[$r_ptr,#28]
732
733         mov     pc,lr
734 .size   __ecp_nistz256_mul_mont,.-__ecp_nistz256_mul_mont
735 ___
736 }
737
738 {
739 my ($out,$inp,$index,$mask)=map("r$_",(0..3));
740 $code.=<<___;
741 @ void  ecp_nistz256_scatter_w5(void *r0,const P256_POINT *r1,
742 @                                        int r2);
743 .globl  ecp_nistz256_scatter_w5
744 .type   ecp_nistz256_scatter_w5,%function
745 .align  5
746 ecp_nistz256_scatter_w5:
747         stmdb   sp!,{r4-r11}
748
749         add     $out,$out,$index,lsl#2
750
751         ldmia   $inp!,{r4-r11}          @ X
752         str     r4,[$out,#64*0-4]
753         str     r5,[$out,#64*1-4]
754         str     r6,[$out,#64*2-4]
755         str     r7,[$out,#64*3-4]
756         str     r8,[$out,#64*4-4]
757         str     r9,[$out,#64*5-4]
758         str     r10,[$out,#64*6-4]
759         str     r11,[$out,#64*7-4]
760         add     $out,$out,#64*8
761
762         ldmia   $inp!,{r4-r11}          @ Y
763         str     r4,[$out,#64*0-4]
764         str     r5,[$out,#64*1-4]
765         str     r6,[$out,#64*2-4]
766         str     r7,[$out,#64*3-4]
767         str     r8,[$out,#64*4-4]
768         str     r9,[$out,#64*5-4]
769         str     r10,[$out,#64*6-4]
770         str     r11,[$out,#64*7-4]
771         add     $out,$out,#64*8
772
773         ldmia   $inp,{r4-r11}           @ Z
774         str     r4,[$out,#64*0-4]
775         str     r5,[$out,#64*1-4]
776         str     r6,[$out,#64*2-4]
777         str     r7,[$out,#64*3-4]
778         str     r8,[$out,#64*4-4]
779         str     r9,[$out,#64*5-4]
780         str     r10,[$out,#64*6-4]
781         str     r11,[$out,#64*7-4]
782
783         ldmia   sp!,{r4-r11}
784 #if __ARM_ARCH__>=5 || defined(__thumb__)
785         bx      lr
786 #else
787         mov     pc,lr
788 #endif
789 .size   ecp_nistz256_scatter_w5,.-ecp_nistz256_scatter_w5
790
791 @ void  ecp_nistz256_gather_w5(P256_POINT *r0,const void *r1,
792 @                                             int r2);
793 .globl  ecp_nistz256_gather_w5
794 .type   ecp_nistz256_gather_w5,%function
795 .align  5
796 ecp_nistz256_gather_w5:
797         stmdb   sp!,{r4-r11}
798
799         cmp     $index,#0
800         mov     $mask,#0
801 #ifdef  __thumb2__
802         itt     ne
803 #endif
804         subne   $index,$index,#1
805         movne   $mask,#-1
806         add     $inp,$inp,$index,lsl#2
807
808         ldr     r4,[$inp,#64*0]
809         ldr     r5,[$inp,#64*1]
810         ldr     r6,[$inp,#64*2]
811         and     r4,r4,$mask
812         ldr     r7,[$inp,#64*3]
813         and     r5,r5,$mask
814         ldr     r8,[$inp,#64*4]
815         and     r6,r6,$mask
816         ldr     r9,[$inp,#64*5]
817         and     r7,r7,$mask
818         ldr     r10,[$inp,#64*6]
819         and     r8,r8,$mask
820         ldr     r11,[$inp,#64*7]
821         add     $inp,$inp,#64*8
822         and     r9,r9,$mask
823         and     r10,r10,$mask
824         and     r11,r11,$mask
825         stmia   $out!,{r4-r11}  @ X
826
827         ldr     r4,[$inp,#64*0]
828         ldr     r5,[$inp,#64*1]
829         ldr     r6,[$inp,#64*2]
830         and     r4,r4,$mask
831         ldr     r7,[$inp,#64*3]
832         and     r5,r5,$mask
833         ldr     r8,[$inp,#64*4]
834         and     r6,r6,$mask
835         ldr     r9,[$inp,#64*5]
836         and     r7,r7,$mask
837         ldr     r10,[$inp,#64*6]
838         and     r8,r8,$mask
839         ldr     r11,[$inp,#64*7]
840         add     $inp,$inp,#64*8
841         and     r9,r9,$mask
842         and     r10,r10,$mask
843         and     r11,r11,$mask
844         stmia   $out!,{r4-r11}  @ Y
845
846         ldr     r4,[$inp,#64*0]
847         ldr     r5,[$inp,#64*1]
848         ldr     r6,[$inp,#64*2]
849         and     r4,r4,$mask
850         ldr     r7,[$inp,#64*3]
851         and     r5,r5,$mask
852         ldr     r8,[$inp,#64*4]
853         and     r6,r6,$mask
854         ldr     r9,[$inp,#64*5]
855         and     r7,r7,$mask
856         ldr     r10,[$inp,#64*6]
857         and     r8,r8,$mask
858         ldr     r11,[$inp,#64*7]
859         and     r9,r9,$mask
860         and     r10,r10,$mask
861         and     r11,r11,$mask
862         stmia   $out,{r4-r11}           @ Z
863
864         ldmia   sp!,{r4-r11}
865 #if __ARM_ARCH__>=5 || defined(__thumb__)
866         bx      lr
867 #else
868         mov     pc,lr
869 #endif
870 .size   ecp_nistz256_gather_w5,.-ecp_nistz256_gather_w5
871
872 @ void  ecp_nistz256_scatter_w7(void *r0,const P256_POINT_AFFINE *r1,
873 @                                        int r2);
874 .globl  ecp_nistz256_scatter_w7
875 .type   ecp_nistz256_scatter_w7,%function
876 .align  5
877 ecp_nistz256_scatter_w7:
878         add     $out,$out,$index
879         mov     $index,#64/4
880 .Loop_scatter_w7:
881         ldr     $mask,[$inp],#4
882         subs    $index,$index,#1
883         strb    $mask,[$out,#64*0-1]
884         mov     $mask,$mask,lsr#8
885         strb    $mask,[$out,#64*1-1]
886         mov     $mask,$mask,lsr#8
887         strb    $mask,[$out,#64*2-1]
888         mov     $mask,$mask,lsr#8
889         strb    $mask,[$out,#64*3-1]
890         add     $out,$out,#64*4
891         bne     .Loop_scatter_w7
892
893 #if __ARM_ARCH__>=5 || defined(__thumb__)
894         bx      lr
895 #else
896         mov     pc,lr
897 #endif
898 .size   ecp_nistz256_scatter_w7,.-ecp_nistz256_scatter_w7
899
900 @ void  ecp_nistz256_gather_w7(P256_POINT_AFFINE *r0,const void *r1,
901 @                                                    int r2);
902 .globl  ecp_nistz256_gather_w7
903 .type   ecp_nistz256_gather_w7,%function
904 .align  5
905 ecp_nistz256_gather_w7:
906         stmdb   sp!,{r4-r7}
907
908         cmp     $index,#0
909         mov     $mask,#0
910 #ifdef  __thumb2__
911         itt     ne
912 #endif
913         subne   $index,$index,#1
914         movne   $mask,#-1
915         add     $inp,$inp,$index
916         mov     $index,#64/4
917         nop
918 .Loop_gather_w7:
919         ldrb    r4,[$inp,#64*0]
920         subs    $index,$index,#1
921         ldrb    r5,[$inp,#64*1]
922         ldrb    r6,[$inp,#64*2]
923         ldrb    r7,[$inp,#64*3]
924         add     $inp,$inp,#64*4
925         orr     r4,r4,r5,lsl#8
926         orr     r4,r4,r6,lsl#16
927         orr     r4,r4,r7,lsl#24
928         and     r4,r4,$mask
929         str     r4,[$out],#4
930         bne     .Loop_gather_w7
931
932         ldmia   sp!,{r4-r7}
933 #if __ARM_ARCH__>=5 || defined(__thumb__)
934         bx      lr
935 #else
936         mov     pc,lr
937 #endif
938 .size   ecp_nistz256_gather_w7,.-ecp_nistz256_gather_w7
939 ___
940 }
941 if (0) {
942 # In comparison to integer-only equivalent of below subroutine:
943 #
944 # Cortex-A8     +10%
945 # Cortex-A9     -10%
946 # Snapdragon S4 +5%
947 #
948 # As not all time is spent in multiplication, overall impact is deemed
949 # too low to care about.
950
951 my ($A0,$A1,$A2,$A3,$Bi,$zero,$temp)=map("d$_",(0..7));
952 my $mask="q4";
953 my $mult="q5";
954 my @AxB=map("q$_",(8..15));
955
956 my ($rptr,$aptr,$bptr,$toutptr)=map("r$_",(0..3));
957
958 $code.=<<___;
959 #if __ARM_ARCH__>=7
960 .fpu    neon
961
962 .globl  ecp_nistz256_mul_mont_neon
963 .type   ecp_nistz256_mul_mont_neon,%function
964 .align  5
965 ecp_nistz256_mul_mont_neon:
966         mov     ip,sp
967         stmdb   sp!,{r4-r9}
968         vstmdb  sp!,{q4-q5}             @ ABI specification says so
969
970         sub             $toutptr,sp,#40
971         vld1.32         {${Bi}[0]},[$bptr,:32]!
972         veor            $zero,$zero,$zero
973         vld1.32         {$A0-$A3}, [$aptr]              @ can't specify :32 :-(
974         vzip.16         $Bi,$zero
975         mov             sp,$toutptr                     @ alloca
976         vmov.i64        $mask,#0xffff
977
978         vmull.u32       @AxB[0],$Bi,${A0}[0]
979         vmull.u32       @AxB[1],$Bi,${A0}[1]
980         vmull.u32       @AxB[2],$Bi,${A1}[0]
981         vmull.u32       @AxB[3],$Bi,${A1}[1]
982          vshr.u64       $temp,@AxB[0]#lo,#16
983         vmull.u32       @AxB[4],$Bi,${A2}[0]
984          vadd.u64       @AxB[0]#hi,@AxB[0]#hi,$temp
985         vmull.u32       @AxB[5],$Bi,${A2}[1]
986          vshr.u64       $temp,@AxB[0]#hi,#16            @ upper 32 bits of a[0]*b[0]
987         vmull.u32       @AxB[6],$Bi,${A3}[0]
988          vand.u64       @AxB[0],@AxB[0],$mask           @ lower 32 bits of a[0]*b[0]
989         vmull.u32       @AxB[7],$Bi,${A3}[1]
990 ___
991 for($i=1;$i<8;$i++) {
992 $code.=<<___;
993          vld1.32        {${Bi}[0]},[$bptr,:32]!
994          veor           $zero,$zero,$zero
995         vadd.u64        @AxB[1]#lo,@AxB[1]#lo,$temp     @ reduction
996         vshl.u64        $mult,@AxB[0],#32
997         vadd.u64        @AxB[3],@AxB[3],@AxB[0]
998         vsub.u64        $mult,$mult,@AxB[0]
999          vzip.16        $Bi,$zero
1000         vadd.u64        @AxB[6],@AxB[6],@AxB[0]
1001         vadd.u64        @AxB[7],@AxB[7],$mult
1002 ___
1003         push(@AxB,shift(@AxB));
1004 $code.=<<___;
1005         vmlal.u32       @AxB[0],$Bi,${A0}[0]
1006         vmlal.u32       @AxB[1],$Bi,${A0}[1]
1007         vmlal.u32       @AxB[2],$Bi,${A1}[0]
1008         vmlal.u32       @AxB[3],$Bi,${A1}[1]
1009          vshr.u64       $temp,@AxB[0]#lo,#16
1010         vmlal.u32       @AxB[4],$Bi,${A2}[0]
1011          vadd.u64       @AxB[0]#hi,@AxB[0]#hi,$temp
1012         vmlal.u32       @AxB[5],$Bi,${A2}[1]
1013          vshr.u64       $temp,@AxB[0]#hi,#16            @ upper 33 bits of a[0]*b[i]+t[0]
1014         vmlal.u32       @AxB[6],$Bi,${A3}[0]
1015          vand.u64       @AxB[0],@AxB[0],$mask           @ lower 32 bits of a[0]*b[0]
1016         vmull.u32       @AxB[7],$Bi,${A3}[1]
1017 ___
1018 }
1019 $code.=<<___;
1020         vadd.u64        @AxB[1]#lo,@AxB[1]#lo,$temp     @ last reduction
1021         vshl.u64        $mult,@AxB[0],#32
1022         vadd.u64        @AxB[3],@AxB[3],@AxB[0]
1023         vsub.u64        $mult,$mult,@AxB[0]
1024         vadd.u64        @AxB[6],@AxB[6],@AxB[0]
1025         vadd.u64        @AxB[7],@AxB[7],$mult
1026
1027         vshr.u64        $temp,@AxB[1]#lo,#16            @ convert
1028         vadd.u64        @AxB[1]#hi,@AxB[1]#hi,$temp
1029         vshr.u64        $temp,@AxB[1]#hi,#16
1030         vzip.16         @AxB[1]#lo,@AxB[1]#hi
1031 ___
1032 foreach (2..7) {
1033 $code.=<<___;
1034         vadd.u64        @AxB[$_]#lo,@AxB[$_]#lo,$temp
1035         vst1.32         {@AxB[$_-1]#lo[0]},[$toutptr,:32]!
1036         vshr.u64        $temp,@AxB[$_]#lo,#16
1037         vadd.u64        @AxB[$_]#hi,@AxB[$_]#hi,$temp
1038         vshr.u64        $temp,@AxB[$_]#hi,#16
1039         vzip.16         @AxB[$_]#lo,@AxB[$_]#hi
1040 ___
1041 }
1042 $code.=<<___;
1043         vst1.32         {@AxB[7]#lo[0]},[$toutptr,:32]!
1044         vst1.32         {$temp},[$toutptr]              @ upper 33 bits
1045
1046         ldr     r1,[sp,#0]
1047         ldr     r2,[sp,#4]
1048         ldr     r3,[sp,#8]
1049         subs    r1,r1,#-1
1050         ldr     r4,[sp,#12]
1051         sbcs    r2,r2,#-1
1052         ldr     r5,[sp,#16]
1053         sbcs    r3,r3,#-1
1054         ldr     r6,[sp,#20]
1055         sbcs    r4,r4,#0
1056         ldr     r7,[sp,#24]
1057         sbcs    r5,r5,#0
1058         ldr     r8,[sp,#28]
1059         sbcs    r6,r6,#0
1060         ldr     r9,[sp,#32]                             @ top-most bit
1061         sbcs    r7,r7,#1
1062         sub     sp,ip,#40+16
1063         sbcs    r8,r8,#-1
1064         sbc     r9,r9,#0
1065         vldmia  sp!,{q4-q5}
1066
1067         adds    r1,r1,r9
1068         adcs    r2,r2,r9
1069         str     r1,[$rptr,#0]
1070         adcs    r3,r3,r9
1071         str     r2,[$rptr,#4]
1072         adcs    r4,r4,#0
1073         str     r3,[$rptr,#8]
1074         adcs    r5,r5,#0
1075         str     r4,[$rptr,#12]
1076         adcs    r6,r6,#0
1077         str     r5,[$rptr,#16]
1078         adcs    r7,r7,r9,lsr#31
1079         str     r6,[$rptr,#20]
1080         adcs    r8,r8,r9
1081         str     r7,[$rptr,#24]
1082         str     r8,[$rptr,#28]
1083
1084         ldmia   sp!,{r4-r9}
1085         bx      lr
1086 .size   ecp_nistz256_mul_mont_neon,.-ecp_nistz256_mul_mont_neon
1087 #endif
1088 ___
1089 }
1090
1091 {{{
1092 ########################################################################
1093 # Below $aN assignment matches order in which 256-bit result appears in
1094 # register bank at return from __ecp_nistz256_mul_mont, so that we can
1095 # skip over reloading it from memory. This means that below functions
1096 # use custom calling sequence accepting 256-bit input in registers,
1097 # output pointer in r0, $r_ptr, and optional pointer in r2, $b_ptr.
1098 #
1099 # See their "normal" counterparts for insights on calculations.
1100
1101 my ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,
1102     $t0,$t1,$t2,$t3)=map("r$_",(11,3..10,12,14,1));
1103 my $ff=$b_ptr;
1104
1105 $code.=<<___;
1106 .type   __ecp_nistz256_sub_from,%function
1107 .align  5
1108 __ecp_nistz256_sub_from:
1109         str     lr,[sp,#-4]!            @ push lr
1110
1111          ldr    $t0,[$b_ptr,#0]
1112          ldr    $t1,[$b_ptr,#4]
1113          ldr    $t2,[$b_ptr,#8]
1114          ldr    $t3,[$b_ptr,#12]
1115         subs    $a0,$a0,$t0
1116          ldr    $t0,[$b_ptr,#16]
1117         sbcs    $a1,$a1,$t1
1118          ldr    $t1,[$b_ptr,#20]
1119         sbcs    $a2,$a2,$t2
1120          ldr    $t2,[$b_ptr,#24]
1121         sbcs    $a3,$a3,$t3
1122          ldr    $t3,[$b_ptr,#28]
1123         sbcs    $a4,$a4,$t0
1124         sbcs    $a5,$a5,$t1
1125         sbcs    $a6,$a6,$t2
1126         sbcs    $a7,$a7,$t3
1127         sbc     $ff,$ff,$ff             @ broadcast borrow bit
1128         ldr     lr,[sp],#4              @ pop lr
1129
1130         adds    $a0,$a0,$ff             @ add synthesized modulus
1131         adcs    $a1,$a1,$ff
1132         str     $a0,[$r_ptr,#0]
1133         adcs    $a2,$a2,$ff
1134         str     $a1,[$r_ptr,#4]
1135         adcs    $a3,$a3,#0
1136         str     $a2,[$r_ptr,#8]
1137         adcs    $a4,$a4,#0
1138         str     $a3,[$r_ptr,#12]
1139         adcs    $a5,$a5,#0
1140         str     $a4,[$r_ptr,#16]
1141         adcs    $a6,$a6,$ff,lsr#31
1142         str     $a5,[$r_ptr,#20]
1143         adcs    $a7,$a7,$ff
1144         str     $a6,[$r_ptr,#24]
1145         str     $a7,[$r_ptr,#28]
1146
1147         mov     pc,lr
1148 .size   __ecp_nistz256_sub_from,.-__ecp_nistz256_sub_from
1149
1150 .type   __ecp_nistz256_sub_morf,%function
1151 .align  5
1152 __ecp_nistz256_sub_morf:
1153         str     lr,[sp,#-4]!            @ push lr
1154
1155          ldr    $t0,[$b_ptr,#0]
1156          ldr    $t1,[$b_ptr,#4]
1157          ldr    $t2,[$b_ptr,#8]
1158          ldr    $t3,[$b_ptr,#12]
1159         subs    $a0,$t0,$a0
1160          ldr    $t0,[$b_ptr,#16]
1161         sbcs    $a1,$t1,$a1
1162          ldr    $t1,[$b_ptr,#20]
1163         sbcs    $a2,$t2,$a2
1164          ldr    $t2,[$b_ptr,#24]
1165         sbcs    $a3,$t3,$a3
1166          ldr    $t3,[$b_ptr,#28]
1167         sbcs    $a4,$t0,$a4
1168         sbcs    $a5,$t1,$a5
1169         sbcs    $a6,$t2,$a6
1170         sbcs    $a7,$t3,$a7
1171         sbc     $ff,$ff,$ff             @ broadcast borrow bit
1172         ldr     lr,[sp],#4              @ pop lr
1173
1174         adds    $a0,$a0,$ff             @ add synthesized modulus
1175         adcs    $a1,$a1,$ff
1176         str     $a0,[$r_ptr,#0]
1177         adcs    $a2,$a2,$ff
1178         str     $a1,[$r_ptr,#4]
1179         adcs    $a3,$a3,#0
1180         str     $a2,[$r_ptr,#8]
1181         adcs    $a4,$a4,#0
1182         str     $a3,[$r_ptr,#12]
1183         adcs    $a5,$a5,#0
1184         str     $a4,[$r_ptr,#16]
1185         adcs    $a6,$a6,$ff,lsr#31
1186         str     $a5,[$r_ptr,#20]
1187         adcs    $a7,$a7,$ff
1188         str     $a6,[$r_ptr,#24]
1189         str     $a7,[$r_ptr,#28]
1190
1191         mov     pc,lr
1192 .size   __ecp_nistz256_sub_morf,.-__ecp_nistz256_sub_morf
1193
1194 .type   __ecp_nistz256_add_self,%function
1195 .align  4
1196 __ecp_nistz256_add_self:
1197         adds    $a0,$a0,$a0             @ a[0:7]+=a[0:7]
1198         adcs    $a1,$a1,$a1
1199         adcs    $a2,$a2,$a2
1200         adcs    $a3,$a3,$a3
1201         adcs    $a4,$a4,$a4
1202         adcs    $a5,$a5,$a5
1203         adcs    $a6,$a6,$a6
1204         mov     $ff,#0
1205         adcs    $a7,$a7,$a7
1206 #ifdef  __thumb2__
1207         it      cs
1208 #endif
1209         movcs   $ff,#-1                 @ $ff = carry ? -1 : 0
1210
1211         subs    $a0,$a0,$ff             @ subtract synthesized modulus
1212         sbcs    $a1,$a1,$ff
1213         str     $a0,[$r_ptr,#0]
1214         sbcs    $a2,$a2,$ff
1215         str     $a1,[$r_ptr,#4]
1216         sbcs    $a3,$a3,#0
1217         str     $a2,[$r_ptr,#8]
1218         sbcs    $a4,$a4,#0
1219         str     $a3,[$r_ptr,#12]
1220         sbcs    $a5,$a5,#0
1221         str     $a4,[$r_ptr,#16]
1222         sbcs    $a6,$a6,$ff,lsr#31
1223         str     $a5,[$r_ptr,#20]
1224         sbcs    $a7,$a7,$ff
1225         str     $a6,[$r_ptr,#24]
1226         str     $a7,[$r_ptr,#28]
1227
1228         mov     pc,lr
1229 .size   __ecp_nistz256_add_self,.-__ecp_nistz256_add_self
1230
1231 ___
1232
1233 ########################################################################
1234 # following subroutines are "literal" implemetation of those found in
1235 # ecp_nistz256.c
1236 #
1237 ########################################################################
1238 # void ecp_nistz256_point_double(P256_POINT *out,const P256_POINT *inp);
1239 #
1240 {
1241 my ($S,$M,$Zsqr,$in_x,$tmp0)=map(32*$_,(0..4));
1242 # above map() describes stack layout with 5 temporary
1243 # 256-bit vectors on top. Then note that we push
1244 # starting from r0, which means that we have copy of
1245 # input arguments just below these temporary vectors.
1246
1247 $code.=<<___;
1248 .globl  ecp_nistz256_point_double
1249 .type   ecp_nistz256_point_double,%function
1250 .align  5
1251 ecp_nistz256_point_double:
1252         stmdb   sp!,{r0-r12,lr}         @ push from r0, unusual, but intentional
1253         sub     sp,sp,#32*5
1254
1255         add     r3,sp,#$in_x
1256         ldmia   $a_ptr!,{r4-r11}        @ copy in_x
1257         stmia   r3,{r4-r11}
1258
1259         add     $r_ptr,sp,#$S
1260         bl      __ecp_nistz256_mul_by_2 @ p256_mul_by_2(S, in_y);
1261
1262         add     $b_ptr,$a_ptr,#32
1263         add     $a_ptr,$a_ptr,#32
1264         add     $r_ptr,sp,#$Zsqr
1265         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Zsqr, in_z);
1266
1267         add     $a_ptr,sp,#$S
1268         add     $b_ptr,sp,#$S
1269         add     $r_ptr,sp,#$S
1270         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(S, S);
1271
1272         ldr     $b_ptr,[sp,#32*5+4]
1273         add     $a_ptr,$b_ptr,#32
1274         add     $b_ptr,$b_ptr,#64
1275         add     $r_ptr,sp,#$tmp0
1276         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(tmp0, in_z, in_y);
1277
1278         ldr     $r_ptr,[sp,#32*5]
1279         add     $r_ptr,$r_ptr,#64
1280         bl      __ecp_nistz256_add_self @ p256_mul_by_2(res_z, tmp0);
1281
1282         add     $a_ptr,sp,#$in_x
1283         add     $b_ptr,sp,#$Zsqr
1284         add     $r_ptr,sp,#$M
1285         bl      __ecp_nistz256_add      @ p256_add(M, in_x, Zsqr);
1286
1287         add     $a_ptr,sp,#$in_x
1288         add     $b_ptr,sp,#$Zsqr
1289         add     $r_ptr,sp,#$Zsqr
1290         bl      __ecp_nistz256_sub      @ p256_sub(Zsqr, in_x, Zsqr);
1291
1292         add     $a_ptr,sp,#$S
1293         add     $b_ptr,sp,#$S
1294         add     $r_ptr,sp,#$tmp0
1295         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(tmp0, S);
1296
1297         add     $a_ptr,sp,#$Zsqr
1298         add     $b_ptr,sp,#$M
1299         add     $r_ptr,sp,#$M
1300         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(M, M, Zsqr);
1301
1302         ldr     $r_ptr,[sp,#32*5]
1303         add     $a_ptr,sp,#$tmp0
1304         add     $r_ptr,$r_ptr,#32
1305         bl      __ecp_nistz256_div_by_2 @ p256_div_by_2(res_y, tmp0);
1306
1307         add     $a_ptr,sp,#$M
1308         add     $r_ptr,sp,#$M
1309         bl      __ecp_nistz256_mul_by_3 @ p256_mul_by_3(M, M);
1310
1311         add     $a_ptr,sp,#$in_x
1312         add     $b_ptr,sp,#$S
1313         add     $r_ptr,sp,#$S
1314         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S, S, in_x);
1315
1316         add     $r_ptr,sp,#$tmp0
1317         bl      __ecp_nistz256_add_self @ p256_mul_by_2(tmp0, S);
1318
1319         ldr     $r_ptr,[sp,#32*5]
1320         add     $a_ptr,sp,#$M
1321         add     $b_ptr,sp,#$M
1322         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(res_x, M);
1323
1324         add     $b_ptr,sp,#$tmp0
1325         bl      __ecp_nistz256_sub_from @ p256_sub(res_x, res_x, tmp0);
1326
1327         add     $b_ptr,sp,#$S
1328         add     $r_ptr,sp,#$S
1329         bl      __ecp_nistz256_sub_morf @ p256_sub(S, S, res_x);
1330
1331         add     $a_ptr,sp,#$M
1332         add     $b_ptr,sp,#$S
1333         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S, S, M);
1334
1335         ldr     $r_ptr,[sp,#32*5]
1336         add     $b_ptr,$r_ptr,#32
1337         add     $r_ptr,$r_ptr,#32
1338         bl      __ecp_nistz256_sub_from @ p256_sub(res_y, S, res_y);
1339
1340         add     sp,sp,#32*5+16          @ +16 means "skip even over saved r0-r3"
1341 #if __ARM_ARCH__>=5 || !defined(__thumb__)
1342         ldmia   sp!,{r4-r12,pc}
1343 #else
1344         ldmia   sp!,{r4-r12,lr}
1345         bx      lr                      @ interoperable with Thumb ISA:-)
1346 #endif
1347 .size   ecp_nistz256_point_double,.-ecp_nistz256_point_double
1348 ___
1349 }
1350
1351 ########################################################################
1352 # void ecp_nistz256_point_add(P256_POINT *out,const P256_POINT *in1,
1353 #                             const P256_POINT *in2);
1354 {
1355 my ($res_x,$res_y,$res_z,
1356     $in1_x,$in1_y,$in1_z,
1357     $in2_x,$in2_y,$in2_z,
1358     $H,$Hsqr,$R,$Rsqr,$Hcub,
1359     $U1,$U2,$S1,$S2)=map(32*$_,(0..17));
1360 my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
1361 # above map() describes stack layout with 18 temporary
1362 # 256-bit vectors on top. Then note that we push
1363 # starting from r0, which means that we have copy of
1364 # input arguments just below these temporary vectors.
1365 # We use three of them for !in1infty, !in2intfy and
1366 # result of check for zero.
1367
1368 $code.=<<___;
1369 .globl  ecp_nistz256_point_add
1370 .type   ecp_nistz256_point_add,%function
1371 .align  5
1372 ecp_nistz256_point_add:
1373         stmdb   sp!,{r0-r12,lr}         @ push from r0, unusual, but intentional
1374         sub     sp,sp,#32*18
1375
1376         ldmia   $b_ptr!,{r4-r11}        @ copy in2
1377         add     r3,sp,#$in2_x
1378         orr     r12,r4,r5
1379         orr     r12,r12,r6
1380         orr     r12,r12,r7
1381         orr     r12,r12,r8
1382         orr     r12,r12,r9
1383         orr     r12,r12,r10
1384         orr     r12,r12,r11
1385         stmia   r3!,{r4-r11}
1386         ldmia   $b_ptr!,{r4-r11}
1387         orr     r12,r12,r4
1388         orr     r12,r12,r5
1389         orr     r12,r12,r6
1390         orr     r12,r12,r7
1391         orr     r12,r12,r8
1392         orr     r12,r12,r9
1393         orr     r12,r12,r10
1394         orr     r12,r12,r11
1395         stmia   r3!,{r4-r11}
1396         ldmia   $b_ptr,{r4-r11}
1397         cmp     r12,#0
1398 #ifdef  __thumb2__
1399         it      ne
1400 #endif
1401         movne   r12,#-1
1402         stmia   r3,{r4-r11}
1403         str     r12,[sp,#32*18+8]       @ !in2infty
1404
1405         ldmia   $a_ptr!,{r4-r11}        @ copy in1
1406         add     r3,sp,#$in1_x
1407         orr     r12,r4,r5
1408         orr     r12,r12,r6
1409         orr     r12,r12,r7
1410         orr     r12,r12,r8
1411         orr     r12,r12,r9
1412         orr     r12,r12,r10
1413         orr     r12,r12,r11
1414         stmia   r3!,{r4-r11}
1415         ldmia   $a_ptr!,{r4-r11}
1416         orr     r12,r12,r4
1417         orr     r12,r12,r5
1418         orr     r12,r12,r6
1419         orr     r12,r12,r7
1420         orr     r12,r12,r8
1421         orr     r12,r12,r9
1422         orr     r12,r12,r10
1423         orr     r12,r12,r11
1424         stmia   r3!,{r4-r11}
1425         ldmia   $a_ptr,{r4-r11}
1426         cmp     r12,#0
1427 #ifdef  __thumb2__
1428         it      ne
1429 #endif
1430         movne   r12,#-1
1431         stmia   r3,{r4-r11}
1432         str     r12,[sp,#32*18+4]       @ !in1infty
1433
1434         add     $a_ptr,sp,#$in2_z
1435         add     $b_ptr,sp,#$in2_z
1436         add     $r_ptr,sp,#$Z2sqr
1437         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Z2sqr, in2_z);
1438
1439         add     $a_ptr,sp,#$in1_z
1440         add     $b_ptr,sp,#$in1_z
1441         add     $r_ptr,sp,#$Z1sqr
1442         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Z1sqr, in1_z);
1443
1444         add     $a_ptr,sp,#$in2_z
1445         add     $b_ptr,sp,#$Z2sqr
1446         add     $r_ptr,sp,#$S1
1447         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S1, Z2sqr, in2_z);
1448
1449         add     $a_ptr,sp,#$in1_z
1450         add     $b_ptr,sp,#$Z1sqr
1451         add     $r_ptr,sp,#$S2
1452         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, Z1sqr, in1_z);
1453
1454         add     $a_ptr,sp,#$in1_y
1455         add     $b_ptr,sp,#$S1
1456         add     $r_ptr,sp,#$S1
1457         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S1, S1, in1_y);
1458
1459         add     $a_ptr,sp,#$in2_y
1460         add     $b_ptr,sp,#$S2
1461         add     $r_ptr,sp,#$S2
1462         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, S2, in2_y);
1463
1464         add     $b_ptr,sp,#$S1
1465         add     $r_ptr,sp,#$R
1466         bl      __ecp_nistz256_sub_from @ p256_sub(R, S2, S1);
1467
1468         orr     $a0,$a0,$a1             @ see if result is zero
1469         orr     $a2,$a2,$a3
1470         orr     $a4,$a4,$a5
1471         orr     $a0,$a0,$a2
1472         orr     $a4,$a4,$a6
1473         orr     $a0,$a0,$a7
1474          add    $a_ptr,sp,#$in1_x
1475         orr     $a0,$a0,$a4
1476          add    $b_ptr,sp,#$Z2sqr
1477         str     $a0,[sp,#32*18+12]
1478
1479         add     $r_ptr,sp,#$U1
1480         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U1, in1_x, Z2sqr);
1481
1482         add     $a_ptr,sp,#$in2_x
1483         add     $b_ptr,sp,#$Z1sqr
1484         add     $r_ptr,sp,#$U2
1485         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U2, in2_x, Z1sqr);
1486
1487         add     $b_ptr,sp,#$U1
1488         add     $r_ptr,sp,#$H
1489         bl      __ecp_nistz256_sub_from @ p256_sub(H, U2, U1);
1490
1491         orr     $a0,$a0,$a1             @ see if result is zero
1492         orr     $a2,$a2,$a3
1493         orr     $a4,$a4,$a5
1494         orr     $a0,$a0,$a2
1495         orr     $a4,$a4,$a6
1496         orr     $a0,$a0,$a7
1497         orrs    $a0,$a0,$a4
1498
1499         bne     .Ladd_proceed           @ is_equal(U1,U2)?
1500
1501         ldr     $t0,[sp,#32*18+4]
1502         ldr     $t1,[sp,#32*18+8]
1503         ldr     $t2,[sp,#32*18+12]
1504         tst     $t0,$t1
1505         beq     .Ladd_proceed           @ (in1infty || in2infty)?
1506         tst     $t2,$t2
1507         beq     .Ladd_proceed           @ is_equal(S1,S2)?
1508
1509         ldr     $r_ptr,[sp,#32*18]
1510         eor     r4,r4,r4
1511         eor     r5,r5,r5
1512         eor     r6,r6,r6
1513         eor     r7,r7,r7
1514         eor     r8,r8,r8
1515         eor     r9,r9,r9
1516         eor     r10,r10,r10
1517         eor     r11,r11,r11
1518         stmia   $r_ptr!,{r4-r11}
1519         stmia   $r_ptr!,{r4-r11}
1520         stmia   $r_ptr!,{r4-r11}
1521         b       .Ladd_done
1522
1523 .align  4
1524 .Ladd_proceed:
1525         add     $a_ptr,sp,#$R
1526         add     $b_ptr,sp,#$R
1527         add     $r_ptr,sp,#$Rsqr
1528         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Rsqr, R);
1529
1530         add     $a_ptr,sp,#$H
1531         add     $b_ptr,sp,#$in1_z
1532         add     $r_ptr,sp,#$res_z
1533         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_z, H, in1_z);
1534
1535         add     $a_ptr,sp,#$H
1536         add     $b_ptr,sp,#$H
1537         add     $r_ptr,sp,#$Hsqr
1538         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Hsqr, H);
1539
1540         add     $a_ptr,sp,#$in2_z
1541         add     $b_ptr,sp,#$res_z
1542         add     $r_ptr,sp,#$res_z
1543         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_z, res_z, in2_z);
1544
1545         add     $a_ptr,sp,#$H
1546         add     $b_ptr,sp,#$Hsqr
1547         add     $r_ptr,sp,#$Hcub
1548         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(Hcub, Hsqr, H);
1549
1550         add     $a_ptr,sp,#$Hsqr
1551         add     $b_ptr,sp,#$U1
1552         add     $r_ptr,sp,#$U2
1553         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U2, U1, Hsqr);
1554
1555         add     $r_ptr,sp,#$Hsqr
1556         bl      __ecp_nistz256_add_self @ p256_mul_by_2(Hsqr, U2);
1557
1558         add     $b_ptr,sp,#$Rsqr
1559         add     $r_ptr,sp,#$res_x
1560         bl      __ecp_nistz256_sub_morf @ p256_sub(res_x, Rsqr, Hsqr);
1561
1562         add     $b_ptr,sp,#$Hcub
1563         bl      __ecp_nistz256_sub_from @  p256_sub(res_x, res_x, Hcub);
1564
1565         add     $b_ptr,sp,#$U2
1566         add     $r_ptr,sp,#$res_y
1567         bl      __ecp_nistz256_sub_morf @ p256_sub(res_y, U2, res_x);
1568
1569         add     $a_ptr,sp,#$Hcub
1570         add     $b_ptr,sp,#$S1
1571         add     $r_ptr,sp,#$S2
1572         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, S1, Hcub);
1573
1574         add     $a_ptr,sp,#$R
1575         add     $b_ptr,sp,#$res_y
1576         add     $r_ptr,sp,#$res_y
1577         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_y, res_y, R);
1578
1579         add     $b_ptr,sp,#$S2
1580         bl      __ecp_nistz256_sub_from @ p256_sub(res_y, res_y, S2);
1581
1582         ldr     r11,[sp,#32*18+4]       @ !in1intfy
1583         ldr     r12,[sp,#32*18+8]       @ !in2intfy
1584         add     r1,sp,#$res_x
1585         add     r2,sp,#$in2_x
1586         and     r10,r11,r12
1587         mvn     r11,r11
1588         add     r3,sp,#$in1_x
1589         and     r11,r11,r12
1590         mvn     r12,r12
1591         ldr     $r_ptr,[sp,#32*18]
1592 ___
1593 for($i=0;$i<96;$i+=8) {                 # conditional moves
1594 $code.=<<___;
1595         ldmia   r1!,{r4-r5}             @ res_x
1596         ldmia   r2!,{r6-r7}             @ in2_x
1597         ldmia   r3!,{r8-r9}             @ in1_x
1598         and     r4,r4,r10
1599         and     r5,r5,r10
1600         and     r6,r6,r11
1601         and     r7,r7,r11
1602         and     r8,r8,r12
1603         and     r9,r9,r12
1604         orr     r4,r4,r6
1605         orr     r5,r5,r7
1606         orr     r4,r4,r8
1607         orr     r5,r5,r9
1608         stmia   $r_ptr!,{r4-r5}
1609 ___
1610 }
1611 $code.=<<___;
1612 .Ladd_done:
1613         add     sp,sp,#32*18+16         @ +16 means "skip even over saved r0-r3"
1614 #if __ARM_ARCH__>=5 || defined(__thumb__)
1615         ldmia   sp!,{r4-r12,pc}
1616 #else
1617         ldmia   sp!,{r4-r12,lr}
1618         bx      lr                      @ interoperable with Thumb ISA:-)
1619 #endif
1620 .size   ecp_nistz256_point_add,.-ecp_nistz256_point_add
1621 ___
1622 }
1623
1624 ########################################################################
1625 # void ecp_nistz256_point_add_affine(P256_POINT *out,const P256_POINT *in1,
1626 #                                    const P256_POINT_AFFINE *in2);
1627 {
1628 my ($res_x,$res_y,$res_z,
1629     $in1_x,$in1_y,$in1_z,
1630     $in2_x,$in2_y,
1631     $U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr)=map(32*$_,(0..14));
1632 my $Z1sqr = $S2;
1633 # above map() describes stack layout with 18 temporary
1634 # 256-bit vectors on top. Then note that we push
1635 # starting from r0, which means that we have copy of
1636 # input arguments just below these temporary vectors.
1637 # We use two of them for !in1infty, !in2intfy.
1638
1639 my @ONE_mont=(1,0,0,-1,-1,-1,-2,0);
1640
1641 $code.=<<___;
1642 .globl  ecp_nistz256_point_add_affine
1643 .type   ecp_nistz256_point_add_affine,%function
1644 .align  5
1645 ecp_nistz256_point_add_affine:
1646         stmdb   sp!,{r0-r12,lr}         @ push from r0, unusual, but intentional
1647         sub     sp,sp,#32*15
1648
1649         ldmia   $a_ptr!,{r4-r11}        @ copy in1
1650         add     r3,sp,#$in1_x
1651         orr     r12,r4,r5
1652         orr     r12,r12,r6
1653         orr     r12,r12,r7
1654         orr     r12,r12,r8
1655         orr     r12,r12,r9
1656         orr     r12,r12,r10
1657         orr     r12,r12,r11
1658         stmia   r3!,{r4-r11}
1659         ldmia   $a_ptr!,{r4-r11}
1660         orr     r12,r12,r4
1661         orr     r12,r12,r5
1662         orr     r12,r12,r6
1663         orr     r12,r12,r7
1664         orr     r12,r12,r8
1665         orr     r12,r12,r9
1666         orr     r12,r12,r10
1667         orr     r12,r12,r11
1668         stmia   r3!,{r4-r11}
1669         ldmia   $a_ptr,{r4-r11}
1670         cmp     r12,#0
1671 #ifdef  __thumb2__
1672         it      ne
1673 #endif
1674         movne   r12,#-1
1675         stmia   r3,{r4-r11}
1676         str     r12,[sp,#32*15+4]       @ !in1infty
1677
1678         ldmia   $b_ptr!,{r4-r11}        @ copy in2
1679         add     r3,sp,#$in2_x
1680         orr     r12,r4,r5
1681         orr     r12,r12,r6
1682         orr     r12,r12,r7
1683         orr     r12,r12,r8
1684         orr     r12,r12,r9
1685         orr     r12,r12,r10
1686         orr     r12,r12,r11
1687         stmia   r3!,{r4-r11}
1688         ldmia   $b_ptr!,{r4-r11}
1689         orr     r12,r12,r4
1690         orr     r12,r12,r5
1691         orr     r12,r12,r6
1692         orr     r12,r12,r7
1693         orr     r12,r12,r8
1694         orr     r12,r12,r9
1695         orr     r12,r12,r10
1696         orr     r12,r12,r11
1697         stmia   r3!,{r4-r11}
1698         cmp     r12,#0
1699 #ifdef  __thumb2__
1700         it      ne
1701 #endif
1702         movne   r12,#-1
1703         str     r12,[sp,#32*15+8]       @ !in2infty
1704
1705         add     $a_ptr,sp,#$in1_z
1706         add     $b_ptr,sp,#$in1_z
1707         add     $r_ptr,sp,#$Z1sqr
1708         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Z1sqr, in1_z);
1709
1710         add     $a_ptr,sp,#$Z1sqr
1711         add     $b_ptr,sp,#$in2_x
1712         add     $r_ptr,sp,#$U2
1713         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U2, Z1sqr, in2_x);
1714
1715         add     $b_ptr,sp,#$in1_x
1716         add     $r_ptr,sp,#$H
1717         bl      __ecp_nistz256_sub_from @ p256_sub(H, U2, in1_x);
1718
1719         add     $a_ptr,sp,#$Z1sqr
1720         add     $b_ptr,sp,#$in1_z
1721         add     $r_ptr,sp,#$S2
1722         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, Z1sqr, in1_z);
1723
1724         add     $a_ptr,sp,#$H
1725         add     $b_ptr,sp,#$in1_z
1726         add     $r_ptr,sp,#$res_z
1727         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_z, H, in1_z);
1728
1729         add     $a_ptr,sp,#$in2_y
1730         add     $b_ptr,sp,#$S2
1731         add     $r_ptr,sp,#$S2
1732         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, S2, in2_y);
1733
1734         add     $b_ptr,sp,#$in1_y
1735         add     $r_ptr,sp,#$R
1736         bl      __ecp_nistz256_sub_from @ p256_sub(R, S2, in1_y);
1737
1738         add     $a_ptr,sp,#$H
1739         add     $b_ptr,sp,#$H
1740         add     $r_ptr,sp,#$Hsqr
1741         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Hsqr, H);
1742
1743         add     $a_ptr,sp,#$R
1744         add     $b_ptr,sp,#$R
1745         add     $r_ptr,sp,#$Rsqr
1746         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Rsqr, R);
1747
1748         add     $a_ptr,sp,#$H
1749         add     $b_ptr,sp,#$Hsqr
1750         add     $r_ptr,sp,#$Hcub
1751         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(Hcub, Hsqr, H);
1752
1753         add     $a_ptr,sp,#$Hsqr
1754         add     $b_ptr,sp,#$in1_x
1755         add     $r_ptr,sp,#$U2
1756         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U2, in1_x, Hsqr);
1757
1758         add     $r_ptr,sp,#$Hsqr
1759         bl      __ecp_nistz256_add_self @ p256_mul_by_2(Hsqr, U2);
1760
1761         add     $b_ptr,sp,#$Rsqr
1762         add     $r_ptr,sp,#$res_x
1763         bl      __ecp_nistz256_sub_morf @ p256_sub(res_x, Rsqr, Hsqr);
1764
1765         add     $b_ptr,sp,#$Hcub
1766         bl      __ecp_nistz256_sub_from @  p256_sub(res_x, res_x, Hcub);
1767
1768         add     $b_ptr,sp,#$U2
1769         add     $r_ptr,sp,#$res_y
1770         bl      __ecp_nistz256_sub_morf @ p256_sub(res_y, U2, res_x);
1771
1772         add     $a_ptr,sp,#$Hcub
1773         add     $b_ptr,sp,#$in1_y
1774         add     $r_ptr,sp,#$S2
1775         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, in1_y, Hcub);
1776
1777         add     $a_ptr,sp,#$R
1778         add     $b_ptr,sp,#$res_y
1779         add     $r_ptr,sp,#$res_y
1780         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_y, res_y, R);
1781
1782         add     $b_ptr,sp,#$S2
1783         bl      __ecp_nistz256_sub_from @ p256_sub(res_y, res_y, S2);
1784
1785         ldr     r11,[sp,#32*15+4]       @ !in1intfy
1786         ldr     r12,[sp,#32*15+8]       @ !in2intfy
1787         add     r1,sp,#$res_x
1788         add     r2,sp,#$in2_x
1789         and     r10,r11,r12
1790         mvn     r11,r11
1791         add     r3,sp,#$in1_x
1792         and     r11,r11,r12
1793         mvn     r12,r12
1794         ldr     $r_ptr,[sp,#32*15]
1795 ___
1796 for($i=0;$i<64;$i+=8) {                 # conditional moves
1797 $code.=<<___;
1798         ldmia   r1!,{r4-r5}             @ res_x
1799         ldmia   r2!,{r6-r7}             @ in2_x
1800         ldmia   r3!,{r8-r9}             @ in1_x
1801         and     r4,r4,r10
1802         and     r5,r5,r10
1803         and     r6,r6,r11
1804         and     r7,r7,r11
1805         and     r8,r8,r12
1806         and     r9,r9,r12
1807         orr     r4,r4,r6
1808         orr     r5,r5,r7
1809         orr     r4,r4,r8
1810         orr     r5,r5,r9
1811         stmia   $r_ptr!,{r4-r5}
1812 ___
1813 }
1814 for(;$i<96;$i+=8) {
1815 my $j=($i-64)/4;
1816 $code.=<<___;
1817         ldmia   r1!,{r4-r5}             @ res_z
1818         ldmia   r3!,{r8-r9}             @ in1_z
1819         and     r4,r4,r10
1820         and     r5,r5,r10
1821         and     r6,r11,#@ONE_mont[$j]
1822         and     r7,r11,#@ONE_mont[$j+1]
1823         and     r8,r8,r12
1824         and     r9,r9,r12
1825         orr     r4,r4,r6
1826         orr     r5,r5,r7
1827         orr     r4,r4,r8
1828         orr     r5,r5,r9
1829         stmia   $r_ptr!,{r4-r5}
1830 ___
1831 }
1832 $code.=<<___;
1833         add     sp,sp,#32*15+16         @ +16 means "skip even over saved r0-r3"
1834 #if __ARM_ARCH__>=5 || !defined(__thumb__)
1835         ldmia   sp!,{r4-r12,pc}
1836 #else
1837         ldmia   sp!,{r4-r12,lr}
1838         bx      lr                      @ interoperable with Thumb ISA:-)
1839 #endif
1840 .size   ecp_nistz256_point_add_affine,.-ecp_nistz256_point_add_affine
1841 ___
1842 }                                       }}}
1843
1844 foreach (split("\n",$code)) {
1845         s/\`([^\`]*)\`/eval $1/geo;
1846
1847         s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
1848
1849         print $_,"\n";
1850 }
1851 close STDOUT;   # enforce flush