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