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