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