ec/asm/ecp_nistz256-*.pl: get corner case logic right.
[openssl.git] / crypto / ec / asm / ecp_nistz256-armv8.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 ARMv8.
11 #
12 # February 2015.
13 #
14 # Original ECP_NISTZ256 submission targeting x86_64 is detailed in
15 # http://eprint.iacr.org/2013/816.
16 #
17 #                       with/without -DECP_NISTZ256_ASM
18 # Apple A7              +120-360%
19 # Cortex-A53            +120-400%
20 # Cortex-A57            +120-350%
21 # X-Gene                +200-330%
22 # Denver                +140-400%
23 #
24 # Ranges denote minimum and maximum improvement coefficients depending
25 # on benchmark. Lower coefficients are for ECDSA sign, server-side
26 # operation. Keep in mind that +400% means 5x improvement.
27
28 $flavour = shift;
29 while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
30
31 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
32 ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
33 ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
34 die "can't locate arm-xlate.pl";
35
36 open OUT,"| \"$^X\" $xlate $flavour $output";
37 *STDOUT=*OUT;
38
39 {
40 my ($rp,$ap,$bp,$bi,$a0,$a1,$a2,$a3,$t0,$t1,$t2,$t3,$poly1,$poly3,
41     $acc0,$acc1,$acc2,$acc3,$acc4,$acc5) =
42     map("x$_",(0..17,19,20));
43
44 my ($acc6,$acc7)=($ap,$bp);     # used in __ecp_nistz256_sqr_mont
45
46 $code.=<<___;
47 #include "arm_arch.h"
48
49 .text
50 ___
51 ########################################################################
52 # Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
53 #
54 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
55 open TABLE,"<ecp_nistz256_table.c"              or
56 open TABLE,"<${dir}../ecp_nistz256_table.c"     or
57 die "failed to open ecp_nistz256_table.c:",$!;
58
59 use integer;
60
61 foreach(<TABLE>) {
62         s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
63 }
64 close TABLE;
65
66 # See ecp_nistz256_table.c for explanation for why it's 64*16*37.
67 # 64*16*37-1 is because $#arr returns last valid index or @arr, not
68 # amount of elements.
69 die "insane number of elements" if ($#arr != 64*16*37-1);
70
71 $code.=<<___;
72 .globl  ecp_nistz256_precomputed
73 .type   ecp_nistz256_precomputed,%object
74 .align  12
75 ecp_nistz256_precomputed:
76 ___
77 ########################################################################
78 # this conversion smashes P256_POINT_AFFINE by individual bytes with
79 # 64 byte interval, similar to
80 #       1111222233334444
81 #       1234123412341234
82 for(1..37) {
83         @tbl = splice(@arr,0,64*16);
84         for($i=0;$i<64;$i++) {
85                 undef @line;
86                 for($j=0;$j<64;$j++) {
87                         push @line,(@tbl[$j*16+$i/4]>>(($i%4)*8))&0xff;
88                 }
89                 $code.=".byte\t";
90                 $code.=join(',',map { sprintf "0x%02x",$_} @line);
91                 $code.="\n";
92         }
93 }
94 $code.=<<___;
95 .size   ecp_nistz256_precomputed,.-ecp_nistz256_precomputed
96 .align  5
97 .Lpoly:
98 .quad   0xffffffffffffffff,0x00000000ffffffff,0x0000000000000000,0xffffffff00000001
99 .LRR:   // 2^512 mod P precomputed for NIST P256 polynomial
100 .quad   0x0000000000000003,0xfffffffbffffffff,0xfffffffffffffffe,0x00000004fffffffd
101 .Lone_mont:
102 .quad   0x0000000000000001,0xffffffff00000000,0xffffffffffffffff,0x00000000fffffffe
103 .Lone:
104 .quad   1,0,0,0
105 .asciz  "ECP_NISTZ256 for ARMv8, CRYPTOGAMS by <appro\@openssl.org>"
106
107 // void ecp_nistz256_to_mont(BN_ULONG x0[4],const BN_ULONG x1[4]);
108 .globl  ecp_nistz256_to_mont
109 .type   ecp_nistz256_to_mont,%function
110 .align  6
111 ecp_nistz256_to_mont:
112         stp     x29,x30,[sp,#-32]!
113         add     x29,sp,#0
114         stp     x19,x20,[sp,#16]
115
116         ldr     $bi,.LRR                // bp[0]
117         ldp     $a0,$a1,[$ap]
118         ldp     $a2,$a3,[$ap,#16]
119         ldr     $poly1,.Lpoly+8
120         ldr     $poly3,.Lpoly+24
121         adr     $bp,.LRR                // &bp[0]
122
123         bl      __ecp_nistz256_mul_mont
124
125         ldp     x19,x20,[sp,#16]
126         ldp     x29,x30,[sp],#32
127         ret
128 .size   ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
129
130 // void ecp_nistz256_from_mont(BN_ULONG x0[4],const BN_ULONG x1[4]);
131 .globl  ecp_nistz256_from_mont
132 .type   ecp_nistz256_from_mont,%function
133 .align  4
134 ecp_nistz256_from_mont:
135         stp     x29,x30,[sp,#-32]!
136         add     x29,sp,#0
137         stp     x19,x20,[sp,#16]
138
139         mov     $bi,#1                  // bp[0]
140         ldp     $a0,$a1,[$ap]
141         ldp     $a2,$a3,[$ap,#16]
142         ldr     $poly1,.Lpoly+8
143         ldr     $poly3,.Lpoly+24
144         adr     $bp,.Lone               // &bp[0]
145
146         bl      __ecp_nistz256_mul_mont
147
148         ldp     x19,x20,[sp,#16]
149         ldp     x29,x30,[sp],#32
150         ret
151 .size   ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
152
153 // void ecp_nistz256_mul_mont(BN_ULONG x0[4],const BN_ULONG x1[4],
154 //                                           const BN_ULONG x2[4]);
155 .globl  ecp_nistz256_mul_mont
156 .type   ecp_nistz256_mul_mont,%function
157 .align  4
158 ecp_nistz256_mul_mont:
159         stp     x29,x30,[sp,#-32]!
160         add     x29,sp,#0
161         stp     x19,x20,[sp,#16]
162
163         ldr     $bi,[$bp]               // bp[0]
164         ldp     $a0,$a1,[$ap]
165         ldp     $a2,$a3,[$ap,#16]
166         ldr     $poly1,.Lpoly+8
167         ldr     $poly3,.Lpoly+24
168
169         bl      __ecp_nistz256_mul_mont
170
171         ldp     x19,x20,[sp,#16]
172         ldp     x29,x30,[sp],#32
173         ret
174 .size   ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
175
176 // void ecp_nistz256_sqr_mont(BN_ULONG x0[4],const BN_ULONG x1[4]);
177 .globl  ecp_nistz256_sqr_mont
178 .type   ecp_nistz256_sqr_mont,%function
179 .align  4
180 ecp_nistz256_sqr_mont:
181         stp     x29,x30,[sp,#-32]!
182         add     x29,sp,#0
183         stp     x19,x20,[sp,#16]
184
185         ldp     $a0,$a1,[$ap]
186         ldp     $a2,$a3,[$ap,#16]
187         ldr     $poly1,.Lpoly+8
188         ldr     $poly3,.Lpoly+24
189
190         bl      __ecp_nistz256_sqr_mont
191
192         ldp     x19,x20,[sp,#16]
193         ldp     x29,x30,[sp],#32
194         ret
195 .size   ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
196
197 // void ecp_nistz256_add(BN_ULONG x0[4],const BN_ULONG x1[4],
198 //                                      const BN_ULONG x2[4]);
199 .globl  ecp_nistz256_add
200 .type   ecp_nistz256_add,%function
201 .align  4
202 ecp_nistz256_add:
203         stp     x29,x30,[sp,#-16]!
204         add     x29,sp,#0
205
206         ldp     $acc0,$acc1,[$ap]
207         ldp     $t0,$t1,[$bp]
208         ldp     $acc2,$acc3,[$ap,#16]
209         ldp     $t2,$t3,[$bp,#16]
210         ldr     $poly1,.Lpoly+8
211         ldr     $poly3,.Lpoly+24
212
213         bl      __ecp_nistz256_add
214
215         ldp     x29,x30,[sp],#16
216         ret
217 .size   ecp_nistz256_add,.-ecp_nistz256_add
218
219 // void ecp_nistz256_div_by_2(BN_ULONG x0[4],const BN_ULONG x1[4]);
220 .globl  ecp_nistz256_div_by_2
221 .type   ecp_nistz256_div_by_2,%function
222 .align  4
223 ecp_nistz256_div_by_2:
224         stp     x29,x30,[sp,#-16]!
225         add     x29,sp,#0
226
227         ldp     $acc0,$acc1,[$ap]
228         ldp     $acc2,$acc3,[$ap,#16]
229         ldr     $poly1,.Lpoly+8
230         ldr     $poly3,.Lpoly+24
231
232         bl      __ecp_nistz256_div_by_2
233
234         ldp     x29,x30,[sp],#16
235         ret
236 .size   ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
237
238 // void ecp_nistz256_mul_by_2(BN_ULONG x0[4],const BN_ULONG x1[4]);
239 .globl  ecp_nistz256_mul_by_2
240 .type   ecp_nistz256_mul_by_2,%function
241 .align  4
242 ecp_nistz256_mul_by_2:
243         stp     x29,x30,[sp,#-16]!
244         add     x29,sp,#0
245
246         ldp     $acc0,$acc1,[$ap]
247         ldp     $acc2,$acc3,[$ap,#16]
248         ldr     $poly1,.Lpoly+8
249         ldr     $poly3,.Lpoly+24
250         mov     $t0,$acc0
251         mov     $t1,$acc1
252         mov     $t2,$acc2
253         mov     $t3,$acc3
254
255         bl      __ecp_nistz256_add      // ret = a+a    // 2*a
256
257         ldp     x29,x30,[sp],#16
258         ret
259 .size   ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
260
261 // void ecp_nistz256_mul_by_3(BN_ULONG x0[4],const BN_ULONG x1[4]);
262 .globl  ecp_nistz256_mul_by_3
263 .type   ecp_nistz256_mul_by_3,%function
264 .align  4
265 ecp_nistz256_mul_by_3:
266         stp     x29,x30,[sp,#-16]!
267         add     x29,sp,#0
268
269         ldp     $acc0,$acc1,[$ap]
270         ldp     $acc2,$acc3,[$ap,#16]
271         ldr     $poly1,.Lpoly+8
272         ldr     $poly3,.Lpoly+24
273         mov     $t0,$acc0
274         mov     $t1,$acc1
275         mov     $t2,$acc2
276         mov     $t3,$acc3
277         mov     $a0,$acc0
278         mov     $a1,$acc1
279         mov     $a2,$acc2
280         mov     $a3,$acc3
281
282         bl      __ecp_nistz256_add      // ret = a+a    // 2*a
283
284         mov     $t0,$a0
285         mov     $t1,$a1
286         mov     $t2,$a2
287         mov     $t3,$a3
288
289         bl      __ecp_nistz256_add      // ret += a     // 2*a+a=3*a
290
291         ldp     x29,x30,[sp],#16
292         ret
293 .size   ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
294
295 // void ecp_nistz256_sub(BN_ULONG x0[4],const BN_ULONG x1[4],
296 //                                      const BN_ULONG x2[4]);
297 .globl  ecp_nistz256_sub
298 .type   ecp_nistz256_sub,%function
299 .align  4
300 ecp_nistz256_sub:
301         stp     x29,x30,[sp,#-16]!
302         add     x29,sp,#0
303
304         ldp     $acc0,$acc1,[$ap]
305         ldp     $acc2,$acc3,[$ap,#16]
306         ldr     $poly1,.Lpoly+8
307         ldr     $poly3,.Lpoly+24
308
309         bl      __ecp_nistz256_sub_from
310
311         ldp     x29,x30,[sp],#16
312         ret
313 .size   ecp_nistz256_sub,.-ecp_nistz256_sub
314
315 // void ecp_nistz256_neg(BN_ULONG x0[4],const BN_ULONG x1[4]);
316 .globl  ecp_nistz256_neg
317 .type   ecp_nistz256_neg,%function
318 .align  4
319 ecp_nistz256_neg:
320         stp     x29,x30,[sp,#-16]!
321         add     x29,sp,#0
322
323         mov     $bp,$ap
324         mov     $acc0,xzr               // a = 0
325         mov     $acc1,xzr
326         mov     $acc2,xzr
327         mov     $acc3,xzr
328         ldr     $poly1,.Lpoly+8
329         ldr     $poly3,.Lpoly+24
330
331         bl      __ecp_nistz256_sub_from
332
333         ldp     x29,x30,[sp],#16
334         ret
335 .size   ecp_nistz256_neg,.-ecp_nistz256_neg
336
337 // note that __ecp_nistz256_mul_mont expects a[0-3] input pre-loaded
338 // to $a0-$a3 and b[0] - to $bi
339 .type   __ecp_nistz256_mul_mont,%function
340 .align  4
341 __ecp_nistz256_mul_mont:
342         mul     $acc0,$a0,$bi           // a[0]*b[0]
343         umulh   $t0,$a0,$bi
344
345         mul     $acc1,$a1,$bi           // a[1]*b[0]
346         umulh   $t1,$a1,$bi
347
348         mul     $acc2,$a2,$bi           // a[2]*b[0]
349         umulh   $t2,$a2,$bi
350
351         mul     $acc3,$a3,$bi           // a[3]*b[0]
352         umulh   $t3,$a3,$bi
353         ldr     $bi,[$bp,#8]            // b[1]
354
355         adds    $acc1,$acc1,$t0         // accumulate high parts of multiplication
356          lsl    $t0,$acc0,#32
357         adcs    $acc2,$acc2,$t1
358          lsr    $t1,$acc0,#32
359         adcs    $acc3,$acc3,$t2
360         adc     $acc4,xzr,$t3
361         mov     $acc5,xzr
362 ___
363 for($i=1;$i<4;$i++) {
364         # Reduction iteration is normally performed by accumulating
365         # result of multiplication of modulus by "magic" digit [and
366         # omitting least significant word, which is guaranteed to
367         # be 0], but thanks to special form of modulus and "magic"
368         # digit being equal to least significant word, it can be
369         # performed with additions and subtractions alone. Indeed:
370         #
371         #            ffff0001.00000000.0000ffff.ffffffff
372         # *                                     abcdefgh
373         # + xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.abcdefgh
374         #
375         # Now observing that ff..ff*x = (2^n-1)*x = 2^n*x-x, we
376         # rewrite above as:
377         #
378         #   xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.abcdefgh
379         # + abcdefgh.abcdefgh.0000abcd.efgh0000.00000000
380         # - 0000abcd.efgh0000.00000000.00000000.abcdefgh
381         #
382         # or marking redundant operations:
383         #
384         #   xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx.--------
385         # + abcdefgh.abcdefgh.0000abcd.efgh0000.--------
386         # - 0000abcd.efgh0000.--------.--------.--------
387
388 $code.=<<___;
389         subs    $t2,$acc0,$t0           // "*0xffff0001"
390         sbc     $t3,$acc0,$t1
391         adds    $acc0,$acc1,$t0         // +=acc[0]<<96 and omit acc[0]
392          mul    $t0,$a0,$bi             // lo(a[0]*b[i])
393         adcs    $acc1,$acc2,$t1
394          mul    $t1,$a1,$bi             // lo(a[1]*b[i])
395         adcs    $acc2,$acc3,$t2         // +=acc[0]*0xffff0001
396          mul    $t2,$a2,$bi             // lo(a[2]*b[i])
397         adcs    $acc3,$acc4,$t3
398          mul    $t3,$a3,$bi             // lo(a[3]*b[i])
399         adc     $acc4,$acc5,xzr
400
401         adds    $acc0,$acc0,$t0         // accumulate low parts of multiplication
402          umulh  $t0,$a0,$bi             // hi(a[0]*b[i])
403         adcs    $acc1,$acc1,$t1
404          umulh  $t1,$a1,$bi             // hi(a[1]*b[i])
405         adcs    $acc2,$acc2,$t2
406          umulh  $t2,$a2,$bi             // hi(a[2]*b[i])
407         adcs    $acc3,$acc3,$t3
408          umulh  $t3,$a3,$bi             // hi(a[3]*b[i])
409         adc     $acc4,$acc4,xzr
410 ___
411 $code.=<<___    if ($i<3);
412         ldr     $bi,[$bp,#8*($i+1)]     // b[$i+1]
413 ___
414 $code.=<<___;
415         adds    $acc1,$acc1,$t0         // accumulate high parts of multiplication
416          lsl    $t0,$acc0,#32
417         adcs    $acc2,$acc2,$t1
418          lsr    $t1,$acc0,#32
419         adcs    $acc3,$acc3,$t2
420         adcs    $acc4,$acc4,$t3
421         adc     $acc5,xzr,xzr
422 ___
423 }
424 $code.=<<___;
425         // last reduction
426         subs    $t2,$acc0,$t0           // "*0xffff0001"
427         sbc     $t3,$acc0,$t1
428         adds    $acc0,$acc1,$t0         // +=acc[0]<<96 and omit acc[0]
429         adcs    $acc1,$acc2,$t1
430         adcs    $acc2,$acc3,$t2         // +=acc[0]*0xffff0001
431         adcs    $acc3,$acc4,$t3
432         adc     $acc4,$acc5,xzr
433
434         adds    $t0,$acc0,#1            // subs $t0,$acc0,#-1 // tmp = ret-modulus
435         sbcs    $t1,$acc1,$poly1
436         sbcs    $t2,$acc2,xzr
437         sbcs    $t3,$acc3,$poly3
438         sbcs    xzr,$acc4,xzr           // did it borrow?
439
440         csel    $acc0,$acc0,$t0,lo      // ret = borrow ? ret : ret-modulus
441         csel    $acc1,$acc1,$t1,lo
442         csel    $acc2,$acc2,$t2,lo
443         stp     $acc0,$acc1,[$rp]
444         csel    $acc3,$acc3,$t3,lo
445         stp     $acc2,$acc3,[$rp,#16]
446
447         ret
448 .size   __ecp_nistz256_mul_mont,.-__ecp_nistz256_mul_mont
449
450 // note that __ecp_nistz256_sqr_mont expects a[0-3] input pre-loaded
451 // to $a0-$a3
452 .type   __ecp_nistz256_sqr_mont,%function
453 .align  4
454 __ecp_nistz256_sqr_mont:
455         //  |  |  |  |  |  |a1*a0|  |
456         //  |  |  |  |  |a2*a0|  |  |
457         //  |  |a3*a2|a3*a0|  |  |  |
458         //  |  |  |  |a2*a1|  |  |  |
459         //  |  |  |a3*a1|  |  |  |  |
460         // *|  |  |  |  |  |  |  | 2|
461         // +|a3*a3|a2*a2|a1*a1|a0*a0|
462         //  |--+--+--+--+--+--+--+--|
463         //  |A7|A6|A5|A4|A3|A2|A1|A0|, where Ax is $accx, i.e. follow $accx
464         //
465         //  "can't overflow" below mark carrying into high part of
466         //  multiplication result, which can't overflow, because it
467         //  can never be all ones.
468
469         mul     $acc1,$a1,$a0           // a[1]*a[0]
470         umulh   $t1,$a1,$a0
471         mul     $acc2,$a2,$a0           // a[2]*a[0]
472         umulh   $t2,$a2,$a0
473         mul     $acc3,$a3,$a0           // a[3]*a[0]
474         umulh   $acc4,$a3,$a0
475
476         adds    $acc2,$acc2,$t1         // accumulate high parts of multiplication
477          mul    $t0,$a2,$a1             // a[2]*a[1]
478          umulh  $t1,$a2,$a1
479         adcs    $acc3,$acc3,$t2
480          mul    $t2,$a3,$a1             // a[3]*a[1]
481          umulh  $t3,$a3,$a1
482         adc     $acc4,$acc4,xzr         // can't overflow
483
484         mul     $acc5,$a3,$a2           // a[3]*a[2]
485         umulh   $acc6,$a3,$a2
486
487         adds    $t1,$t1,$t2             // accumulate high parts of multiplication
488          mul    $acc0,$a0,$a0           // a[0]*a[0]
489         adc     $t2,$t3,xzr             // can't overflow
490
491         adds    $acc3,$acc3,$t0         // accumulate low parts of multiplication
492          umulh  $a0,$a0,$a0
493         adcs    $acc4,$acc4,$t1
494          mul    $t1,$a1,$a1             // a[1]*a[1]
495         adcs    $acc5,$acc5,$t2
496          umulh  $a1,$a1,$a1
497         adc     $acc6,$acc6,xzr         // can't overflow
498
499         adds    $acc1,$acc1,$acc1       // acc[1-6]*=2
500          mul    $t2,$a2,$a2             // a[2]*a[2]
501         adcs    $acc2,$acc2,$acc2
502          umulh  $a2,$a2,$a2
503         adcs    $acc3,$acc3,$acc3
504          mul    $t3,$a3,$a3             // a[3]*a[3]
505         adcs    $acc4,$acc4,$acc4
506          umulh  $a3,$a3,$a3
507         adcs    $acc5,$acc5,$acc5
508         adcs    $acc6,$acc6,$acc6
509         adc     $acc7,xzr,xzr
510
511         adds    $acc1,$acc1,$a0         // +a[i]*a[i]
512         adcs    $acc2,$acc2,$t1
513         adcs    $acc3,$acc3,$a1
514         adcs    $acc4,$acc4,$t2
515         adcs    $acc5,$acc5,$a2
516          lsl    $t0,$acc0,#32
517         adcs    $acc6,$acc6,$t3
518          lsr    $t1,$acc0,#32
519         adc     $acc7,$acc7,$a3
520 ___
521 for($i=0;$i<3;$i++) {                   # reductions, see commentary in
522                                         # multiplication for details
523 $code.=<<___;
524         subs    $t2,$acc0,$t0           // "*0xffff0001"
525         sbc     $t3,$acc0,$t1
526         adds    $acc0,$acc1,$t0         // +=acc[0]<<96 and omit acc[0]
527         adcs    $acc1,$acc2,$t1
528          lsl    $t0,$acc0,#32
529         adcs    $acc2,$acc3,$t2         // +=acc[0]*0xffff0001
530          lsr    $t1,$acc0,#32
531         adc     $acc3,$t3,xzr           // can't overflow
532 ___
533 }
534 $code.=<<___;
535         subs    $t2,$acc0,$t0           // "*0xffff0001"
536         sbc     $t3,$acc0,$t1
537         adds    $acc0,$acc1,$t0         // +=acc[0]<<96 and omit acc[0]
538         adcs    $acc1,$acc2,$t1
539         adcs    $acc2,$acc3,$t2         // +=acc[0]*0xffff0001
540         adc     $acc3,$t3,xzr           // can't overflow
541
542         adds    $acc0,$acc0,$acc4       // accumulate upper half
543         adcs    $acc1,$acc1,$acc5
544         adcs    $acc2,$acc2,$acc6
545         adcs    $acc3,$acc3,$acc7
546         adc     $acc4,xzr,xzr
547
548         adds    $t0,$acc0,#1            // subs $t0,$acc0,#-1 // tmp = ret-modulus
549         sbcs    $t1,$acc1,$poly1
550         sbcs    $t2,$acc2,xzr
551         sbcs    $t3,$acc3,$poly3
552         sbcs    xzr,$acc4,xzr           // did it borrow?
553
554         csel    $acc0,$acc0,$t0,lo      // ret = borrow ? ret : ret-modulus
555         csel    $acc1,$acc1,$t1,lo
556         csel    $acc2,$acc2,$t2,lo
557         stp     $acc0,$acc1,[$rp]
558         csel    $acc3,$acc3,$t3,lo
559         stp     $acc2,$acc3,[$rp,#16]
560
561         ret
562 .size   __ecp_nistz256_sqr_mont,.-__ecp_nistz256_sqr_mont
563
564 // Note that __ecp_nistz256_add expects both input vectors pre-loaded to
565 // $a0-$a3 and $t0-$t3. This is done because it's used in multiple
566 // contexts, e.g. in multiplication by 2 and 3...
567 .type   __ecp_nistz256_add,%function
568 .align  4
569 __ecp_nistz256_add:
570         adds    $acc0,$acc0,$t0         // ret = a+b
571         adcs    $acc1,$acc1,$t1
572         adcs    $acc2,$acc2,$t2
573         adcs    $acc3,$acc3,$t3
574         adc     $ap,xzr,xzr             // zap $ap
575
576         adds    $t0,$acc0,#1            // subs $t0,$a0,#-1 // tmp = ret-modulus
577         sbcs    $t1,$acc1,$poly1
578         sbcs    $t2,$acc2,xzr
579         sbc     $t3,$acc3,$poly3
580         cmp     $ap,xzr                 // did addition carry?
581
582         csel    $acc0,$acc0,$t0,eq      // ret = carry ? ret-modulus : ret
583         csel    $acc1,$acc1,$t1,eq
584         csel    $acc2,$acc2,$t2,eq
585         stp     $acc0,$acc1,[$rp]
586         csel    $acc3,$acc3,$t3,eq
587         stp     $acc2,$acc3,[$rp,#16]
588
589         ret
590 .size   __ecp_nistz256_add,.-__ecp_nistz256_add
591
592 .type   __ecp_nistz256_sub_from,%function
593 .align  4
594 __ecp_nistz256_sub_from:
595         ldp     $t0,$t1,[$bp]
596         ldp     $t2,$t3,[$bp,#16]
597         subs    $acc0,$acc0,$t0         // ret = a-b
598         sbcs    $acc1,$acc1,$t1
599         sbcs    $acc2,$acc2,$t2
600         sbcs    $acc3,$acc3,$t3
601         sbc     $ap,xzr,xzr             // zap $ap
602
603         subs    $t0,$acc0,#1            // adds $t0,$a0,#-1 // tmp = ret+modulus
604         adcs    $t1,$acc1,$poly1
605         adcs    $t2,$acc2,xzr
606         adc     $t3,$acc3,$poly3
607         cmp     $ap,xzr                 // did subtraction borrow?
608
609         csel    $acc0,$acc0,$t0,eq      // ret = borrow ? ret+modulus : ret
610         csel    $acc1,$acc1,$t1,eq
611         csel    $acc2,$acc2,$t2,eq
612         stp     $acc0,$acc1,[$rp]
613         csel    $acc3,$acc3,$t3,eq
614         stp     $acc2,$acc3,[$rp,#16]
615
616         ret
617 .size   __ecp_nistz256_sub_from,.-__ecp_nistz256_sub_from
618
619 .type   __ecp_nistz256_sub_morf,%function
620 .align  4
621 __ecp_nistz256_sub_morf:
622         ldp     $t0,$t1,[$bp]
623         ldp     $t2,$t3,[$bp,#16]
624         subs    $acc0,$t0,$acc0         // ret = b-a
625         sbcs    $acc1,$t1,$acc1
626         sbcs    $acc2,$t2,$acc2
627         sbcs    $acc3,$t3,$acc3
628         sbc     $ap,xzr,xzr             // zap $ap
629
630         subs    $t0,$acc0,#1            // adds $t0,$a0,#-1 // tmp = ret+modulus
631         adcs    $t1,$acc1,$poly1
632         adcs    $t2,$acc2,xzr
633         adc     $t3,$acc3,$poly3
634         cmp     $ap,xzr                 // did subtraction borrow?
635
636         csel    $acc0,$acc0,$t0,eq      // ret = borrow ? ret+modulus : ret
637         csel    $acc1,$acc1,$t1,eq
638         csel    $acc2,$acc2,$t2,eq
639         stp     $acc0,$acc1,[$rp]
640         csel    $acc3,$acc3,$t3,eq
641         stp     $acc2,$acc3,[$rp,#16]
642
643         ret
644 .size   __ecp_nistz256_sub_morf,.-__ecp_nistz256_sub_morf
645
646 .type   __ecp_nistz256_div_by_2,%function
647 .align  4
648 __ecp_nistz256_div_by_2:
649         subs    $t0,$acc0,#1            // adds $t0,$a0,#-1 // tmp = a+modulus
650         adcs    $t1,$acc1,$poly1
651         adcs    $t2,$acc2,xzr
652         adcs    $t3,$acc3,$poly3
653         adc     $ap,xzr,xzr             // zap $ap
654         tst     $acc0,#1                // is a even?
655
656         csel    $acc0,$acc0,$t0,eq      // ret = even ? a : a+modulus 
657         csel    $acc1,$acc1,$t1,eq
658         csel    $acc2,$acc2,$t2,eq
659         csel    $acc3,$acc3,$t3,eq
660         csel    $ap,xzr,$ap,eq
661
662         lsr     $acc0,$acc0,#1          // ret >>= 1
663         orr     $acc0,$acc0,$acc1,lsl#63
664         lsr     $acc1,$acc1,#1
665         orr     $acc1,$acc1,$acc2,lsl#63
666         lsr     $acc2,$acc2,#1
667         orr     $acc2,$acc2,$acc3,lsl#63
668         lsr     $acc3,$acc3,#1
669         stp     $acc0,$acc1,[$rp]
670         orr     $acc3,$acc3,$ap,lsl#63
671         stp     $acc2,$acc3,[$rp,#16]
672
673         ret
674 .size   __ecp_nistz256_div_by_2,.-__ecp_nistz256_div_by_2
675 ___
676 ########################################################################
677 # following subroutines are "literal" implemetation of those found in
678 # ecp_nistz256.c
679 #
680 ########################################################################
681 # void ecp_nistz256_point_double(P256_POINT *out,const P256_POINT *inp);
682 #
683 {
684 my ($S,$M,$Zsqr,$tmp0)=map(32*$_,(0..3));
685 # above map() describes stack layout with 4 temporary
686 # 256-bit vectors on top.
687 my ($rp_real,$ap_real) = map("x$_",(21,22));
688
689 $code.=<<___;
690 .globl  ecp_nistz256_point_double
691 .type   ecp_nistz256_point_double,%function
692 .align  5
693 ecp_nistz256_point_double:
694         stp     x29,x30,[sp,#-80]!
695         add     x29,sp,#0
696         stp     x19,x20,[sp,#16]
697         stp     x21,x22,[sp,#32]
698         sub     sp,sp,#32*4
699
700 .Ldouble_shortcut:
701         ldp     $acc0,$acc1,[$ap,#32]
702          mov    $rp_real,$rp
703         ldp     $acc2,$acc3,[$ap,#48]
704          mov    $ap_real,$ap
705          ldr    $poly1,.Lpoly+8
706         mov     $t0,$acc0
707          ldr    $poly3,.Lpoly+24
708         mov     $t1,$acc1
709          ldp    $a0,$a1,[$ap_real,#64]  // forward load for p256_sqr_mont
710         mov     $t2,$acc2
711         mov     $t3,$acc3
712          ldp    $a2,$a3,[$ap_real,#64+16]
713         add     $rp,sp,#$S
714         bl      __ecp_nistz256_add      // p256_mul_by_2(S, in_y);
715
716         add     $rp,sp,#$Zsqr
717         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(Zsqr, in_z);
718
719         ldp     $t0,$t1,[$ap_real]
720         ldp     $t2,$t3,[$ap_real,#16]
721         mov     $a0,$acc0               // put Zsqr aside for p256_sub
722         mov     $a1,$acc1
723         mov     $a2,$acc2
724         mov     $a3,$acc3
725         add     $rp,sp,#$M
726         bl      __ecp_nistz256_add      // p256_add(M, Zsqr, in_x);
727
728         add     $bp,$ap_real,#0
729         mov     $acc0,$a0               // restore Zsqr
730         mov     $acc1,$a1
731          ldp    $a0,$a1,[sp,#$S]        // forward load for p256_sqr_mont
732         mov     $acc2,$a2
733         mov     $acc3,$a3
734          ldp    $a2,$a3,[sp,#$S+16]
735         add     $rp,sp,#$Zsqr
736         bl      __ecp_nistz256_sub_morf // p256_sub(Zsqr, in_x, Zsqr);
737
738         add     $rp,sp,#$S
739         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(S, S);
740
741         ldr     $bi,[$ap_real,#32]
742         ldp     $a0,$a1,[$ap_real,#64]
743         ldp     $a2,$a3,[$ap_real,#64+16]
744         add     $bp,$ap_real,#32
745         add     $rp,sp,#$tmp0
746         bl      __ecp_nistz256_mul_mont // p256_mul_mont(tmp0, in_z, in_y);
747
748         mov     $t0,$acc0
749         mov     $t1,$acc1
750          ldp    $a0,$a1,[sp,#$S]        // forward load for p256_sqr_mont
751         mov     $t2,$acc2
752         mov     $t3,$acc3
753          ldp    $a2,$a3,[sp,#$S+16]
754         add     $rp,$rp_real,#64
755         bl      __ecp_nistz256_add      // p256_mul_by_2(res_z, tmp0);
756
757         add     $rp,sp,#$tmp0
758         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(tmp0, S);
759
760          ldr    $bi,[sp,#$Zsqr]         // forward load for p256_mul_mont
761          ldp    $a0,$a1,[sp,#$M]
762          ldp    $a2,$a3,[sp,#$M+16]
763         add     $rp,$rp_real,#32
764         bl      __ecp_nistz256_div_by_2 // p256_div_by_2(res_y, tmp0);
765
766         add     $bp,sp,#$Zsqr
767         add     $rp,sp,#$M
768         bl      __ecp_nistz256_mul_mont // p256_mul_mont(M, M, Zsqr);
769
770         mov     $t0,$acc0               // duplicate M
771         mov     $t1,$acc1
772         mov     $t2,$acc2
773         mov     $t3,$acc3
774         mov     $a0,$acc0               // put M aside
775         mov     $a1,$acc1
776         mov     $a2,$acc2
777         mov     $a3,$acc3
778         add     $rp,sp,#$M
779         bl      __ecp_nistz256_add
780         mov     $t0,$a0                 // restore M
781         mov     $t1,$a1
782          ldr    $bi,[$ap_real]          // forward load for p256_mul_mont
783         mov     $t2,$a2
784          ldp    $a0,$a1,[sp,#$S]
785         mov     $t3,$a3
786          ldp    $a2,$a3,[sp,#$S+16]
787         bl      __ecp_nistz256_add      // p256_mul_by_3(M, M);
788
789         add     $bp,$ap_real,#0
790         add     $rp,sp,#$S
791         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S, S, in_x);
792
793         mov     $t0,$acc0
794         mov     $t1,$acc1
795          ldp    $a0,$a1,[sp,#$M]        // forward load for p256_sqr_mont
796         mov     $t2,$acc2
797         mov     $t3,$acc3
798          ldp    $a2,$a3,[sp,#$M+16]
799         add     $rp,sp,#$tmp0
800         bl      __ecp_nistz256_add      // p256_mul_by_2(tmp0, S);
801
802         add     $rp,$rp_real,#0
803         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(res_x, M);
804
805         add     $bp,sp,#$tmp0
806         bl      __ecp_nistz256_sub_from // p256_sub(res_x, res_x, tmp0);
807
808         add     $bp,sp,#$S
809         add     $rp,sp,#$S
810         bl      __ecp_nistz256_sub_morf // p256_sub(S, S, res_x);
811
812         ldr     $bi,[sp,#$M]
813         mov     $a0,$acc0               // copy S
814         mov     $a1,$acc1
815         mov     $a2,$acc2
816         mov     $a3,$acc3
817         add     $bp,sp,#$M
818         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S, S, M);
819
820         add     $bp,$rp_real,#32
821         add     $rp,$rp_real,#32
822         bl      __ecp_nistz256_sub_from // p256_sub(res_y, S, res_y);
823
824         add     sp,x29,#0               // destroy frame
825         ldp     x19,x20,[x29,#16]
826         ldp     x21,x22,[x29,#32]
827         ldp     x29,x30,[sp],#80
828         ret
829 .size   ecp_nistz256_point_double,.-ecp_nistz256_point_double
830 ___
831 }
832
833 ########################################################################
834 # void ecp_nistz256_point_add(P256_POINT *out,const P256_POINT *in1,
835 #                             const P256_POINT *in2);
836 {
837 my ($res_x,$res_y,$res_z,
838     $H,$Hsqr,$R,$Rsqr,$Hcub,
839     $U1,$U2,$S1,$S2)=map(32*$_,(0..11));
840 my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
841 # above map() describes stack layout with 12 temporary
842 # 256-bit vectors on top.
843 my ($rp_real,$ap_real,$bp_real,$in1infty,$in2infty,$temp)=map("x$_",(21..26));
844
845 $code.=<<___;
846 .globl  ecp_nistz256_point_add
847 .type   ecp_nistz256_point_add,%function
848 .align  5
849 ecp_nistz256_point_add:
850         stp     x29,x30,[sp,#-80]!
851         add     x29,sp,#0
852         stp     x19,x20,[sp,#16]
853         stp     x21,x22,[sp,#32]
854         stp     x23,x24,[sp,#48]
855         stp     x25,x26,[sp,#64]
856         sub     sp,sp,#32*12
857
858         ldp     $a0,$a1,[$bp]
859         ldp     $a2,$a3,[$bp,#16]
860         ldp     $t0,$t1,[$bp,#32]
861         ldp     $t2,$t3,[$bp,#48]
862          mov    $rp_real,$rp
863          mov    $ap_real,$ap
864          mov    $bp_real,$bp
865         orr     $a0,$a0,$a1
866         orr     $a2,$a2,$a3
867          ldp    $acc0,$acc1,[$ap]
868         orr     $t0,$t0,$t1
869         orr     $t2,$t2,$t3
870          ldp    $acc2,$acc3,[$ap,#16]
871         orr     $a0,$a0,$a2
872         orr     $t2,$t0,$t2
873          ldp    $t0,$t1,[$ap,#32]
874         orr     $in2infty,$a0,$t2
875         cmp     $in2infty,#0
876          ldp    $t2,$t3,[$ap,#48]
877         csetm   $in2infty,ne            // !in2infty
878
879          ldp    $a0,$a1,[$bp_real,#64]  // forward load for p256_sqr_mont
880         orr     $acc0,$acc0,$acc1
881         orr     $acc2,$acc2,$acc3
882          ldp    $a2,$a3,[$bp_real,#64+16]
883         orr     $t0,$t0,$t1
884         orr     $t2,$t2,$t3
885         orr     $acc0,$acc0,$acc2
886         orr     $t0,$t0,$t2
887         orr     $in1infty,$acc0,$t0
888         cmp     $in1infty,#0
889          ldr    $poly1,.Lpoly+8
890          ldr    $poly3,.Lpoly+24
891         csetm   $in1infty,ne            // !in1infty
892
893         add     $rp,sp,#$Z2sqr
894         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(Z2sqr, in2_z);
895
896         ldp     $a0,$a1,[$ap_real,#64]
897         ldp     $a2,$a3,[$ap_real,#64+16]
898         add     $rp,sp,#$Z1sqr
899         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(Z1sqr, in1_z);
900
901         ldr     $bi,[$bp_real,#64]
902         ldp     $a0,$a1,[sp,#$Z2sqr]
903         ldp     $a2,$a3,[sp,#$Z2sqr+16]
904         add     $bp,$bp_real,#64
905         add     $rp,sp,#$S1
906         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S1, Z2sqr, in2_z);
907
908         ldr     $bi,[$ap_real,#64]
909         ldp     $a0,$a1,[sp,#$Z1sqr]
910         ldp     $a2,$a3,[sp,#$Z1sqr+16]
911         add     $bp,$ap_real,#64
912         add     $rp,sp,#$S2
913         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S2, Z1sqr, in1_z);
914
915         ldr     $bi,[$ap_real,#32]
916         ldp     $a0,$a1,[sp,#$S1]
917         ldp     $a2,$a3,[sp,#$S1+16]
918         add     $bp,$ap_real,#32
919         add     $rp,sp,#$S1
920         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S1, S1, in1_y);
921
922         ldr     $bi,[$bp_real,#32]
923         ldp     $a0,$a1,[sp,#$S2]
924         ldp     $a2,$a3,[sp,#$S2+16]
925         add     $bp,$bp_real,#32
926         add     $rp,sp,#$S2
927         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S2, S2, in2_y);
928
929         add     $bp,sp,#$S1
930          ldr    $bi,[sp,#$Z2sqr]        // forward load for p256_mul_mont
931          ldp    $a0,$a1,[$ap_real]
932          ldp    $a2,$a3,[$ap_real,#16]
933         add     $rp,sp,#$R
934         bl      __ecp_nistz256_sub_from // p256_sub(R, S2, S1);
935
936         orr     $acc0,$acc0,$acc1       // see if result is zero
937         orr     $acc2,$acc2,$acc3
938         orr     $temp,$acc0,$acc2
939
940         add     $bp,sp,#$Z2sqr
941         add     $rp,sp,#$U1
942         bl      __ecp_nistz256_mul_mont // p256_mul_mont(U1, in1_x, Z2sqr);
943
944         ldr     $bi,[sp,#$Z1sqr]
945         ldp     $a0,$a1,[$bp_real]
946         ldp     $a2,$a3,[$bp_real,#16]
947         add     $bp,sp,#$Z1sqr
948         add     $rp,sp,#$U2
949         bl      __ecp_nistz256_mul_mont // p256_mul_mont(U2, in2_x, Z1sqr);
950
951         add     $bp,sp,#$U1
952          ldp    $a0,$a1,[sp,#$R]        // forward load for p256_sqr_mont
953          ldp    $a2,$a3,[sp,#$R+16]
954         add     $rp,sp,#$H
955         bl      __ecp_nistz256_sub_from // p256_sub(H, U2, U1);
956
957         orr     $acc0,$acc0,$acc1       // see if result is zero
958         orr     $acc2,$acc2,$acc3
959         orr     $acc0,$acc0,$acc2
960         tst     $acc0,$acc0
961         b.ne    .Ladd_proceed           // is_equal(U1,U2)?
962
963         tst     $in1infty,$in2infty
964         b.eq    .Ladd_proceed           // (in1infty || in2infty)?
965
966         tst     $temp,$temp
967         b.eq    .Ladd_double            // is_equal(S1,S2)?
968
969         eor     $a0,$a0,$a0
970         eor     $a1,$a1,$a1
971         stp     $a0,$a1,[$rp_real]
972         stp     $a0,$a1,[$rp_real,#16]
973         stp     $a0,$a1,[$rp_real,#32]
974         stp     $a0,$a1,[$rp_real,#48]
975         stp     $a0,$a1,[$rp_real,#64]
976         stp     $a0,$a1,[$rp_real,#80]
977         b       .Ladd_done
978
979 .align  4
980 .Ladd_double:
981         mov     $ap,$ap_real
982         mov     $rp,$rp_real
983         ldp     x23,x24,[x29,#48]
984         ldp     x25,x26,[x29,#64]
985         add     sp,sp,#32*(12-4)        // difference in stack frames
986         b       .Ldouble_shortcut
987
988 .align  4
989 .Ladd_proceed:
990         add     $rp,sp,#$Rsqr
991         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(Rsqr, R);
992
993         ldr     $bi,[$ap_real,#64]
994         ldp     $a0,$a1,[sp,#$H]
995         ldp     $a2,$a3,[sp,#$H+16]
996         add     $bp,$ap_real,#64
997         add     $rp,sp,#$res_z
998         bl      __ecp_nistz256_mul_mont // p256_mul_mont(res_z, H, in1_z);
999
1000         ldp     $a0,$a1,[sp,#$H]
1001         ldp     $a2,$a3,[sp,#$H+16]
1002         add     $rp,sp,#$Hsqr
1003         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(Hsqr, H);
1004
1005         ldr     $bi,[$bp_real,#64]
1006         ldp     $a0,$a1,[sp,#$res_z]
1007         ldp     $a2,$a3,[sp,#$res_z+16]
1008         add     $bp,$bp_real,#64
1009         add     $rp,sp,#$res_z
1010         bl      __ecp_nistz256_mul_mont // p256_mul_mont(res_z, res_z, in2_z);
1011
1012         ldr     $bi,[sp,#$H]
1013         ldp     $a0,$a1,[sp,#$Hsqr]
1014         ldp     $a2,$a3,[sp,#$Hsqr+16]
1015         add     $bp,sp,#$H
1016         add     $rp,sp,#$Hcub
1017         bl      __ecp_nistz256_mul_mont // p256_mul_mont(Hcub, Hsqr, H);
1018
1019         ldr     $bi,[sp,#$Hsqr]
1020         ldp     $a0,$a1,[sp,#$U1]
1021         ldp     $a2,$a3,[sp,#$U1+16]
1022         add     $bp,sp,#$Hsqr
1023         add     $rp,sp,#$U2
1024         bl      __ecp_nistz256_mul_mont // p256_mul_mont(U2, U1, Hsqr);
1025
1026         mov     $t0,$acc0
1027         mov     $t1,$acc1
1028         mov     $t2,$acc2
1029         mov     $t3,$acc3
1030         add     $rp,sp,#$Hsqr
1031         bl      __ecp_nistz256_add      // p256_mul_by_2(Hsqr, U2);
1032
1033         add     $bp,sp,#$Rsqr
1034         add     $rp,sp,#$res_x
1035         bl      __ecp_nistz256_sub_morf // p256_sub(res_x, Rsqr, Hsqr);
1036
1037         add     $bp,sp,#$Hcub
1038         bl      __ecp_nistz256_sub_from //  p256_sub(res_x, res_x, Hcub);
1039
1040         add     $bp,sp,#$U2
1041          ldr    $bi,[sp,#$Hcub]         // forward load for p256_mul_mont
1042          ldp    $a0,$a1,[sp,#$S1]
1043          ldp    $a2,$a3,[sp,#$S1+16]
1044         add     $rp,sp,#$res_y
1045         bl      __ecp_nistz256_sub_morf // p256_sub(res_y, U2, res_x);
1046
1047         add     $bp,sp,#$Hcub
1048         add     $rp,sp,#$S2
1049         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S2, S1, Hcub);
1050
1051         ldr     $bi,[sp,#$R]
1052         ldp     $a0,$a1,[sp,#$res_y]
1053         ldp     $a2,$a3,[sp,#$res_y+16]
1054         add     $bp,sp,#$R
1055         add     $rp,sp,#$res_y
1056         bl      __ecp_nistz256_mul_mont // p256_mul_mont(res_y, res_y, R);
1057
1058         add     $bp,sp,#$S2
1059         bl      __ecp_nistz256_sub_from // p256_sub(res_y, res_y, S2);
1060
1061         ldp     $a0,$a1,[sp,#$res_x]            // res
1062         ldp     $a2,$a3,[sp,#$res_x+16]
1063         ldp     $t0,$t1,[$bp_real]              // in2
1064         ldp     $t2,$t3,[$bp_real,#16]
1065 ___
1066 for($i=0;$i<64;$i+=32) {                # conditional moves
1067 $code.=<<___;
1068         ldp     $acc0,$acc1,[$ap_real,#$i]      // in1
1069         cmp     $in1infty,#0                    // !$in1intfy, remember?
1070         ldp     $acc2,$acc3,[$ap_real,#$i+16]
1071         csel    $t0,$a0,$t0,ne
1072         csel    $t1,$a1,$t1,ne
1073         ldp     $a0,$a1,[sp,#$res_x+$i+32]      // res
1074         csel    $t2,$a2,$t2,ne
1075         csel    $t3,$a3,$t3,ne
1076         cmp     $in2infty,#0                    // !$in2intfy, remember?
1077         ldp     $a2,$a3,[sp,#$res_x+$i+48]
1078         csel    $acc0,$t0,$acc0,ne
1079         csel    $acc1,$t1,$acc1,ne
1080         ldp     $t0,$t1,[$bp_real,#$i+32]       // in2
1081         csel    $acc2,$t2,$acc2,ne
1082         csel    $acc3,$t3,$acc3,ne
1083         ldp     $t2,$t3,[$bp_real,#$i+48]
1084         stp     $acc0,$acc1,[$rp_real,#$i]
1085         stp     $acc2,$acc3,[$rp_real,#$i+16]
1086 ___
1087 }
1088 $code.=<<___;
1089         ldp     $acc0,$acc1,[$ap_real,#$i]      // in1
1090         cmp     $in1infty,#0                    // !$in1intfy, remember?
1091         ldp     $acc2,$acc3,[$ap_real,#$i+16]
1092         csel    $t0,$a0,$t0,ne
1093         csel    $t1,$a1,$t1,ne
1094         csel    $t2,$a2,$t2,ne
1095         csel    $t3,$a3,$t3,ne
1096         cmp     $in2infty,#0                    // !$in2intfy, remember?
1097         csel    $acc0,$t0,$acc0,ne
1098         csel    $acc1,$t1,$acc1,ne
1099         csel    $acc2,$t2,$acc2,ne
1100         csel    $acc3,$t3,$acc3,ne
1101         stp     $acc0,$acc1,[$rp_real,#$i]
1102         stp     $acc2,$acc3,[$rp_real,#$i+16]
1103
1104 .Ladd_done:
1105         add     sp,x29,#0       // destroy frame
1106         ldp     x19,x20,[x29,#16]
1107         ldp     x21,x22,[x29,#32]
1108         ldp     x23,x24,[x29,#48]
1109         ldp     x25,x26,[x29,#64]
1110         ldp     x29,x30,[sp],#80
1111         ret
1112 .size   ecp_nistz256_point_add,.-ecp_nistz256_point_add
1113 ___
1114 }
1115
1116 ########################################################################
1117 # void ecp_nistz256_point_add_affine(P256_POINT *out,const P256_POINT *in1,
1118 #                                    const P256_POINT_AFFINE *in2);
1119 {
1120 my ($res_x,$res_y,$res_z,
1121     $U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr)=map(32*$_,(0..9));
1122 my $Z1sqr = $S2;
1123 # above map() describes stack layout with 10 temporary
1124 # 256-bit vectors on top.
1125 my ($rp_real,$ap_real,$bp_real,$in1infty,$in2infty,$temp)=map("x$_",(21..26));
1126
1127 $code.=<<___;
1128 .globl  ecp_nistz256_point_add_affine
1129 .type   ecp_nistz256_point_add_affine,%function
1130 .align  5
1131 ecp_nistz256_point_add_affine:
1132         stp     x29,x30,[sp,#-80]!
1133         add     x29,sp,#0
1134         stp     x19,x20,[sp,#16]
1135         stp     x21,x22,[sp,#32]
1136         stp     x23,x24,[sp,#48]
1137         stp     x25,x26,[sp,#64]
1138         sub     sp,sp,#32*10
1139
1140         mov     $rp_real,$rp
1141         mov     $ap_real,$ap
1142         mov     $bp_real,$bp
1143         ldr     $poly1,.Lpoly+8
1144         ldr     $poly3,.Lpoly+24
1145
1146         ldp     $a0,$a1,[$ap]
1147         ldp     $a2,$a3,[$ap,#16]
1148         ldp     $t0,$t1,[$ap,#32]
1149         ldp     $t2,$t3,[$ap,#48]
1150         orr     $a0,$a0,$a1
1151         orr     $a2,$a2,$a3
1152         orr     $t0,$t0,$t1
1153         orr     $t2,$t2,$t3
1154         orr     $a0,$a0,$a2
1155         orr     $t0,$t0,$t2
1156         orr     $in1infty,$a0,$t0
1157         cmp     $in1infty,#0
1158         csetm   $in1infty,ne            // !in1infty
1159
1160         ldp     $a0,$a1,[$bp]
1161         ldp     $a2,$a3,[$bp,#16]
1162         ldp     $t0,$t1,[$bp,#32]
1163         ldp     $t2,$t3,[$bp,#48]
1164         orr     $a0,$a0,$a1
1165         orr     $a2,$a2,$a3
1166         orr     $t0,$t0,$t1
1167         orr     $t2,$t2,$t3
1168         orr     $a0,$a0,$a2
1169         orr     $t0,$t0,$t2
1170         orr     $in2infty,$a0,$t0
1171         cmp     $in2infty,#0
1172         csetm   $in2infty,ne            // !in2infty
1173
1174         ldp     $a0,$a1,[$ap_real,#64]
1175         ldp     $a2,$a3,[$ap_real,#64+16]
1176         add     $rp,sp,#$Z1sqr
1177         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(Z1sqr, in1_z);
1178
1179         mov     $a0,$acc0
1180         mov     $a1,$acc1
1181         mov     $a2,$acc2
1182         mov     $a3,$acc3
1183         ldr     $bi,[$bp_real]
1184         add     $bp,$bp_real,#0
1185         add     $rp,sp,#$U2
1186         bl      __ecp_nistz256_mul_mont // p256_mul_mont(U2, Z1sqr, in2_x);
1187
1188         add     $bp,$ap_real,#0
1189          ldr    $bi,[$ap_real,#64]      // forward load for p256_mul_mont
1190          ldp    $a0,$a1,[sp,#$Z1sqr]
1191          ldp    $a2,$a3,[sp,#$Z1sqr+16]
1192         add     $rp,sp,#$H
1193         bl      __ecp_nistz256_sub_from // p256_sub(H, U2, in1_x);
1194
1195         add     $bp,$ap_real,#64
1196         add     $rp,sp,#$S2
1197         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S2, Z1sqr, in1_z);
1198
1199         ldr     $bi,[$ap_real,#64]
1200         ldp     $a0,$a1,[sp,#$H]
1201         ldp     $a2,$a3,[sp,#$H+16]
1202         add     $bp,$ap_real,#64
1203         add     $rp,sp,#$res_z
1204         bl      __ecp_nistz256_mul_mont // p256_mul_mont(res_z, H, in1_z);
1205
1206         ldr     $bi,[$bp_real,#32]
1207         ldp     $a0,$a1,[sp,#$S2]
1208         ldp     $a2,$a3,[sp,#$S2+16]
1209         add     $bp,$bp_real,#32
1210         add     $rp,sp,#$S2
1211         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S2, S2, in2_y);
1212
1213         add     $bp,$ap_real,#32
1214          ldp    $a0,$a1,[sp,#$H]        // forward load for p256_sqr_mont
1215          ldp    $a2,$a3,[sp,#$H+16]
1216         add     $rp,sp,#$R
1217         bl      __ecp_nistz256_sub_from // p256_sub(R, S2, in1_y);
1218
1219         add     $rp,sp,#$Hsqr
1220         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(Hsqr, H);
1221
1222         ldp     $a0,$a1,[sp,#$R]
1223         ldp     $a2,$a3,[sp,#$R+16]
1224         add     $rp,sp,#$Rsqr
1225         bl      __ecp_nistz256_sqr_mont // p256_sqr_mont(Rsqr, R);
1226
1227         ldr     $bi,[sp,#$H]
1228         ldp     $a0,$a1,[sp,#$Hsqr]
1229         ldp     $a2,$a3,[sp,#$Hsqr+16]
1230         add     $bp,sp,#$H
1231         add     $rp,sp,#$Hcub
1232         bl      __ecp_nistz256_mul_mont // p256_mul_mont(Hcub, Hsqr, H);
1233
1234         ldr     $bi,[$ap_real]
1235         ldp     $a0,$a1,[sp,#$Hsqr]
1236         ldp     $a2,$a3,[sp,#$Hsqr+16]
1237         add     $bp,$ap_real,#0
1238         add     $rp,sp,#$U2
1239         bl      __ecp_nistz256_mul_mont // p256_mul_mont(U2, in1_x, Hsqr);
1240
1241         mov     $t0,$acc0
1242         mov     $t1,$acc1
1243         mov     $t2,$acc2
1244         mov     $t3,$acc3
1245         add     $rp,sp,#$Hsqr
1246         bl      __ecp_nistz256_add      // p256_mul_by_2(Hsqr, U2);
1247
1248         add     $bp,sp,#$Rsqr
1249         add     $rp,sp,#$res_x
1250         bl      __ecp_nistz256_sub_morf // p256_sub(res_x, Rsqr, Hsqr);
1251
1252         add     $bp,sp,#$Hcub
1253         bl      __ecp_nistz256_sub_from //  p256_sub(res_x, res_x, Hcub);
1254
1255         add     $bp,sp,#$U2
1256          ldr    $bi,[$ap_real,#32]      // forward load for p256_mul_mont
1257          ldp    $a0,$a1,[sp,#$Hcub]
1258          ldp    $a2,$a3,[sp,#$Hcub+16]
1259         add     $rp,sp,#$res_y
1260         bl      __ecp_nistz256_sub_morf // p256_sub(res_y, U2, res_x);
1261
1262         add     $bp,$ap_real,#32
1263         add     $rp,sp,#$S2
1264         bl      __ecp_nistz256_mul_mont // p256_mul_mont(S2, in1_y, Hcub);
1265
1266         ldr     $bi,[sp,#$R]
1267         ldp     $a0,$a1,[sp,#$res_y]
1268         ldp     $a2,$a3,[sp,#$res_y+16]
1269         add     $bp,sp,#$R
1270         add     $rp,sp,#$res_y
1271         bl      __ecp_nistz256_mul_mont // p256_mul_mont(res_y, res_y, R);
1272
1273         add     $bp,sp,#$S2
1274         bl      __ecp_nistz256_sub_from // p256_sub(res_y, res_y, S2);
1275
1276         ldp     $a0,$a1,[sp,#$res_x]            // res
1277         ldp     $a2,$a3,[sp,#$res_x+16]
1278         ldp     $t0,$t1,[$bp_real]              // in2
1279         ldp     $t2,$t3,[$bp_real,#16]
1280 ___
1281 for($i=0;$i<64;$i+=32) {                # conditional moves
1282 $code.=<<___;
1283         ldp     $acc0,$acc1,[$ap_real,#$i]      // in1
1284         cmp     $in1infty,#0                    // !$in1intfy, remember?
1285         ldp     $acc2,$acc3,[$ap_real,#$i+16]
1286         csel    $t0,$a0,$t0,ne
1287         csel    $t1,$a1,$t1,ne
1288         ldp     $a0,$a1,[sp,#$res_x+$i+32]      // res
1289         csel    $t2,$a2,$t2,ne
1290         csel    $t3,$a3,$t3,ne
1291         cmp     $in2infty,#0                    // !$in2intfy, remember?
1292         ldp     $a2,$a3,[sp,#$res_x+$i+48]
1293         csel    $acc0,$t0,$acc0,ne
1294         csel    $acc1,$t1,$acc1,ne
1295         ldp     $t0,$t1,[$bp_real,#$i+32]       // in2
1296         csel    $acc2,$t2,$acc2,ne
1297         csel    $acc3,$t3,$acc3,ne
1298         ldp     $t2,$t3,[$bp_real,#$i+48]
1299         stp     $acc0,$acc1,[$rp_real,#$i]
1300         stp     $acc2,$acc3,[$rp_real,#$i+16]
1301 ___
1302 $code.=<<___    if ($i == 0);
1303         adr     $bp_real,.Lone_mont-64
1304 ___
1305 }
1306 $code.=<<___;
1307         ldp     $acc0,$acc1,[$ap_real,#$i]      // in1
1308         cmp     $in1infty,#0                    // !$in1intfy, remember?
1309         ldp     $acc2,$acc3,[$ap_real,#$i+16]
1310         csel    $t0,$a0,$t0,ne
1311         csel    $t1,$a1,$t1,ne
1312         csel    $t2,$a2,$t2,ne
1313         csel    $t3,$a3,$t3,ne
1314         cmp     $in2infty,#0                    // !$in2intfy, remember?
1315         csel    $acc0,$t0,$acc0,ne
1316         csel    $acc1,$t1,$acc1,ne
1317         csel    $acc2,$t2,$acc2,ne
1318         csel    $acc3,$t3,$acc3,ne
1319         stp     $acc0,$acc1,[$rp_real,#$i]
1320         stp     $acc2,$acc3,[$rp_real,#$i+16]
1321
1322         add     sp,x29,#0               // destroy frame
1323         ldp     x19,x20,[x29,#16]
1324         ldp     x21,x22,[x29,#32]
1325         ldp     x23,x24,[x29,#48]
1326         ldp     x25,x26,[x29,#64]
1327         ldp     x29,x30,[sp],#80
1328         ret
1329 .size   ecp_nistz256_point_add_affine,.-ecp_nistz256_point_add_affine
1330 ___
1331 }       }
1332
1333 ########################################################################
1334 # scatter-gather subroutines
1335 {
1336 my ($out,$inp,$index,$mask)=map("x$_",(0..3));
1337 $code.=<<___;
1338 // void ecp_nistz256_scatter_w5(void *x0,const P256_POINT *x1,
1339 //                                       int x2);
1340 .globl  ecp_nistz256_scatter_w5
1341 .type   ecp_nistz256_scatter_w5,%function
1342 .align  4
1343 ecp_nistz256_scatter_w5:
1344         stp     x29,x30,[sp,#-16]!
1345         add     x29,sp,#0
1346
1347         add     $out,$out,$index,lsl#2
1348
1349         ldp     x4,x5,[$inp]            // X
1350         ldp     x6,x7,[$inp,#16]
1351         str     w4,[$out,#64*0-4]
1352         lsr     x4,x4,#32
1353         str     w5,[$out,#64*1-4]
1354         lsr     x5,x5,#32
1355         str     w6,[$out,#64*2-4]
1356         lsr     x6,x6,#32
1357         str     w7,[$out,#64*3-4]
1358         lsr     x7,x7,#32
1359         str     w4,[$out,#64*4-4]
1360         str     w5,[$out,#64*5-4]
1361         str     w6,[$out,#64*6-4]
1362         str     w7,[$out,#64*7-4]
1363         add     $out,$out,#64*8
1364
1365         ldp     x4,x5,[$inp,#32]        // Y
1366         ldp     x6,x7,[$inp,#48]
1367         str     w4,[$out,#64*0-4]
1368         lsr     x4,x4,#32
1369         str     w5,[$out,#64*1-4]
1370         lsr     x5,x5,#32
1371         str     w6,[$out,#64*2-4]
1372         lsr     x6,x6,#32
1373         str     w7,[$out,#64*3-4]
1374         lsr     x7,x7,#32
1375         str     w4,[$out,#64*4-4]
1376         str     w5,[$out,#64*5-4]
1377         str     w6,[$out,#64*6-4]
1378         str     w7,[$out,#64*7-4]
1379         add     $out,$out,#64*8
1380
1381         ldp     x4,x5,[$inp,#64]        // Z
1382         ldp     x6,x7,[$inp,#80]
1383         str     w4,[$out,#64*0-4]
1384         lsr     x4,x4,#32
1385         str     w5,[$out,#64*1-4]
1386         lsr     x5,x5,#32
1387         str     w6,[$out,#64*2-4]
1388         lsr     x6,x6,#32
1389         str     w7,[$out,#64*3-4]
1390         lsr     x7,x7,#32
1391         str     w4,[$out,#64*4-4]
1392         str     w5,[$out,#64*5-4]
1393         str     w6,[$out,#64*6-4]
1394         str     w7,[$out,#64*7-4]
1395
1396         ldr     x29,[sp],#16
1397         ret
1398 .size   ecp_nistz256_scatter_w5,.-ecp_nistz256_scatter_w5
1399
1400 // void ecp_nistz256_gather_w5(P256_POINT *x0,const void *x1,
1401 //                                            int x2);
1402 .globl  ecp_nistz256_gather_w5
1403 .type   ecp_nistz256_gather_w5,%function
1404 .align  4
1405 ecp_nistz256_gather_w5:
1406         stp     x29,x30,[sp,#-16]!
1407         add     x29,sp,#0
1408
1409         cmp     $index,xzr
1410         csetm   x3,ne
1411         add     $index,$index,x3
1412         add     $inp,$inp,$index,lsl#2
1413
1414         ldr     w4,[$inp,#64*0]
1415         ldr     w5,[$inp,#64*1]
1416         ldr     w6,[$inp,#64*2]
1417         ldr     w7,[$inp,#64*3]
1418         ldr     w8,[$inp,#64*4]
1419         ldr     w9,[$inp,#64*5]
1420         ldr     w10,[$inp,#64*6]
1421         ldr     w11,[$inp,#64*7]
1422         add     $inp,$inp,#64*8
1423         orr     x4,x4,x8,lsl#32
1424         orr     x5,x5,x9,lsl#32
1425         orr     x6,x6,x10,lsl#32
1426         orr     x7,x7,x11,lsl#32
1427         csel    x4,x4,xzr,ne
1428         csel    x5,x5,xzr,ne
1429         csel    x6,x6,xzr,ne
1430         csel    x7,x7,xzr,ne
1431         stp     x4,x5,[$out]            // X
1432         stp     x6,x7,[$out,#16]
1433
1434         ldr     w4,[$inp,#64*0]
1435         ldr     w5,[$inp,#64*1]
1436         ldr     w6,[$inp,#64*2]
1437         ldr     w7,[$inp,#64*3]
1438         ldr     w8,[$inp,#64*4]
1439         ldr     w9,[$inp,#64*5]
1440         ldr     w10,[$inp,#64*6]
1441         ldr     w11,[$inp,#64*7]
1442         add     $inp,$inp,#64*8
1443         orr     x4,x4,x8,lsl#32
1444         orr     x5,x5,x9,lsl#32
1445         orr     x6,x6,x10,lsl#32
1446         orr     x7,x7,x11,lsl#32
1447         csel    x4,x4,xzr,ne
1448         csel    x5,x5,xzr,ne
1449         csel    x6,x6,xzr,ne
1450         csel    x7,x7,xzr,ne
1451         stp     x4,x5,[$out,#32]        // Y
1452         stp     x6,x7,[$out,#48]
1453
1454         ldr     w4,[$inp,#64*0]
1455         ldr     w5,[$inp,#64*1]
1456         ldr     w6,[$inp,#64*2]
1457         ldr     w7,[$inp,#64*3]
1458         ldr     w8,[$inp,#64*4]
1459         ldr     w9,[$inp,#64*5]
1460         ldr     w10,[$inp,#64*6]
1461         ldr     w11,[$inp,#64*7]
1462         orr     x4,x4,x8,lsl#32
1463         orr     x5,x5,x9,lsl#32
1464         orr     x6,x6,x10,lsl#32
1465         orr     x7,x7,x11,lsl#32
1466         csel    x4,x4,xzr,ne
1467         csel    x5,x5,xzr,ne
1468         csel    x6,x6,xzr,ne
1469         csel    x7,x7,xzr,ne
1470         stp     x4,x5,[$out,#64]        // Z
1471         stp     x6,x7,[$out,#80]
1472
1473         ldr     x29,[sp],#16
1474         ret
1475 .size   ecp_nistz256_gather_w5,.-ecp_nistz256_gather_w5
1476
1477 // void ecp_nistz256_scatter_w7(void *x0,const P256_POINT_AFFINE *x1,
1478 //                                       int x2);
1479 .globl  ecp_nistz256_scatter_w7
1480 .type   ecp_nistz256_scatter_w7,%function
1481 .align  4
1482 ecp_nistz256_scatter_w7:
1483         stp     x29,x30,[sp,#-16]!
1484         add     x29,sp,#0
1485
1486         add     $out,$out,$index
1487         mov     $index,#64/8
1488 .Loop_scatter_w7:
1489         ldr     x3,[$inp],#8
1490         subs    $index,$index,#1
1491         prfm    pstl1strm,[$out,#4096+64*0]
1492         prfm    pstl1strm,[$out,#4096+64*1]
1493         prfm    pstl1strm,[$out,#4096+64*2]
1494         prfm    pstl1strm,[$out,#4096+64*3]
1495         prfm    pstl1strm,[$out,#4096+64*4]
1496         prfm    pstl1strm,[$out,#4096+64*5]
1497         prfm    pstl1strm,[$out,#4096+64*6]
1498         prfm    pstl1strm,[$out,#4096+64*7]
1499         strb    w3,[$out,#64*0-1]
1500         lsr     x3,x3,#8
1501         strb    w3,[$out,#64*1-1]
1502         lsr     x3,x3,#8
1503         strb    w3,[$out,#64*2-1]
1504         lsr     x3,x3,#8
1505         strb    w3,[$out,#64*3-1]
1506         lsr     x3,x3,#8
1507         strb    w3,[$out,#64*4-1]
1508         lsr     x3,x3,#8
1509         strb    w3,[$out,#64*5-1]
1510         lsr     x3,x3,#8
1511         strb    w3,[$out,#64*6-1]
1512         lsr     x3,x3,#8
1513         strb    w3,[$out,#64*7-1]
1514         add     $out,$out,#64*8
1515         b.ne    .Loop_scatter_w7
1516
1517         ldr     x29,[sp],#16
1518         ret
1519 .size   ecp_nistz256_scatter_w7,.-ecp_nistz256_scatter_w7
1520
1521 // void ecp_nistz256_gather_w7(P256_POINT_AFFINE *x0,const void *x1,
1522 //                                                   int x2);
1523 .globl  ecp_nistz256_gather_w7
1524 .type   ecp_nistz256_gather_w7,%function
1525 .align  4
1526 ecp_nistz256_gather_w7:
1527         stp     x29,x30,[sp,#-16]!
1528         add     x29,sp,#0
1529
1530         cmp     $index,xzr
1531         csetm   x3,ne
1532         add     $index,$index,x3
1533         add     $inp,$inp,$index
1534         mov     $index,#64/8
1535         nop
1536 .Loop_gather_w7:
1537         ldrb    w4,[$inp,#64*0]
1538         prfm    pldl1strm,[$inp,#4096+64*0]
1539         subs    $index,$index,#1
1540         ldrb    w5,[$inp,#64*1]
1541         prfm    pldl1strm,[$inp,#4096+64*1]
1542         ldrb    w6,[$inp,#64*2]
1543         prfm    pldl1strm,[$inp,#4096+64*2]
1544         ldrb    w7,[$inp,#64*3]
1545         prfm    pldl1strm,[$inp,#4096+64*3]
1546         ldrb    w8,[$inp,#64*4]
1547         prfm    pldl1strm,[$inp,#4096+64*4]
1548         ldrb    w9,[$inp,#64*5]
1549         prfm    pldl1strm,[$inp,#4096+64*5]
1550         ldrb    w10,[$inp,#64*6]
1551         prfm    pldl1strm,[$inp,#4096+64*6]
1552         ldrb    w11,[$inp,#64*7]
1553         prfm    pldl1strm,[$inp,#4096+64*7]
1554         add     $inp,$inp,#64*8
1555         orr     x4,x4,x5,lsl#8
1556         orr     x6,x6,x7,lsl#8
1557         orr     x8,x8,x9,lsl#8
1558         orr     x4,x4,x6,lsl#16
1559         orr     x10,x10,x11,lsl#8
1560         orr     x4,x4,x8,lsl#32
1561         orr     x4,x4,x10,lsl#48
1562         and     x4,x4,x3
1563         str     x4,[$out],#8
1564         b.ne    .Loop_gather_w7
1565
1566         ldr     x29,[sp],#16
1567         ret
1568 .size   ecp_nistz256_gather_w7,.-ecp_nistz256_gather_w7
1569 ___
1570 }
1571
1572 foreach (split("\n",$code)) {
1573         s/\`([^\`]*)\`/eval $1/ge;
1574
1575         print $_,"\n";
1576 }
1577 close STDOUT;   # enforce flush