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