Merge f_field.h into field.h
[openssl.git] / crypto / ec / asm / ecp_nistz256-x86_64.pl
index 48d64645f0a445a8da31104e59865d74031bf5e0..eba6ffd430bef6b5a2c0836c9d6db83d0ca1f9e2 100755 (executable)
@@ -1,15 +1,17 @@
 #! /usr/bin/env perl
-# Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 2014-2018 The OpenSSL Project Authors. All Rights Reserved.
 # Copyright (c) 2014, Intel Corporation. All Rights Reserved.
+# Copyright (c) 2015 CloudFlare, Inc.
 #
 # Licensed under the OpenSSL license (the "License").  You may not use
 # this file except in compliance with the License.  You can obtain a copy
 # in the file LICENSE in the source distribution or at
 # https://www.openssl.org/source/license.html
 #
-# Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
+# Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1, 3)
 # (1) Intel Corporation, Israel Development Center, Haifa, Israel
 # (2) University of Haifa, Israel
+# (3) CloudFlare, Inc.
 #
 # Reference:
 # S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with
 # Further optimization by <appro@openssl.org>:
 #
 #              this/original   with/without -DECP_NISTZ256_ASM(*)
-# Opteron      +12-49%         +110-150%
-# Bulldozer    +14-45%         +175-210%
-# P4           +18-46%         n/a :-(
-# Westmere     +12-34%         +80-87%
-# Sandy Bridge +9-35%          +110-120%
-# Ivy Bridge   +9-35%          +110-125%
-# Haswell      +8-37%          +140-160%
-# Broadwell    +18-58%         +145-210%
-# Atom         +15-50%         +130-180%
-# VIA Nano     +43-160%        +300-480%
+# Opteron      +15-49%         +150-195%
+# Bulldozer    +18-45%         +175-240%
+# P4           +24-46%         +100-150%
+# Westmere     +18-34%         +87-160%
+# Sandy Bridge +14-35%         +120-185%
+# Ivy Bridge   +11-35%         +125-180%
+# Haswell      +10-37%         +160-200%
+# Broadwell    +24-58%         +210-270%
+# Atom         +20-50%         +180-240%
+# VIA Nano     +50-160%        +480-480%
 #
 # (*)  "without -DECP_NISTZ256_ASM" refers to build with
 #      "enable-ec_nistp_64_gcc_128";
 #
 # Ranges denote minimum and maximum improvement coefficients depending
-# on benchmark. Lower coefficients are for ECDSA sign, relatively fastest
-# server-side operation. Keep in mind that +100% means 2x improvement.
+# on benchmark. In "this/original" column lower coefficient is for
+# ECDSA sign, while in "with/without" - for ECDH key agreement, and
+# higher - for ECDSA sign, relatively fastest server-side operation.
+# Keep in mind that +100% means 2x improvement.
 
 $flavour = shift;
 $output  = shift;
@@ -95,6 +99,12 @@ $code.=<<___;
 .long 3,3,3,3,3,3,3,3
 .LONE_mont:
 .quad 0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe
