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