ec/asm/ecp_nistz256-*.pl: get corner case logic right.
[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__)
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 .Lpoint_double_shortcut:
1256         add     r3,sp,#$in_x
1257         ldmia   $a_ptr!,{r4-r11}        @ copy in_x
1258         stmia   r3,{r4-r11}
1259
1260         add     $r_ptr,sp,#$S
1261         bl      __ecp_nistz256_mul_by_2 @ p256_mul_by_2(S, in_y);
1262
1263         add     $b_ptr,$a_ptr,#32
1264         add     $a_ptr,$a_ptr,#32
1265         add     $r_ptr,sp,#$Zsqr
1266         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Zsqr, in_z);
1267
1268         add     $a_ptr,sp,#$S
1269         add     $b_ptr,sp,#$S
1270         add     $r_ptr,sp,#$S
1271         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(S, S);
1272
1273         ldr     $b_ptr,[sp,#32*5+4]
1274         add     $a_ptr,$b_ptr,#32
1275         add     $b_ptr,$b_ptr,#64
1276         add     $r_ptr,sp,#$tmp0
1277         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(tmp0, in_z, in_y);
1278
1279         ldr     $r_ptr,[sp,#32*5]
1280         add     $r_ptr,$r_ptr,#64
1281         bl      __ecp_nistz256_add_self @ p256_mul_by_2(res_z, tmp0);
1282
1283         add     $a_ptr,sp,#$in_x
1284         add     $b_ptr,sp,#$Zsqr
1285         add     $r_ptr,sp,#$M
1286         bl      __ecp_nistz256_add      @ p256_add(M, in_x, Zsqr);
1287
1288         add     $a_ptr,sp,#$in_x
1289         add     $b_ptr,sp,#$Zsqr
1290         add     $r_ptr,sp,#$Zsqr
1291         bl      __ecp_nistz256_sub      @ p256_sub(Zsqr, in_x, Zsqr);
1292
1293         add     $a_ptr,sp,#$S
1294         add     $b_ptr,sp,#$S
1295         add     $r_ptr,sp,#$tmp0
1296         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(tmp0, S);
1297
1298         add     $a_ptr,sp,#$Zsqr
1299         add     $b_ptr,sp,#$M
1300         add     $r_ptr,sp,#$M
1301         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(M, M, Zsqr);
1302
1303         ldr     $r_ptr,[sp,#32*5]
1304         add     $a_ptr,sp,#$tmp0
1305         add     $r_ptr,$r_ptr,#32
1306         bl      __ecp_nistz256_div_by_2 @ p256_div_by_2(res_y, tmp0);
1307
1308         add     $a_ptr,sp,#$M
1309         add     $r_ptr,sp,#$M
1310         bl      __ecp_nistz256_mul_by_3 @ p256_mul_by_3(M, M);
1311
1312         add     $a_ptr,sp,#$in_x
1313         add     $b_ptr,sp,#$S
1314         add     $r_ptr,sp,#$S
1315         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S, S, in_x);
1316
1317         add     $r_ptr,sp,#$tmp0
1318         bl      __ecp_nistz256_add_self @ p256_mul_by_2(tmp0, S);
1319
1320         ldr     $r_ptr,[sp,#32*5]
1321         add     $a_ptr,sp,#$M
1322         add     $b_ptr,sp,#$M
1323         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(res_x, M);
1324
1325         add     $b_ptr,sp,#$tmp0
1326         bl      __ecp_nistz256_sub_from @ p256_sub(res_x, res_x, tmp0);
1327
1328         add     $b_ptr,sp,#$S
1329         add     $r_ptr,sp,#$S
1330         bl      __ecp_nistz256_sub_morf @ p256_sub(S, S, res_x);
1331
1332         add     $a_ptr,sp,#$M
1333         add     $b_ptr,sp,#$S
1334         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S, S, M);
1335
1336         ldr     $r_ptr,[sp,#32*5]
1337         add     $b_ptr,$r_ptr,#32
1338         add     $r_ptr,$r_ptr,#32
1339         bl      __ecp_nistz256_sub_from @ p256_sub(res_y, S, res_y);
1340
1341         add     sp,sp,#32*5+16          @ +16 means "skip even over saved r0-r3"
1342 #if __ARM_ARCH__>=5 || !defined(__thumb__)
1343         ldmia   sp!,{r4-r12,pc}
1344 #else
1345         ldmia   sp!,{r4-r12,lr}
1346         bx      lr                      @ interoperable with Thumb ISA:-)
1347 #endif
1348 .size   ecp_nistz256_point_double,.-ecp_nistz256_point_double
1349 ___
1350 }
1351
1352 ########################################################################
1353 # void ecp_nistz256_point_add(P256_POINT *out,const P256_POINT *in1,
1354 #                             const P256_POINT *in2);
1355 {
1356 my ($res_x,$res_y,$res_z,
1357     $in1_x,$in1_y,$in1_z,
1358     $in2_x,$in2_y,$in2_z,
1359     $H,$Hsqr,$R,$Rsqr,$Hcub,
1360     $U1,$U2,$S1,$S2)=map(32*$_,(0..17));
1361 my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
1362 # above map() describes stack layout with 18 temporary
1363 # 256-bit vectors on top. Then note that we push
1364 # starting from r0, which means that we have copy of
1365 # input arguments just below these temporary vectors.
1366 # We use three of them for !in1infty, !in2intfy and
1367 # result of check for zero.
1368
1369 $code.=<<___;
1370 .globl  ecp_nistz256_point_add
1371 .type   ecp_nistz256_point_add,%function
1372 .align  5
1373 ecp_nistz256_point_add:
1374         stmdb   sp!,{r0-r12,lr}         @ push from r0, unusual, but intentional
1375         sub     sp,sp,#32*18+16
1376
1377         ldmia   $b_ptr!,{r4-r11}        @ copy in2
1378         add     r3,sp,#$in2_x
1379         orr     r12,r4,r5
1380         orr     r12,r12,r6
1381         orr     r12,r12,r7
1382         orr     r12,r12,r8
1383         orr     r12,r12,r9
1384         orr     r12,r12,r10
1385         orr     r12,r12,r11
1386         stmia   r3!,{r4-r11}
1387         ldmia   $b_ptr!,{r4-r11}
1388         orr     r12,r12,r4
1389         orr     r12,r12,r5
1390         orr     r12,r12,r6
1391         orr     r12,r12,r7
1392         orr     r12,r12,r8
1393         orr     r12,r12,r9
1394         orr     r12,r12,r10
1395         orr     r12,r12,r11
1396         stmia   r3!,{r4-r11}
1397         ldmia   $b_ptr,{r4-r11}
1398         cmp     r12,#0
1399 #ifdef  __thumb2__
1400         it      ne
1401 #endif
1402         movne   r12,#-1
1403         stmia   r3,{r4-r11}
1404         str     r12,[sp,#32*18+8]       @ !in2infty
1405
1406         ldmia   $a_ptr!,{r4-r11}        @ copy in1
1407         add     r3,sp,#$in1_x
1408         orr     r12,r4,r5
1409         orr     r12,r12,r6
1410         orr     r12,r12,r7
1411         orr     r12,r12,r8
1412         orr     r12,r12,r9
1413         orr     r12,r12,r10
1414         orr     r12,r12,r11
1415         stmia   r3!,{r4-r11}
1416         ldmia   $a_ptr!,{r4-r11}
1417         orr     r12,r12,r4
1418         orr     r12,r12,r5
1419         orr     r12,r12,r6
1420         orr     r12,r12,r7
1421         orr     r12,r12,r8
1422         orr     r12,r12,r9
1423         orr     r12,r12,r10
1424         orr     r12,r12,r11
1425         stmia   r3!,{r4-r11}
1426         ldmia   $a_ptr,{r4-r11}
1427         cmp     r12,#0
1428 #ifdef  __thumb2__
1429         it      ne
1430 #endif
1431         movne   r12,#-1
1432         stmia   r3,{r4-r11}
1433         str     r12,[sp,#32*18+4]       @ !in1infty
1434
1435         add     $a_ptr,sp,#$in2_z
1436         add     $b_ptr,sp,#$in2_z
1437         add     $r_ptr,sp,#$Z2sqr
1438         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Z2sqr, in2_z);
1439
1440         add     $a_ptr,sp,#$in1_z
1441         add     $b_ptr,sp,#$in1_z
1442         add     $r_ptr,sp,#$Z1sqr
1443         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Z1sqr, in1_z);
1444
1445         add     $a_ptr,sp,#$in2_z
1446         add     $b_ptr,sp,#$Z2sqr
1447         add     $r_ptr,sp,#$S1
1448         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S1, Z2sqr, in2_z);
1449
1450         add     $a_ptr,sp,#$in1_z
1451         add     $b_ptr,sp,#$Z1sqr
1452         add     $r_ptr,sp,#$S2
1453         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, Z1sqr, in1_z);
1454
1455         add     $a_ptr,sp,#$in1_y
1456         add     $b_ptr,sp,#$S1
1457         add     $r_ptr,sp,#$S1
1458         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S1, S1, in1_y);
1459
1460         add     $a_ptr,sp,#$in2_y
1461         add     $b_ptr,sp,#$S2
1462         add     $r_ptr,sp,#$S2
1463         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, S2, in2_y);
1464
1465         add     $b_ptr,sp,#$S1
1466         add     $r_ptr,sp,#$R
1467         bl      __ecp_nistz256_sub_from @ p256_sub(R, S2, S1);
1468
1469         orr     $a0,$a0,$a1             @ see if result is zero
1470         orr     $a2,$a2,$a3
1471         orr     $a4,$a4,$a5
1472         orr     $a0,$a0,$a2
1473         orr     $a4,$a4,$a6
1474         orr     $a0,$a0,$a7
1475          add    $a_ptr,sp,#$in1_x
1476         orr     $a0,$a0,$a4
1477          add    $b_ptr,sp,#$Z2sqr
1478         str     $a0,[sp,#32*18+12]
1479
1480         add     $r_ptr,sp,#$U1
1481         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U1, in1_x, Z2sqr);
1482
1483         add     $a_ptr,sp,#$in2_x
1484         add     $b_ptr,sp,#$Z1sqr
1485         add     $r_ptr,sp,#$U2
1486         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U2, in2_x, Z1sqr);
1487
1488         add     $b_ptr,sp,#$U1
1489         add     $r_ptr,sp,#$H
1490         bl      __ecp_nistz256_sub_from @ p256_sub(H, U2, U1);
1491
1492         orr     $a0,$a0,$a1             @ see if result is zero
1493         orr     $a2,$a2,$a3
1494         orr     $a4,$a4,$a5
1495         orr     $a0,$a0,$a2
1496         orr     $a4,$a4,$a6
1497         orr     $a0,$a0,$a7
1498         orrs    $a0,$a0,$a4
1499
1500         bne     .Ladd_proceed           @ is_equal(U1,U2)?
1501
1502         ldr     $t0,[sp,#32*18+4]
1503         ldr     $t1,[sp,#32*18+8]
1504         ldr     $t2,[sp,#32*18+12]
1505         tst     $t0,$t1
1506         beq     .Ladd_proceed           @ (in1infty || in2infty)?
1507         tst     $t2,$t2
1508         beq     .Ladd_double            @ is_equal(S1,S2)?
1509
1510         ldr     $r_ptr,[sp,#32*18+16]
1511         eor     r4,r4,r4
1512         eor     r5,r5,r5
1513         eor     r6,r6,r6
1514         eor     r7,r7,r7
1515         eor     r8,r8,r8
1516         eor     r9,r9,r9
1517         eor     r10,r10,r10
1518         eor     r11,r11,r11
1519         stmia   $r_ptr!,{r4-r11}
1520         stmia   $r_ptr!,{r4-r11}
1521         stmia   $r_ptr!,{r4-r11}
1522         b       .Ladd_done
1523
1524 .align  4
1525 .Ladd_double:
1526         ldr     $a_ptr,[sp,#32*18+20]
1527         add     sp,sp,#32*(18-5)+16     @ difference in frame sizes
1528         b       .Lpoint_double_shortcut
1529
1530 .align  4
1531 .Ladd_proceed:
1532         add     $a_ptr,sp,#$R
1533         add     $b_ptr,sp,#$R
1534         add     $r_ptr,sp,#$Rsqr
1535         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Rsqr, R);
1536
1537         add     $a_ptr,sp,#$H
1538         add     $b_ptr,sp,#$in1_z
1539         add     $r_ptr,sp,#$res_z
1540         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_z, H, in1_z);
1541
1542         add     $a_ptr,sp,#$H
1543         add     $b_ptr,sp,#$H
1544         add     $r_ptr,sp,#$Hsqr
1545         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Hsqr, H);
1546
1547         add     $a_ptr,sp,#$in2_z
1548         add     $b_ptr,sp,#$res_z
1549         add     $r_ptr,sp,#$res_z
1550         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_z, res_z, in2_z);
1551
1552         add     $a_ptr,sp,#$H
1553         add     $b_ptr,sp,#$Hsqr
1554         add     $r_ptr,sp,#$Hcub
1555         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(Hcub, Hsqr, H);
1556
1557         add     $a_ptr,sp,#$Hsqr
1558         add     $b_ptr,sp,#$U1
1559         add     $r_ptr,sp,#$U2
1560         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U2, U1, Hsqr);
1561
1562         add     $r_ptr,sp,#$Hsqr
1563         bl      __ecp_nistz256_add_self @ p256_mul_by_2(Hsqr, U2);
1564
1565         add     $b_ptr,sp,#$Rsqr
1566         add     $r_ptr,sp,#$res_x
1567         bl      __ecp_nistz256_sub_morf @ p256_sub(res_x, Rsqr, Hsqr);
1568
1569         add     $b_ptr,sp,#$Hcub
1570         bl      __ecp_nistz256_sub_from @  p256_sub(res_x, res_x, Hcub);
1571
1572         add     $b_ptr,sp,#$U2
1573         add     $r_ptr,sp,#$res_y
1574         bl      __ecp_nistz256_sub_morf @ p256_sub(res_y, U2, res_x);
1575
1576         add     $a_ptr,sp,#$Hcub
1577         add     $b_ptr,sp,#$S1
1578         add     $r_ptr,sp,#$S2
1579         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, S1, Hcub);
1580
1581         add     $a_ptr,sp,#$R
1582         add     $b_ptr,sp,#$res_y
1583         add     $r_ptr,sp,#$res_y
1584         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_y, res_y, R);
1585
1586         add     $b_ptr,sp,#$S2
1587         bl      __ecp_nistz256_sub_from @ p256_sub(res_y, res_y, S2);
1588
1589         ldr     r11,[sp,#32*18+4]       @ !in1intfy
1590         ldr     r12,[sp,#32*18+8]       @ !in2intfy
1591         add     r1,sp,#$res_x
1592         add     r2,sp,#$in2_x
1593         and     r10,r11,r12
1594         mvn     r11,r11
1595         add     r3,sp,#$in1_x
1596         and     r11,r11,r12
1597         mvn     r12,r12
1598         ldr     $r_ptr,[sp,#32*18+16]
1599 ___
1600 for($i=0;$i<96;$i+=8) {                 # conditional moves
1601 $code.=<<___;
1602         ldmia   r1!,{r4-r5}             @ res_x
1603         ldmia   r2!,{r6-r7}             @ in2_x
1604         ldmia   r3!,{r8-r9}             @ in1_x
1605         and     r4,r4,r10
1606         and     r5,r5,r10
1607         and     r6,r6,r11
1608         and     r7,r7,r11
1609         and     r8,r8,r12
1610         and     r9,r9,r12
1611         orr     r4,r4,r6
1612         orr     r5,r5,r7
1613         orr     r4,r4,r8
1614         orr     r5,r5,r9
1615         stmia   $r_ptr!,{r4-r5}
1616 ___
1617 }
1618 $code.=<<___;
1619 .Ladd_done:
1620         add     sp,sp,#32*18+16+16      @ +16 means "skip even over saved r0-r3"
1621 #if __ARM_ARCH__>=5 || defined(__thumb__)
1622         ldmia   sp!,{r4-r12,pc}
1623 #else
1624         ldmia   sp!,{r4-r12,lr}
1625         bx      lr                      @ interoperable with Thumb ISA:-)
1626 #endif
1627 .size   ecp_nistz256_point_add,.-ecp_nistz256_point_add
1628 ___
1629 }
1630
1631 ########################################################################
1632 # void ecp_nistz256_point_add_affine(P256_POINT *out,const P256_POINT *in1,
1633 #                                    const P256_POINT_AFFINE *in2);
1634 {
1635 my ($res_x,$res_y,$res_z,
1636     $in1_x,$in1_y,$in1_z,
1637     $in2_x,$in2_y,
1638     $U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr)=map(32*$_,(0..14));
1639 my $Z1sqr = $S2;
1640 # above map() describes stack layout with 18 temporary
1641 # 256-bit vectors on top. Then note that we push
1642 # starting from r0, which means that we have copy of
1643 # input arguments just below these temporary vectors.
1644 # We use two of them for !in1infty, !in2intfy.
1645
1646 my @ONE_mont=(1,0,0,-1,-1,-1,-2,0);
1647
1648 $code.=<<___;
1649 .globl  ecp_nistz256_point_add_affine
1650 .type   ecp_nistz256_point_add_affine,%function
1651 .align  5
1652 ecp_nistz256_point_add_affine:
1653         stmdb   sp!,{r0-r12,lr}         @ push from r0, unusual, but intentional
1654         sub     sp,sp,#32*15
1655
1656         ldmia   $a_ptr!,{r4-r11}        @ copy in1
1657         add     r3,sp,#$in1_x
1658         orr     r12,r4,r5
1659         orr     r12,r12,r6
1660         orr     r12,r12,r7
1661         orr     r12,r12,r8
1662         orr     r12,r12,r9
1663         orr     r12,r12,r10
1664         orr     r12,r12,r11
1665         stmia   r3!,{r4-r11}
1666         ldmia   $a_ptr!,{r4-r11}
1667         orr     r12,r12,r4
1668         orr     r12,r12,r5
1669         orr     r12,r12,r6
1670         orr     r12,r12,r7
1671         orr     r12,r12,r8
1672         orr     r12,r12,r9
1673         orr     r12,r12,r10
1674         orr     r12,r12,r11
1675         stmia   r3!,{r4-r11}
1676         ldmia   $a_ptr,{r4-r11}
1677         cmp     r12,#0
1678 #ifdef  __thumb2__
1679         it      ne
1680 #endif
1681         movne   r12,#-1
1682         stmia   r3,{r4-r11}
1683         str     r12,[sp,#32*15+4]       @ !in1infty
1684
1685         ldmia   $b_ptr!,{r4-r11}        @ copy in2
1686         add     r3,sp,#$in2_x
1687         orr     r12,r4,r5
1688         orr     r12,r12,r6
1689         orr     r12,r12,r7
1690         orr     r12,r12,r8
1691         orr     r12,r12,r9
1692         orr     r12,r12,r10
1693         orr     r12,r12,r11
1694         stmia   r3!,{r4-r11}
1695         ldmia   $b_ptr!,{r4-r11}
1696         orr     r12,r12,r4
1697         orr     r12,r12,r5
1698         orr     r12,r12,r6
1699         orr     r12,r12,r7
1700         orr     r12,r12,r8
1701         orr     r12,r12,r9
1702         orr     r12,r12,r10
1703         orr     r12,r12,r11
1704         stmia   r3!,{r4-r11}
1705         cmp     r12,#0
1706 #ifdef  __thumb2__
1707         it      ne
1708 #endif
1709         movne   r12,#-1
1710         str     r12,[sp,#32*15+8]       @ !in2infty
1711
1712         add     $a_ptr,sp,#$in1_z
1713         add     $b_ptr,sp,#$in1_z
1714         add     $r_ptr,sp,#$Z1sqr
1715         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Z1sqr, in1_z);
1716
1717         add     $a_ptr,sp,#$Z1sqr
1718         add     $b_ptr,sp,#$in2_x
1719         add     $r_ptr,sp,#$U2
1720         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U2, Z1sqr, in2_x);
1721
1722         add     $b_ptr,sp,#$in1_x
1723         add     $r_ptr,sp,#$H
1724         bl      __ecp_nistz256_sub_from @ p256_sub(H, U2, in1_x);
1725
1726         add     $a_ptr,sp,#$Z1sqr
1727         add     $b_ptr,sp,#$in1_z
1728         add     $r_ptr,sp,#$S2
1729         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, Z1sqr, in1_z);
1730
1731         add     $a_ptr,sp,#$H
1732         add     $b_ptr,sp,#$in1_z
1733         add     $r_ptr,sp,#$res_z
1734         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_z, H, in1_z);
1735
1736         add     $a_ptr,sp,#$in2_y
1737         add     $b_ptr,sp,#$S2
1738         add     $r_ptr,sp,#$S2
1739         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, S2, in2_y);
1740
1741         add     $b_ptr,sp,#$in1_y
1742         add     $r_ptr,sp,#$R
1743         bl      __ecp_nistz256_sub_from @ p256_sub(R, S2, in1_y);
1744
1745         add     $a_ptr,sp,#$H
1746         add     $b_ptr,sp,#$H
1747         add     $r_ptr,sp,#$Hsqr
1748         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Hsqr, H);
1749
1750         add     $a_ptr,sp,#$R
1751         add     $b_ptr,sp,#$R
1752         add     $r_ptr,sp,#$Rsqr
1753         bl      __ecp_nistz256_mul_mont @ p256_sqr_mont(Rsqr, R);
1754
1755         add     $a_ptr,sp,#$H
1756         add     $b_ptr,sp,#$Hsqr
1757         add     $r_ptr,sp,#$Hcub
1758         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(Hcub, Hsqr, H);
1759
1760         add     $a_ptr,sp,#$Hsqr
1761         add     $b_ptr,sp,#$in1_x
1762         add     $r_ptr,sp,#$U2
1763         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(U2, in1_x, Hsqr);
1764
1765         add     $r_ptr,sp,#$Hsqr
1766         bl      __ecp_nistz256_add_self @ p256_mul_by_2(Hsqr, U2);
1767
1768         add     $b_ptr,sp,#$Rsqr
1769         add     $r_ptr,sp,#$res_x
1770         bl      __ecp_nistz256_sub_morf @ p256_sub(res_x, Rsqr, Hsqr);
1771
1772         add     $b_ptr,sp,#$Hcub
1773         bl      __ecp_nistz256_sub_from @  p256_sub(res_x, res_x, Hcub);
1774
1775         add     $b_ptr,sp,#$U2
1776         add     $r_ptr,sp,#$res_y
1777         bl      __ecp_nistz256_sub_morf @ p256_sub(res_y, U2, res_x);
1778
1779         add     $a_ptr,sp,#$Hcub
1780         add     $b_ptr,sp,#$in1_y
1781         add     $r_ptr,sp,#$S2
1782         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(S2, in1_y, Hcub);
1783
1784         add     $a_ptr,sp,#$R
1785         add     $b_ptr,sp,#$res_y
1786         add     $r_ptr,sp,#$res_y
1787         bl      __ecp_nistz256_mul_mont @ p256_mul_mont(res_y, res_y, R);
1788
1789         add     $b_ptr,sp,#$S2
1790         bl      __ecp_nistz256_sub_from @ p256_sub(res_y, res_y, S2);
1791
1792         ldr     r11,[sp,#32*15+4]       @ !in1intfy
1793         ldr     r12,[sp,#32*15+8]       @ !in2intfy
1794         add     r1,sp,#$res_x
1795         add     r2,sp,#$in2_x
1796         and     r10,r11,r12
1797         mvn     r11,r11
1798         add     r3,sp,#$in1_x
1799         and     r11,r11,r12
1800         mvn     r12,r12
1801         ldr     $r_ptr,[sp,#32*15]
1802 ___
1803 for($i=0;$i<64;$i+=8) {                 # conditional moves
1804 $code.=<<___;
1805         ldmia   r1!,{r4-r5}             @ res_x
1806         ldmia   r2!,{r6-r7}             @ in2_x
1807         ldmia   r3!,{r8-r9}             @ in1_x
1808         and     r4,r4,r10
1809         and     r5,r5,r10
1810         and     r6,r6,r11
1811         and     r7,r7,r11
1812         and     r8,r8,r12
1813         and     r9,r9,r12
1814         orr     r4,r4,r6
1815         orr     r5,r5,r7
1816         orr     r4,r4,r8
1817         orr     r5,r5,r9
1818         stmia   $r_ptr!,{r4-r5}
1819 ___
1820 }
1821 for(;$i<96;$i+=8) {
1822 my $j=($i-64)/4;
1823 $code.=<<___;
1824         ldmia   r1!,{r4-r5}             @ res_z
1825         ldmia   r3!,{r8-r9}             @ in1_z
1826         and     r4,r4,r10
1827         and     r5,r5,r10
1828         and     r6,r11,#@ONE_mont[$j]
1829         and     r7,r11,#@ONE_mont[$j+1]
1830         and     r8,r8,r12
1831         and     r9,r9,r12
1832         orr     r4,r4,r6
1833         orr     r5,r5,r7
1834         orr     r4,r4,r8
1835         orr     r5,r5,r9
1836         stmia   $r_ptr!,{r4-r5}
1837 ___
1838 }
1839 $code.=<<___;
1840         add     sp,sp,#32*15+16         @ +16 means "skip even over saved r0-r3"
1841 #if __ARM_ARCH__>=5 || !defined(__thumb__)
1842         ldmia   sp!,{r4-r12,pc}
1843 #else
1844         ldmia   sp!,{r4-r12,lr}
1845         bx      lr                      @ interoperable with Thumb ISA:-)
1846 #endif
1847 .size   ecp_nistz256_point_add_affine,.-ecp_nistz256_point_add_affine
1848 ___
1849 }                                       }}}
1850
1851 foreach (split("\n",$code)) {
1852         s/\`([^\`]*)\`/eval $1/geo;
1853
1854         s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
1855
1856         print $_,"\n";
1857 }
1858 close STDOUT;   # enforce flush