+
+# Constants for computations modulo ord(p256)
+.Lord:
+.quad 0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff, 0xffffffff00000000
+.LordK:
+.quad 0xccd1c8aaee00bc4f
 ___
 
 {
@@ -334,152 +344,1231 @@ ecp_nistz256_add:
         mov    $a1, $t1
        adc     \$0, $t4
 
-       sub     8*0($a_ptr), $a0
-        mov    $a2, $t2
-       sbb     8*1($a_ptr), $a1
-       sbb     8*2($a_ptr), $a2
-        mov    $a3, $t3
-       sbb     8*3($a_ptr), $a3
-       sbb     \$0, $t4
+       sub     8*0($a_ptr), $a0
+        mov    $a2, $t2
+       sbb     8*1($a_ptr), $a1
+       sbb     8*2($a_ptr), $a2
+        mov    $a3, $t3
+       sbb     8*3($a_ptr), $a3
+       sbb     \$0, $t4
+
+       cmovc   $t0, $a0
+       cmovc   $t1, $a1
+       mov     $a0, 8*0($r_ptr)
+       cmovc   $t2, $a2
+       mov     $a1, 8*1($r_ptr)
+       cmovc   $t3, $a3
+       mov     $a2, 8*2($r_ptr)
+       mov     $a3, 8*3($r_ptr)
+
+       mov     0(%rsp),%r13
+.cfi_restore   %r13
+       mov     8(%rsp),%r12
+.cfi_restore   %r12
+       lea     16(%rsp),%rsp
+.cfi_adjust_cfa_offset -16
+.Ladd_epilogue:
+       ret
+.cfi_endproc
+.size  ecp_nistz256_add,.-ecp_nistz256_add
+
+################################################################################
+# void ecp_nistz256_sub(uint64_t res[4], uint64_t a[4], uint64_t b[4]);
+.globl ecp_nistz256_sub
+.type  ecp_nistz256_sub,\@function,3
+.align 32
+ecp_nistz256_sub:
+.cfi_startproc
+       push    %r12
+.cfi_push      %r12
+       push    %r13
+.cfi_push      %r13
+.Lsub_body:
+
+       mov     8*0($a_ptr), $a0
+       xor     $t4, $t4
+       mov     8*1($a_ptr), $a1
+       mov     8*2($a_ptr), $a2
+       mov     8*3($a_ptr), $a3
+       lea     .Lpoly(%rip), $a_ptr
+
+       sub     8*0($b_ptr), $a0
+       sbb     8*1($b_ptr), $a1
+        mov    $a0, $t0
+       sbb     8*2($b_ptr), $a2
+       sbb     8*3($b_ptr), $a3
+        mov    $a1, $t1
+       sbb     \$0, $t4
+
+       add     8*0($a_ptr), $a0
+        mov    $a2, $t2
+       adc     8*1($a_ptr), $a1
+       adc     8*2($a_ptr), $a2
+        mov    $a3, $t3
+       adc     8*3($a_ptr), $a3
+       test    $t4, $t4
+
+       cmovz   $t0, $a0
+       cmovz   $t1, $a1
+       mov     $a0, 8*0($r_ptr)
+       cmovz   $t2, $a2
+       mov     $a1, 8*1($r_ptr)
+       cmovz   $t3, $a3
+       mov     $a2, 8*2($r_ptr)
+       mov     $a3, 8*3($r_ptr)
+
+       mov     0(%rsp),%r13
+.cfi_restore   %r13
+       mov     8(%rsp),%r12
+.cfi_restore   %r12
+       lea     16(%rsp),%rsp
+.cfi_adjust_cfa_offset -16
+.Lsub_epilogue:
+       ret
+.cfi_endproc
+.size  ecp_nistz256_sub,.-ecp_nistz256_sub
+
+################################################################################
+# void ecp_nistz256_neg(uint64_t res[4], uint64_t a[4]);
+.globl ecp_nistz256_neg
+.type  ecp_nistz256_neg,\@function,2
+.align 32
+ecp_nistz256_neg:
+.cfi_startproc
+       push    %r12
+.cfi_push      %r12
+       push    %r13
+.cfi_push      %r13
+.Lneg_body:
+
+       xor     $a0, $a0
+       xor     $a1, $a1
+       xor     $a2, $a2
+       xor     $a3, $a3
+       xor     $t4, $t4
+
+       sub     8*0($a_ptr), $a0
+       sbb     8*1($a_ptr), $a1
+       sbb     8*2($a_ptr), $a2
+        mov    $a0, $t0
+       sbb     8*3($a_ptr), $a3
+       lea     .Lpoly(%rip), $a_ptr
+        mov    $a1, $t1
+       sbb     \$0, $t4
+
+       add     8*0($a_ptr), $a0
+        mov    $a2, $t2
+       adc     8*1($a_ptr), $a1
+       adc     8*2($a_ptr), $a2
+        mov    $a3, $t3
+       adc     8*3($a_ptr), $a3
+       test    $t4, $t4
+
+       cmovz   $t0, $a0
+       cmovz   $t1, $a1
+       mov     $a0, 8*0($r_ptr)
+       cmovz   $t2, $a2
+       mov     $a1, 8*1($r_ptr)
+       cmovz   $t3, $a3
+       mov     $a2, 8*2($r_ptr)
+       mov     $a3, 8*3($r_ptr)
+
+       mov     0(%rsp),%r13
+.cfi_restore   %r13
+       mov     8(%rsp),%r12
+.cfi_restore   %r12
+       lea     16(%rsp),%rsp
+.cfi_adjust_cfa_offset -16
+.Lneg_epilogue:
+       ret
+.cfi_endproc
+.size  ecp_nistz256_neg,.-ecp_nistz256_neg
+___
+}
+{
+my ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
+my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
+my ($t0,$t1,$t2,$t3,$t4)=("%rcx","%rbp","%rbx","%rdx","%rax");
+my ($poly1,$poly3)=($acc6,$acc7);
+
+$code.=<<___;
+################################################################################
+# void ecp_nistz256_ord_mul_mont(
+#   uint64_t res[4],
+#   uint64_t a[4],
+#   uint64_t b[4]);
+
+.globl ecp_nistz256_ord_mul_mont
+.type  ecp_nistz256_ord_mul_mont,\@function,3
+.align 32
+ecp_nistz256_ord_mul_mont:
+.cfi_startproc
+___
+$code.=<<___   if ($addx);
+       mov     \$0x80100, %ecx
+       and     OPENSSL_ia32cap_P+8(%rip), %ecx
+       cmp     \$0x80100, %ecx
+       je      .Lecp_nistz256_ord_mul_montx
+___
+$code.=<<___;
+       push    %rbp
+.cfi_push      %rbp
+       push    %rbx
+.cfi_push      %rbx
+       push    %r12
+.cfi_push      %r12
+       push    %r13
+.cfi_push      %r13
+       push    %r14
+.cfi_push      %r14
+       push    %r15
+.cfi_push      %r15
+.Lord_mul_body:
+
+       mov     8*0($b_org), %rax
+       mov     $b_org, $b_ptr
+       lea     .Lord(%rip), %r14
+       mov     .LordK(%rip), %r15
+
+       ################################# * b[0]
+       mov     %rax, $t0
+       mulq    8*0($a_ptr)
+       mov     %rax, $acc0
+       mov     $t0, %rax
+       mov     %rdx, $acc1
+
+       mulq    8*1($a_ptr)
+       add     %rax, $acc1
+       mov     $t0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $acc2
+
+       mulq    8*2($a_ptr)
+       add     %rax, $acc2
+       mov     $t0, %rax
+       adc     \$0, %rdx
+
+        mov    $acc0, $acc5
+        imulq  %r15,$acc0
+
+       mov     %rdx, $acc3
+       mulq    8*3($a_ptr)
+       add     %rax, $acc3
+        mov    $acc0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $acc4
+
+       ################################# First reduction step
+       mulq    8*0(%r14)
+       mov     $acc0, $t1
+       add     %rax, $acc5             # guaranteed to be zero
+       mov     $acc0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t0
+
+       sub     $acc0, $acc2
+       sbb     \$0, $acc0              # can't borrow
+
+       mulq    8*1(%r14)
+       add     $t0, $acc1
+       adc     \$0, %rdx
+       add     %rax, $acc1
+       mov     $t1, %rax
+       adc     %rdx, $acc2
+       mov     $t1, %rdx
+       adc     \$0, $acc0              # can't overflow
+
+       shl     \$32, %rax
+       shr     \$32, %rdx
+       sub     %rax, $acc3
+        mov    8*1($b_ptr), %rax
+       sbb     %rdx, $t1               # can't borrow
+
+       add     $acc0, $acc3
+       adc     $t1, $acc4
+       adc     \$0, $acc5
+
+       ################################# * b[1]
+       mov     %rax, $t0
+       mulq    8*0($a_ptr)
+       add     %rax, $acc1
+       mov     $t0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t1
+
+       mulq    8*1($a_ptr)
+       add     $t1, $acc2
+       adc     \$0, %rdx
+       add     %rax, $acc2
+       mov     $t0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t1
+
+       mulq    8*2($a_ptr)
+       add     $t1, $acc3
+       adc     \$0, %rdx
+       add     %rax, $acc3
+       mov     $t0, %rax
+       adc     \$0, %rdx
+
+        mov    $acc1, $t0
+        imulq  %r15, $acc1
+
+       mov     %rdx, $t1
+       mulq    8*3($a_ptr)
+       add     $t1, $acc4
+       adc     \$0, %rdx
+       xor     $acc0, $acc0
+       add     %rax, $acc4
+        mov    $acc1, %rax
+       adc     %rdx, $acc5
+       adc     \$0, $acc0
+
+       ################################# Second reduction step
+       mulq    8*0(%r14)
+       mov     $acc1, $t1
+       add     %rax, $t0               # guaranteed to be zero
+       mov     $acc1, %rax
+       adc     %rdx, $t0
+
+       sub     $acc1, $acc3
+       sbb     \$0, $acc1              # can't borrow
+
+       mulq    8*1(%r14)
+       add     $t0, $acc2
+       adc     \$0, %rdx
+       add     %rax, $acc2
+       mov     $t1, %rax
+       adc     %rdx, $acc3
+       mov     $t1, %rdx
+       adc     \$0, $acc1              # can't overflow
+
+       shl     \$32, %rax
+       shr     \$32, %rdx
+       sub     %rax, $acc4
+        mov    8*2($b_ptr), %rax
+       sbb     %rdx, $t1               # can't borrow
+
+       add     $acc1, $acc4
+       adc     $t1, $acc5
+       adc     \$0, $acc0
+
+       ################################## * b[2]
+       mov     %rax, $t0
+       mulq    8*0($a_ptr)
+       add     %rax, $acc2
+       mov     $t0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t1
+
+       mulq    8*1($a_ptr)
+       add     $t1, $acc3
+       adc     \$0, %rdx
+       add     %rax, $acc3
+       mov     $t0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t1
+
+       mulq    8*2($a_ptr)
+       add     $t1, $acc4
+       adc     \$0, %rdx
+       add     %rax, $acc4
+       mov     $t0, %rax
+       adc     \$0, %rdx
+
+        mov    $acc2, $t0
+        imulq  %r15, $acc2
+
+       mov     %rdx, $t1
+       mulq    8*3($a_ptr)
+       add     $t1, $acc5
+       adc     \$0, %rdx
+       xor     $acc1, $acc1
+       add     %rax, $acc5
+        mov    $acc2, %rax
+       adc     %rdx, $acc0
+       adc     \$0, $acc1
+
+       ################################# Third reduction step
+       mulq    8*0(%r14)
+       mov     $acc2, $t1
+       add     %rax, $t0               # guaranteed to be zero
+       mov     $acc2, %rax
+       adc     %rdx, $t0
+
+       sub     $acc2, $acc4
+       sbb     \$0, $acc2              # can't borrow
+
+       mulq    8*1(%r14)
+       add     $t0, $acc3
+       adc     \$0, %rdx
+       add     %rax, $acc3
+       mov     $t1, %rax
+       adc     %rdx, $acc4
+       mov     $t1, %rdx
+       adc     \$0, $acc2              # can't overflow
+
+       shl     \$32, %rax
+       shr     \$32, %rdx
+       sub     %rax, $acc5
+        mov    8*3($b_ptr), %rax
+       sbb     %rdx, $t1               # can't borrow
+
+       add     $acc2, $acc5
+       adc     $t1, $acc0
+       adc     \$0, $acc1
+
+       ################################# * b[3]
+       mov     %rax, $t0
+       mulq    8*0($a_ptr)
+       add     %rax, $acc3
+       mov     $t0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t1
+
+       mulq    8*1($a_ptr)
+       add     $t1, $acc4
+       adc     \$0, %rdx
+       add     %rax, $acc4
+       mov     $t0, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t1
+
+       mulq    8*2($a_ptr)
+       add     $t1, $acc5
+       adc     \$0, %rdx
+       add     %rax, $acc5
+       mov     $t0, %rax
+       adc     \$0, %rdx
+
+        mov    $acc3, $t0
+        imulq  %r15, $acc3
+
+       mov     %rdx, $t1
+       mulq    8*3($a_ptr)
+       add     $t1, $acc0
+       adc     \$0, %rdx
+       xor     $acc2, $acc2
+       add     %rax, $acc0
+        mov    $acc3, %rax
+       adc     %rdx, $acc1
+       adc     \$0, $acc2
+
+       ################################# Last reduction step
+       mulq    8*0(%r14)
+       mov     $acc3, $t1
+       add     %rax, $t0               # guaranteed to be zero
+       mov     $acc3, %rax
+       adc     %rdx, $t0
+
+       sub     $acc3, $acc5
+       sbb     \$0, $acc3              # can't borrow
+
+       mulq    8*1(%r14)
+       add     $t0, $acc4
+       adc     \$0, %rdx
+       add     %rax, $acc4
+       mov     $t1, %rax
+       adc     %rdx, $acc5
+       mov     $t1, %rdx
+       adc     \$0, $acc3              # can't overflow
+
+       shl     \$32, %rax
+       shr     \$32, %rdx
+       sub     %rax, $acc0
+       sbb     %rdx, $t1               # can't borrow
+
+       add     $acc3, $acc0
+       adc     $t1, $acc1
+       adc     \$0, $acc2
+
+       ################################# Subtract ord
+        mov    $acc4, $a_ptr
+       sub     8*0(%r14), $acc4
+        mov    $acc5, $acc3
+       sbb     8*1(%r14), $acc5
+        mov    $acc0, $t0
+       sbb     8*2(%r14), $acc0
+        mov    $acc1, $t1
+       sbb     8*3(%r14), $acc1
+       sbb     \$0, $acc2
+
+       cmovc   $a_ptr, $acc4
+       cmovc   $acc3, $acc5
+       cmovc   $t0, $acc0
+       cmovc   $t1, $acc1
+
+       mov     $acc4, 8*0($r_ptr)
+       mov     $acc5, 8*1($r_ptr)
+       mov     $acc0, 8*2($r_ptr)
+       mov     $acc1, 8*3($r_ptr)
+
+       mov     0(%rsp),%r15
+.cfi_restore   %r15
+       mov     8(%rsp),%r14
+.cfi_restore   %r14
+       mov     16(%rsp),%r13
+.cfi_restore   %r13
+       mov     24(%rsp),%r12
+.cfi_restore   %r12
+       mov     32(%rsp),%rbx
+.cfi_restore   %rbx
+       mov     40(%rsp),%rbp
+.cfi_restore   %rbp
+       lea     48(%rsp),%rsp
+.cfi_adjust_cfa_offset -48
+.Lord_mul_epilogue:
+       ret
+.cfi_endproc
+.size  ecp_nistz256_ord_mul_mont,.-ecp_nistz256_ord_mul_mont
+
+################################################################################
+# void ecp_nistz256_ord_sqr_mont(
+#   uint64_t res[4],
+#   uint64_t a[4],
+#   int rep);
+
+.globl ecp_nistz256_ord_sqr_mont
+.type  ecp_nistz256_ord_sqr_mont,\@function,3
+.align 32
+ecp_nistz256_ord_sqr_mont:
+.cfi_startproc
+___
+$code.=<<___   if ($addx);
+       mov     \$0x80100, %ecx
+       and     OPENSSL_ia32cap_P+8(%rip), %ecx
+       cmp     \$0x80100, %ecx
+       je      .Lecp_nistz256_ord_sqr_montx
+___
+$code.=<<___;
+       push    %rbp
+.cfi_push      %rbp
+       push    %rbx
+.cfi_push      %rbx
+       push    %r12
+.cfi_push      %r12
+       push    %r13
+.cfi_push      %r13
+       push    %r14
+.cfi_push      %r14
+       push    %r15
+.cfi_push      %r15
+.Lord_sqr_body:
+
+       mov     8*0($a_ptr), $acc0
+       mov     8*1($a_ptr), %rax
+       mov     8*2($a_ptr), $acc6
+       mov     8*3($a_ptr), $acc7
+       lea     .Lord(%rip), $a_ptr     # pointer to modulus
+       mov     $b_org, $b_ptr
+       jmp     .Loop_ord_sqr
+
+.align 32
+.Loop_ord_sqr:
+       ################################# a[1:] * a[0]
+       mov     %rax, $t1               # put aside a[1]
+       mul     $acc0                   # a[1] * a[0]
+       mov     %rax, $acc1
+       movq    $t1, %xmm1              # offload a[1]
+       mov     $acc6, %rax
+       mov     %rdx, $acc2
+
+       mul     $acc0                   # a[2] * a[0]
+       add     %rax, $acc2
+       mov     $acc7, %rax
+       movq    $acc6, %xmm2            # offload a[2]
+       adc     \$0, %rdx
+       mov     %rdx, $acc3
+
+       mul     $acc0                   # a[3] * a[0]
+       add     %rax, $acc3
+       mov     $acc7, %rax
+       movq    $acc7, %xmm3            # offload a[3]
+       adc     \$0, %rdx
+       mov     %rdx, $acc4
+
+       ################################# a[3] * a[2]
+       mul     $acc6                   # a[3] * a[2]
+       mov     %rax, $acc5
+       mov     $acc6, %rax
+       mov     %rdx, $acc6
+
+       ################################# a[2:] * a[1]
+       mul     $t1                     # a[2] * a[1]
+       add     %rax, $acc3
+       mov     $acc7, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $acc7
+
+       mul     $t1                     # a[3] * a[1]
+       add     %rax, $acc4
+       adc     \$0, %rdx
+
+       add     $acc7, $acc4
+       adc     %rdx, $acc5
+       adc     \$0, $acc6              # can't overflow
+
+       ################################# *2
+       xor     $acc7, $acc7
+       mov     $acc0, %rax
+       add     $acc1, $acc1
+       adc     $acc2, $acc2
+       adc     $acc3, $acc3
+       adc     $acc4, $acc4
+       adc     $acc5, $acc5
+       adc     $acc6, $acc6
+       adc     \$0, $acc7
+
+       ################################# Missing products
+       mul     %rax                    # a[0] * a[0]
+       mov     %rax, $acc0
+       movq    %xmm1, %rax
+       mov     %rdx, $t1
+
+       mul     %rax                    # a[1] * a[1]
+       add     $t1, $acc1
+       adc     %rax, $acc2
+       movq    %xmm2, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t1
+
+       mul     %rax                    # a[2] * a[2]
+       add     $t1, $acc3
+       adc     %rax, $acc4
+       movq    %xmm3, %rax
+       adc     \$0, %rdx
+       mov     %rdx, $t1
+
+        mov    $acc0, $t0
+        imulq  8*4($a_ptr), $acc0      # *= .LordK
+
+       mul     %rax                    # a[3] * a[3]
+       add     $t1, $acc5
+       adc     %rax, $acc6
+        mov    8*0($a_ptr), %rax       # modulus[0]
+       adc     %rdx, $acc7             # can't overflow
+
+       ################################# First reduction step
+       mul     $acc0
+       mov     $acc0, $t1
+       add     %rax, $t0               # guaranteed to be zero
+       mov     8*1($a_ptr), %rax       # modulus[1]
+       adc     %rdx, $t0
+
+       sub     $acc0, $acc2
+       sbb     \$0, $t1                # can't borrow
+
+       mul     $acc0
+       add     $t0, $acc1
+       adc     \$0, %rdx
+       add     %rax, $acc1
+       mov     $acc0, %rax
+       adc     %rdx, $acc2
+       mov     $acc0, %rdx
+       adc     \$0, $t1                # can't overflow
+
+        mov    $acc1, $t0
+        imulq  8*4($a_ptr), $acc1      # *= .LordK
+
+       shl     \$32, %rax
+       shr     \$32, %rdx
+       sub     %rax, $acc3
+        mov    8*0($a_ptr), %rax
+       sbb     %rdx, $acc0             # can't borrow
+
+       add     $t1, $acc3
+       adc     \$0, $acc0              # can't overflow
+
+       ################################# Second reduction step
+       mul     $acc1
+       mov     $acc1, $t1
+       add     %rax, $t0               # guaranteed to be zero
+       mov     8*1($a_ptr), %rax
+       adc     %rdx, $t0
+
+       sub     $acc1, $acc3
+       sbb     \$0, $t1                # can't borrow
+
+       mul     $acc1
+       add     $t0, $acc2
+       adc     \$0, %rdx
+       add     %rax, $acc2
+       mov     $acc1, %rax
+       adc     %rdx, $acc3
+       mov     $acc1, %rdx
+       adc     \$0, $t1                # can't overflow
+
+        mov    $acc2, $t0
+        imulq  8*4($a_ptr), $acc2      # *= .LordK
+
+       shl     \$32, %rax
+       shr     \$32, %rdx
+       sub     %rax, $acc0
+        mov    8*0($a_ptr), %rax
+       sbb     %rdx, $acc1             # can't borrow
+
+       add     $t1, $acc0
+       adc     \$0, $acc1              # can't overflow
+
+       ################################# Third reduction step
+       mul     $acc2
+       mov     $acc2, $t1
+       add     %rax, $t0               # guaranteed to be zero
+       mov     8*1($a_ptr), %rax
+       adc     %rdx, $t0
+
+       sub     $acc2, $acc0
+       sbb     \$0, $t1                # can't borrow
+
+       mul     $acc2
+       add     $t0, $acc3
+       adc     \$0, %rdx
+       add     %rax, $acc3
+       mov     $acc2, %rax
+       adc     %rdx, $acc0
+       mov     $acc2, %rdx
+       adc     \$0, $t1                # can't overflow
+
+        mov    $acc3, $t0
+        imulq  8*4($a_ptr), $acc3      # *= .LordK
+
+       shl     \$32, %rax
+       shr     \$32, %rdx
+       sub     %rax, $acc1
+        mov    8*0($a_ptr), %rax
+       sbb     %rdx, $acc2             # can't borrow
+
+       add     $t1, $acc1
+       adc     \$0, $acc2              # can't overflow
+
+       ################################# Last reduction step
+       mul     $acc3
+       mov     $acc3, $t1
+       add     %rax, $t0               # guaranteed to be zero
+       mov     8*1($a_ptr), %rax
+       adc     %rdx, $t0
+
+       sub     $acc3, $acc1
+       sbb     \$0, $t1                # can't borrow
+
+       mul     $acc3
+       add     $t0, $acc0
+       adc     \$0, %rdx
+       add     %rax, $acc0
+       mov     $acc3, %rax
+       adc     %rdx, $acc1
+       mov     $acc3, %rdx
+       adc     \$0, $t1                # can't overflow
+
+       shl     \$32, %rax
+       shr     \$32, %rdx
+       sub     %rax, $acc2
+       sbb     %rdx, $acc3             # can't borrow
+
+       add     $t1, $acc2
+       adc     \$0, $acc3              # can't overflow
+
+       ################################# Add bits [511:256] of the sqr result
+       xor     %rdx, %rdx
+       add     $acc4, $acc0
+       adc     $acc5, $acc1
+        mov    $acc0, $acc4
+       adc     $acc6, $acc2
+       adc     $acc7, $acc3
+        mov    $acc1, %rax
+       adc     \$0, %rdx
+
+       ################################# Compare to modulus
+       sub     8*0($a_ptr), $acc0
+        mov    $acc2, $acc6
+       sbb     8*1($a_ptr), $acc1
+       sbb     8*2($a_ptr), $acc2
+        mov    $acc3, $acc7
+       sbb     8*3($a_ptr), $acc3
+       sbb     \$0, %rdx
+
+       cmovc   $acc4, $acc0
+       cmovnc  $acc1, %rax
+       cmovnc  $acc2, $acc6
+       cmovnc  $acc3, $acc7
+
+       dec     $b_ptr
+       jnz     .Loop_ord_sqr
+
+       mov     $acc0, 8*0($r_ptr)
+       mov     %rax,  8*1($r_ptr)
+       pxor    %xmm1, %xmm1
+       mov     $acc6, 8*2($r_ptr)
+       pxor    %xmm2, %xmm2
+       mov     $acc7, 8*3($r_ptr)
+       pxor    %xmm3, %xmm3
+
+       mov     0(%rsp),%r15
+.cfi_restore   %r15
+       mov     8(%rsp),%r14
+.cfi_restore   %r14
+       mov     16(%rsp),%r13
+.cfi_restore   %r13
+       mov     24(%rsp),%r12
+.cfi_restore   %r12
+       mov     32(%rsp),%rbx
+.cfi_restore   %rbx
+       mov     40(%rsp),%rbp
+.cfi_restore   %rbp
+       lea     48(%rsp),%rsp
+.cfi_adjust_cfa_offset -48
+.Lord_sqr_epilogue:
+       ret
+.cfi_endproc
+.size  ecp_nistz256_ord_sqr_mont,.-ecp_nistz256_ord_sqr_mont
+___
+
+$code.=<<___   if ($addx);
+################################################################################
+.type  ecp_nistz256_ord_mul_montx,\@function,3
+.align 32
+ecp_nistz256_ord_mul_montx:
+.cfi_startproc
+.Lecp_nistz256_ord_mul_montx:
+       push    %rbp
+.cfi_push      %rbp
+       push    %rbx
+.cfi_push      %rbx
+       push    %r12
+.cfi_push      %r12
+       push    %r13
+.cfi_push      %r13
+       push    %r14
+.cfi_push      %r14
+       push    %r15
+.cfi_push      %r15
+.Lord_mulx_body:
+
+       mov     $b_org, $b_ptr
+       mov     8*0($b_org), %rdx
+       mov     8*0($a_ptr), $acc1
+       mov     8*1($a_ptr), $acc2
+       mov     8*2($a_ptr), $acc3
+       mov     8*3($a_ptr), $acc4
+       lea     -128($a_ptr), $a_ptr    # control u-op density
+       lea     .Lord-128(%rip), %r14
+       mov     .LordK(%rip), %r15
+
+       ################################# Multiply by b[0]
+       mulx    $acc1, $acc0, $acc1
+       mulx    $acc2, $t0, $acc2
+       mulx    $acc3, $t1, $acc3
+       add     $t0, $acc1
+       mulx    $acc4, $t0, $acc4
+        mov    $acc0, %rdx
+        mulx   %r15, %rdx, %rax
+       adc     $t1, $acc2
+       adc     $t0, $acc3
+       adc     \$0, $acc4
+
+       ################################# reduction
+       xor     $acc5, $acc5            # $acc5=0, cf=0, of=0
+       mulx    8*0+128(%r14), $t0, $t1
+       adcx    $t0, $acc0              # guaranteed to be zero
+       adox    $t1, $acc1
+
+       mulx    8*1+128(%r14), $t0, $t1
+       adcx    $t0, $acc1
+       adox    $t1, $acc2
+
+       mulx    8*2+128(%r14), $t0, $t1
+       adcx    $t0, $acc2
+       adox    $t1, $acc3
+
+       mulx    8*3+128(%r14), $t0, $t1
+        mov    8*1($b_ptr), %rdx
+       adcx    $t0, $acc3
+       adox    $t1, $acc4
+       adcx    $acc0, $acc4
+       adox    $acc0, $acc5
+       adc     \$0, $acc5              # cf=0, of=0
+
+       ################################# Multiply by b[1]
+       mulx    8*0+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc1
+       adox    $t1, $acc2
+
+       mulx    8*1+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc2
+       adox    $t1, $acc3
+
+       mulx    8*2+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc3
+       adox    $t1, $acc4
+
+       mulx    8*3+128($a_ptr), $t0, $t1
+        mov    $acc1, %rdx
+        mulx   %r15, %rdx, %rax
+       adcx    $t0, $acc4
+       adox    $t1, $acc5
+
+       adcx    $acc0, $acc5
+       adox    $acc0, $acc0
+       adc     \$0, $acc0              # cf=0, of=0
+
+       ################################# reduction
+       mulx    8*0+128(%r14), $t0, $t1
+       adcx    $t0, $acc1              # guaranteed to be zero
+       adox    $t1, $acc2
+
+       mulx    8*1+128(%r14), $t0, $t1
+       adcx    $t0, $acc2
+       adox    $t1, $acc3
+
+       mulx    8*2+128(%r14), $t0, $t1
+       adcx    $t0, $acc3
+       adox    $t1, $acc4
+
+       mulx    8*3+128(%r14), $t0, $t1
+        mov    8*2($b_ptr), %rdx
+       adcx    $t0, $acc4
+       adox    $t1, $acc5
+       adcx    $acc1, $acc5
+       adox    $acc1, $acc0
+       adc     \$0, $acc0              # cf=0, of=0
+
+       ################################# Multiply by b[2]
+       mulx    8*0+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc2
+       adox    $t1, $acc3
+
+       mulx    8*1+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc3
+       adox    $t1, $acc4
+
+       mulx    8*2+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc4
+       adox    $t1, $acc5
+
+       mulx    8*3+128($a_ptr), $t0, $t1
+        mov    $acc2, %rdx
+        mulx   %r15, %rdx, %rax
+       adcx    $t0, $acc5
+       adox    $t1, $acc0
+
+       adcx    $acc1, $acc0
+       adox    $acc1, $acc1
+       adc     \$0, $acc1              # cf=0, of=0
+
+       ################################# reduction
+       mulx    8*0+128(%r14), $t0, $t1
+       adcx    $t0, $acc2              # guaranteed to be zero
+       adox    $t1, $acc3
+
+       mulx    8*1+128(%r14), $t0, $t1
+       adcx    $t0, $acc3
+       adox    $t1, $acc4
+
+       mulx    8*2+128(%r14), $t0, $t1
+       adcx    $t0, $acc4
+       adox    $t1, $acc5
+
+       mulx    8*3+128(%r14), $t0, $t1
+        mov    8*3($b_ptr), %rdx
+       adcx    $t0, $acc5
+       adox    $t1, $acc0
+       adcx    $acc2, $acc0
+       adox    $acc2, $acc1
+       adc     \$0, $acc1              # cf=0, of=0
+
+       ################################# Multiply by b[3]
+       mulx    8*0+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc3
+       adox    $t1, $acc4
+
+       mulx    8*1+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc4
+       adox    $t1, $acc5
+
+       mulx    8*2+128($a_ptr), $t0, $t1
+       adcx    $t0, $acc5
+       adox    $t1, $acc0
+
+       mulx    8*3+128($a_ptr), $t0, $t1
+        mov    $acc3, %rdx
+        mulx   %r15, %rdx, %rax
+       adcx    $t0, $acc0
+       adox    $t1, $acc1
+
+       adcx    $acc2, $acc1
+       adox    $acc2, $acc2
+       adc     \$0, $acc2              # cf=0, of=0
+
+       ################################# reduction
+       mulx    8*0+128(%r14), $t0, $t1
+       adcx    $t0, $acc3              # guranteed to be zero
+       adox    $t1, $acc4
+
+       mulx    8*1+128(%r14), $t0, $t1
+       adcx    $t0, $acc4
+       adox    $t1, $acc5
+
+       mulx    8*2+128(%r14), $t0, $t1
+       adcx    $t0, $acc5
+       adox    $t1, $acc0
+
+       mulx    8*3+128(%r14), $t0, $t1
+       lea     128(%r14),%r14
+        mov    $acc4, $t2
+       adcx    $t0, $acc0
+       adox    $t1, $acc1
+        mov    $acc5, $t3
+       adcx    $acc3, $acc1
+       adox    $acc3, $acc2
+       adc     \$0, $acc2
+
+       #################################
+       # Branch-less conditional subtraction of P
+        mov    $acc0, $t0
+       sub     8*0(%r14), $acc4
+       sbb     8*1(%r14), $acc5
+       sbb     8*2(%r14), $acc0
+        mov    $acc1, $t1
+       sbb     8*3(%r14), $acc1
+       sbb     \$0, $acc2
 
-       cmovc   $t0, $a0
-       cmovc   $t1, $a1
-       mov     $a0, 8*0($r_ptr)
-       cmovc   $t2, $a2
-       mov     $a1, 8*1($r_ptr)
-       cmovc   $t3, $a3
-       mov     $a2, 8*2($r_ptr)
-       mov     $a3, 8*3($r_ptr)
+       cmovc   $t2, $acc4
+       cmovc   $t3, $acc5
+       cmovc   $t0, $acc0
+       cmovc   $t1, $acc1
 
-       mov     0(%rsp),%r13
+       mov     $acc4, 8*0($r_ptr)
+       mov     $acc5, 8*1($r_ptr)
+       mov     $acc0, 8*2($r_ptr)
+       mov     $acc1, 8*3($r_ptr)
+
+       mov     0(%rsp),%r15
+.cfi_restore   %r15
+       mov     8(%rsp),%r14
+.cfi_restore   %r14
+       mov     16(%rsp),%r13
 .cfi_restore   %r13
-       mov     8(%rsp),%r12
+       mov     24(%rsp),%r12
 .cfi_restore   %r12
-       lea     16(%rsp),%rsp
-.cfi_adjust_cfa_offset -16
-.Ladd_epilogue:
+       mov     32(%rsp),%rbx
+.cfi_restore   %rbx
+       mov     40(%rsp),%rbp
+.cfi_restore   %rbp
+       lea     48(%rsp),%rsp
+.cfi_adjust_cfa_offset -48
+.Lord_mulx_epilogue:
        ret
 .cfi_endproc
-.size  ecp_nistz256_add,.-ecp_nistz256_add
+.size  ecp_nistz256_ord_mul_montx,.-ecp_nistz256_ord_mul_montx
 
-################################################################################
-# void ecp_nistz256_sub(uint64_t res[4], uint64_t a[4], uint64_t b[4]);
-.globl ecp_nistz256_sub
-.type  ecp_nistz256_sub,\@function,3
+.type  ecp_nistz256_ord_sqr_montx,\@function,3
 .align 32
-ecp_nistz256_sub:
+ecp_nistz256_ord_sqr_montx:
 .cfi_startproc
+.Lecp_nistz256_ord_sqr_montx:
+       push    %rbp
+.cfi_push      %rbp
+       push    %rbx
+.cfi_push      %rbx
        push    %r12
 .cfi_push      %r12
        push    %r13
 .cfi_push      %r13
-.Lsub_body:
+       push    %r14
+.cfi_push      %r14
+       push    %r15
+.cfi_push      %r15
+.Lord_sqrx_body:
 
-       mov     8*0($a_ptr), $a0
-       xor     $t4, $t4
-       mov     8*1($a_ptr), $a1
-       mov     8*2($a_ptr), $a2
-       mov     8*3($a_ptr), $a3
-       lea     .Lpoly(%rip), $a_ptr
+       mov     $b_org, $b_ptr
+       mov     8*0($a_ptr), %rdx
+       mov     8*1($a_ptr), $acc6
+       mov     8*2($a_ptr), $acc7
+       mov     8*3($a_ptr), $acc0
+       lea     .Lord(%rip), $a_ptr
+       jmp     .Loop_ord_sqrx
 
-       sub     8*0($b_ptr), $a0
-       sbb     8*1($b_ptr), $a1
-        mov    $a0, $t0
-       sbb     8*2($b_ptr), $a2
-       sbb     8*3($b_ptr), $a3
-        mov    $a1, $t1
-       sbb     \$0, $t4
+.align 32
+.Loop_ord_sqrx:
+       mulx    $acc6, $acc1, $acc2     # a[0]*a[1]
+       mulx    $acc7, $t0, $acc3       # a[0]*a[2]
+        mov    %rdx, %rax              # offload a[0]
+        movq   $acc6, %xmm1            # offload a[1]
+       mulx    $acc0, $t1, $acc4       # a[0]*a[3]
+        mov    $acc6, %rdx
+       add     $t0, $acc2
+        movq   $acc7, %xmm2            # offload a[2]
+       adc     $t1, $acc3
+       adc     \$0, $acc4
+       xor     $acc5, $acc5            # $acc5=0,cf=0,of=0
+       #################################
+       mulx    $acc7, $t0, $t1         # a[1]*a[2]
+       adcx    $t0, $acc3
+       adox    $t1, $acc4
 
-       add     8*0($a_ptr), $a0
-        mov    $a2, $t2
-       adc     8*1($a_ptr), $a1
-       adc     8*2($a_ptr), $a2
-        mov    $a3, $t3
-       adc     8*3($a_ptr), $a3
-       test    $t4, $t4
+       mulx    $acc0, $t0, $t1         # a[1]*a[3]
+        mov    $acc7, %rdx
+       adcx    $t0, $acc4
+       adox    $t1, $acc5
+       adc     \$0, $acc5
+       #################################
+       mulx    $acc0, $t0, $acc6       # a[2]*a[3]
+       mov     %rax, %rdx
+        movq   $acc0, %xmm3            # offload a[3]
+       xor     $acc7, $acc7            # $acc7=0,cf=0,of=0
+        adcx   $acc1, $acc1            # acc1:6<<1
+       adox    $t0, $acc5
+        adcx   $acc2, $acc2
+       adox    $acc7, $acc6            # of=0
 
-       cmovz   $t0, $a0
-       cmovz   $t1, $a1
-       mov     $a0, 8*0($r_ptr)
-       cmovz   $t2, $a2
-       mov     $a1, 8*1($r_ptr)
-       cmovz   $t3, $a3
-       mov     $a2, 8*2($r_ptr)
-       mov     $a3, 8*3($r_ptr)
+       ################################# a[i]*a[i]
+       mulx    %rdx, $acc0, $t1
+       movq    %xmm1, %rdx
+        adcx   $acc3, $acc3
+       adox    $t1, $acc1
+        adcx   $acc4, $acc4
+       mulx    %rdx, $t0, $t4
+       movq    %xmm2, %rdx
+        adcx   $acc5, $acc5
+       adox    $t0, $acc2
+        adcx   $acc6, $acc6
+       mulx    %rdx, $t0, $t1
+       .byte   0x67
+       movq    %xmm3, %rdx
+       adox    $t4, $acc3
+        adcx   $acc7, $acc7
+       adox    $t0, $acc4
+       adox    $t1, $acc5
+       mulx    %rdx, $t0, $t4
+       adox    $t0, $acc6
+       adox    $t4, $acc7
 
-       mov     0(%rsp),%r13
-.cfi_restore   %r13
-       mov     8(%rsp),%r12
-.cfi_restore   %r12
-       lea     16(%rsp),%rsp
-.cfi_adjust_cfa_offset -16
-.Lsub_epilogue:
-       ret
-.cfi_endproc
-.size  ecp_nistz256_sub,.-ecp_nistz256_sub
+       ################################# reduction
+       mov     $acc0, %rdx
+       mulx    8*4($a_ptr), %rdx, $t0
 
-################################################################################
-# void ecp_nistz256_neg(uint64_t res[4], uint64_t a[4]);
-.globl ecp_nistz256_neg
-.type  ecp_nistz256_neg,\@function,2
-.align 32
-ecp_nistz256_neg:
-.cfi_startproc
-       push    %r12
-.cfi_push      %r12
-       push    %r13
-.cfi_push      %r13
-.Lneg_body:
+       xor     %rax, %rax              # cf=0, of=0
+       mulx    8*0($a_ptr), $t0, $t1
+       adcx    $t0, $acc0              # guaranteed to be zero
+       adox    $t1, $acc1
+       mulx    8*1($a_ptr), $t0, $t1
+       adcx    $t0, $acc1
+       adox    $t1, $acc2
+       mulx    8*2($a_ptr), $t0, $t1
+       adcx    $t0, $acc2
+       adox    $t1, $acc3
+       mulx    8*3($a_ptr), $t0, $t1
+       adcx    $t0, $acc3
+       adox    $t1, $acc0              # of=0
+       adcx    %rax, $acc0             # cf=0
 
-       xor     $a0, $a0
-       xor     $a1, $a1
-       xor     $a2, $a2
-       xor     $a3, $a3
-       xor     $t4, $t4
+       #################################
+       mov     $acc1, %rdx
+       mulx    8*4($a_ptr), %rdx, $t0
 
-       sub     8*0($a_ptr), $a0
-       sbb     8*1($a_ptr), $a1
-       sbb     8*2($a_ptr), $a2
-        mov    $a0, $t0
-       sbb     8*3($a_ptr), $a3
-       lea     .Lpoly(%rip), $a_ptr
-        mov    $a1, $t1
-       sbb     \$0, $t4
+       mulx    8*0($a_ptr), $t0, $t1
+       adox    $t0, $acc1              # guaranteed to be zero
+       adcx    $t1, $acc2
+       mulx    8*1($a_ptr), $t0, $t1
+       adox    $t0, $acc2
+       adcx    $t1, $acc3
+       mulx    8*2($a_ptr), $t0, $t1
+       adox    $t0, $acc3
+       adcx    $t1, $acc0
+       mulx    8*3($a_ptr), $t0, $t1
+       adox    $t0, $acc0
+       adcx    $t1, $acc1              # cf=0
+       adox    %rax, $acc1             # of=0
 
-       add     8*0($a_ptr), $a0
-        mov    $a2, $t2
-       adc     8*1($a_ptr), $a1
-       adc     8*2($a_ptr), $a2
-        mov    $a3, $t3
-       adc     8*3($a_ptr), $a3
-       test    $t4, $t4
+       #################################
+       mov     $acc2, %rdx
+       mulx    8*4($a_ptr), %rdx, $t0
 
-       cmovz   $t0, $a0
-       cmovz   $t1, $a1
-       mov     $a0, 8*0($r_ptr)
-       cmovz   $t2, $a2
-       mov     $a1, 8*1($r_ptr)
-       cmovz   $t3, $a3
-       mov     $a2, 8*2($r_ptr)
-       mov     $a3, 8*3($r_ptr)
+       mulx    8*0($a_ptr), $t0, $t1
+       adcx    $t0, $acc2              # guaranteed to be zero
+       adox    $t1, $acc3
+       mulx    8*1($a_ptr), $t0, $t1
+       adcx    $t0, $acc3
+       adox    $t1, $acc0
+       mulx    8*2($a_ptr), $t0, $t1
+       adcx    $t0, $acc0
+       adox    $t1, $acc1
+       mulx    8*3($a_ptr), $t0, $t1
+       adcx    $t0, $acc1
+       adox    $t1, $acc2              # of=0
+       adcx    %rax, $acc2             # cf=0
 
-       mov     0(%rsp),%r13
+       #################################
+       mov     $acc3, %rdx
+       mulx    8*4($a_ptr), %rdx, $t0
+
+       mulx    8*0($a_ptr), $t0, $t1
+       adox    $t0, $acc3              # guaranteed to be zero
+       adcx    $t1, $acc0
+       mulx    8*1($a_ptr), $t0, $t1
+       adox    $t0, $acc0
+       adcx    $t1, $acc1
+       mulx    8*2($a_ptr), $t0, $t1
+       adox    $t0, $acc1
+       adcx    $t1, $acc2
+       mulx    8*3($a_ptr), $t0, $t1
+       adox    $t0, $acc2
+       adcx    $t1, $acc3
+       adox    %rax, $acc3
+
+       ################################# accumulate upper half
+       add     $acc0, $acc4            # add   $acc4, $acc0
+       adc     $acc5, $acc1
+        mov    $acc4, %rdx
+       adc     $acc6, $acc2
+       adc     $acc7, $acc3
+        mov    $acc1, $acc6
+       adc     \$0, %rax
+
+       ################################# compare to modulus
+       sub     8*0($a_ptr), $acc4
+        mov    $acc2, $acc7
+       sbb     8*1($a_ptr), $acc1
+       sbb     8*2($a_ptr), $acc2
+        mov    $acc3, $acc0
+       sbb     8*3($a_ptr), $acc3
+       sbb     \$0, %rax
+
+       cmovnc  $acc4, %rdx
+       cmovnc  $acc1, $acc6
+       cmovnc  $acc2, $acc7
+       cmovnc  $acc3, $acc0
+
+       dec     $b_ptr
+       jnz     .Loop_ord_sqrx
+
+       mov     %rdx, 8*0($r_ptr)
+       mov     $acc6, 8*1($r_ptr)
+       pxor    %xmm1, %xmm1
+       mov     $acc7, 8*2($r_ptr)
+       pxor    %xmm2, %xmm2
+       mov     $acc0, 8*3($r_ptr)
+       pxor    %xmm3, %xmm3
+
+       mov     0(%rsp),%r15
+.cfi_restore   %r15
+       mov     8(%rsp),%r14
+.cfi_restore   %r14
+       mov     16(%rsp),%r13
 .cfi_restore   %r13
-       mov     8(%rsp),%r12
+       mov     24(%rsp),%r12
 .cfi_restore   %r12
-       lea     16(%rsp),%rsp
-.cfi_adjust_cfa_offset -16
-.Lneg_epilogue:
+       mov     32(%rsp),%rbx
+.cfi_restore   %rbx
+       mov     40(%rsp),%rbp
+.cfi_restore   %rbp
+       lea     48(%rsp),%rsp
+.cfi_adjust_cfa_offset -48
+.Lord_sqrx_epilogue:
        ret
 .cfi_endproc
-.size  ecp_nistz256_neg,.-ecp_nistz256_neg
+.size  ecp_nistz256_ord_sqr_montx,.-ecp_nistz256_ord_sqr_montx
 ___
-}
-{
-my ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
-my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
-my ($t0,$t1,$t2,$t3,$t4)=("%rcx","%rbp","%rbx","%rdx","%rax");
-my ($poly1,$poly3)=($acc6,$acc7);
 
 $code.=<<___;
 ################################################################################
@@ -3366,6 +4455,24 @@ full_handler:
        .rva    .LSEH_end_ecp_nistz256_neg
        .rva    .LSEH_info_ecp_nistz256_neg
 
+       .rva    .LSEH_begin_ecp_nistz256_ord_mul_mont
+       .rva    .LSEH_end_ecp_nistz256_ord_mul_mont
+       .rva    .LSEH_info_ecp_nistz256_ord_mul_mont
+
+       .rva    .LSEH_begin_ecp_nistz256_ord_sqr_mont
+       .rva    .LSEH_end_ecp_nistz256_ord_sqr_mont
+       .rva    .LSEH_info_ecp_nistz256_ord_sqr_mont
+___
+$code.=<<___   if ($addx);
+       .rva    .LSEH_begin_ecp_nistz256_ord_mul_montx
+       .rva    .LSEH_end_ecp_nistz256_ord_mul_montx
+       .rva    .LSEH_info_ecp_nistz256_ord_mul_montx
+
+       .rva    .LSEH_begin_ecp_nistz256_ord_sqr_montx
+       .rva    .LSEH_end_ecp_nistz256_ord_sqr_montx
+       .rva    .LSEH_info_ecp_nistz256_ord_sqr_montx
+___
+$code.=<<___;
        .rva    .LSEH_begin_ecp_nistz256_to_mont
        .rva    .LSEH_end_ecp_nistz256_to_mont
        .rva    .LSEH_info_ecp_nistz256_to_mont
@@ -3453,6 +4560,30 @@ $code.=<<___;
        .byte   9,0,0,0
        .rva    short_handler
        .rva    .Lneg_body,.Lneg_epilogue               # HandlerData[]
+.LSEH_info_ecp_nistz256_ord_mul_mont:
+       .byte   9,0,0,0
+       .rva    full_handler
+       .rva    .Lord_mul_body,.Lord_mul_epilogue       # HandlerData[]
+       .long   48,0
+.LSEH_info_ecp_nistz256_ord_sqr_mont:
+       .byte   9,0,0,0
+       .rva    full_handler
+       .rva    .Lord_sqr_body,.Lord_sqr_epilogue       # HandlerData[]
+       .long   48,0
+___
+$code.=<<___ if ($addx);
+.LSEH_info_ecp_nistz256_ord_mul_montx:
+       .byte   9,0,0,0
+       .rva    full_handler
+       .rva    .Lord_mulx_body,.Lord_mulx_epilogue     # HandlerData[]
+       .long   48,0
+.LSEH_info_ecp_nistz256_ord_sqr_montx:
+       .byte   9,0,0,0
+       .rva    full_handler
+       .rva    .Lord_sqrx_body,.Lord_sqrx_epilogue     # HandlerData[]
+       .long   48,0
+___
+$code.=<<___;
 .LSEH_info_ecp_nistz256_to_mont:
        .byte   9,0,0,0
        .rva    full_handler