[openssl-commits] [openssl] master update

Dr. Stephen Henson steve at openssl.org
Sun Feb 28 22:55:37 UTC 2016


The branch master has been updated
       via  71736242409da85aef5107167d44e601ee66841c (commit)
       via  5f7b0e1fdc2ba7971cf1817bae076ff55d4023d0 (commit)
       via  5697291f2dbf62650572d207e6062dc6b06f4928 (commit)
       via  0780daa03095254642f2b9e0a41e26cd253b865f (commit)
       via  244e5f5de6e6a6578328b396699aae83b1fe2c89 (commit)
       via  df3bde67918a1424aff1a441579866c687275310 (commit)
       via  a90def6b537af2de72e84c2d776c318d4bb4511a (commit)
       via  1db3107ada6a93140b6b7deb59346b1c14e0adb8 (commit)
       via  db50c1da199145e0427ec5d3e457d5c2249cc078 (commit)
       via  4a5bbc4ef57e21ac7b2f000c2dcbe86e01b2a882 (commit)
       via  755031d921add2e1261dec6c13bb85b0f20c77ca (commit)
       via  af4f2ad9dd7d7a5f5b3fd64d1ffa14a4eb59216a (commit)
       via  4b0555ec9d322abec2ddf769387e1228dc9a440b (commit)
       via  8dcfdbf510085fd5740abe78f1f8ca120b475f05 (commit)
       via  e5b2ea0ac3b4d752847d197117d58e0f6ad8e08e (commit)
       via  3e8ee4753c78556a83b7bc08d522c08f0d8808c1 (commit)
       via  6ea04154dc17c37083717d8a8bb86f4bc9f0dee5 (commit)
       via  6903e2e7e9a47bb350920ae640287cf9f43a22ce (commit)
       via  474d84ec81d6926698d27a2cbbbbe2961ecf6541 (commit)
       via  899cf48f17ba95a7bd986bbeffeebf9a1d9fd3fb (commit)
      from  17fa4e8eda466dc36fd0c332bb7adc4f331dd480 (commit)


- Log -----------------------------------------------------------------
commit 71736242409da85aef5107167d44e601ee66841c
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sun Feb 28 22:43:30 2016 +0000

    Add CHANGES entry for X25519
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 5f7b0e1fdc2ba7971cf1817bae076ff55d4023d0
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sun Feb 28 18:00:46 2016 +0000

    make update
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 5697291f2dbf62650572d207e6062dc6b06f4928
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sun Feb 21 16:22:43 2016 +0000

    Remove unused code.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 0780daa03095254642f2b9e0a41e26cd253b865f
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Feb 20 14:24:06 2016 +0000

    Change BORINGSSL defines to OPENSSL
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 244e5f5de6e6a6578328b396699aae83b1fe2c89
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Feb 20 14:19:28 2016 +0000

    Initial adaptations for Curve25519 code.
    
    Fix "mixed declarations and code" warnings.
    Use OpenSSL headers.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit df3bde67918a1424aff1a441579866c687275310
Author: Emilia Kasper <emilia at openssl.org>
Date:   Wed Feb 24 16:18:10 2016 +0000

    Place under OpenSSL license.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Stephen Henson <steve at openssl.org>

commit a90def6b537af2de72e84c2d776c318d4bb4511a
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Feb 20 13:56:47 2016 +0000

    Add X25519 code from BoringSSL.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 1db3107ada6a93140b6b7deb59346b1c14e0adb8
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Thu Feb 25 17:46:14 2016 +0000

    TLS support for X25519
    
    Add X25519 to TLS supported curve list.
    Reject attempts to configure keys which cannot be used
    for signing.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit db50c1da199145e0427ec5d3e457d5c2249cc078
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Feb 12 14:11:47 2016 +0000

    add ecdhx25519 option to speed
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 4a5bbc4ef57e21ac7b2f000c2dcbe86e01b2a882
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Feb 23 14:35:33 2016 +0000

    skip inappropriate X25519 tests
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 755031d921add2e1261dec6c13bb85b0f20c77ca
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Feb 2 19:07:18 2016 +0000

    Add X25519 test vectors from RFC7748 6.1
    Check sign/verify blocked with X25519
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit af4f2ad9dd7d7a5f5b3fd64d1ffa14a4eb59216a
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Feb 2 15:23:00 2016 +0000

    Add X25519 curve to list
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 4b0555ec9d322abec2ddf769387e1228dc9a440b
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Feb 23 15:02:34 2016 +0000

    Add no signing flag.
    
    Add a flag to EC_METHOD for curves which do not support signing.
    New function EC_KEY_can_sign() returns 1 is key can be used for signing.
    Return an explicit error is an attempt is made to sign with
    no signing curves.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 8dcfdbf510085fd5740abe78f1f8ca120b475f05
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Feb 2 14:50:10 2016 +0000

    Add new EC_METHOD for X25519.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit e5b2ea0ac3b4d752847d197117d58e0f6ad8e08e
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 1 18:52:41 2016 +0000

    Add group_order_bits to EC_METHOD.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 3e8ee4753c78556a83b7bc08d522c08f0d8808c1
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 1 18:22:35 2016 +0000

    Add custom_data field for EC_POINT, EC_KEY.
    
    In some cases the EC_POINT and EC_KEY BIGNUM components are suboptimal
    or inappropriate. Add an "custom_data" field which curves can populate with
    a custom structure to suit their needs.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 6ea04154dc17c37083717d8a8bb86f4bc9f0dee5
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed Feb 17 15:05:27 2016 +0000

    Extract compression form in EC_KEY_oct2key().
    
    Extract compression form in EC_KEY_oct2key() instead of manually in the
    ASN.1 code. For custom curves do not assume the initial octet is the
    compression form: it isn't for X25519 et al.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 6903e2e7e9a47bb350920ae640287cf9f43a22ce
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 1 18:15:57 2016 +0000

    Extended EC_METHOD customisation support.
    
    Add support for optional overrides of various private key operations
    in EC_METHOD.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 474d84ec81d6926698d27a2cbbbbe2961ecf6541
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 1 17:57:01 2016 +0000

    EC_METHOD customisation operations.
    
    Extend EC_METHOD to permit additional customisation of private key and
    ECDH operations.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

commit 899cf48f17ba95a7bd986bbeffeebf9a1d9fd3fb
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Feb 22 14:27:09 2016 +0000

    Rename OIDs.
    
    Use standard X25519 and X448 names for OIDs. Delete EdDSA OIDs: for now they
    wont be used and EdDSA may use a different format.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Emilia Käsper <emilia at openssl.org>

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                    |   16 +
 apps/speed.c               |   16 +-
 crypto/ec/Makefile.in      |    5 +-
 crypto/ec/build.info       |    3 +-
 crypto/ec/curve25519.c     | 3592 ++++++++++++++++++++++++++++++++++++++++++++
 crypto/ec/ec2_smpl.c       |    1 +
 crypto/ec/ec_25519.c       |  381 +++++
 crypto/ec/ec_asn1.c        |   35 +-
 crypto/ec/ec_check.c       |    4 +
 crypto/ec/ec_curve.c       |    5 +
 crypto/ec/ec_err.c         |    3 +-
 crypto/ec/ec_key.c         |   45 +-
 crypto/ec/ec_lcl.h         |   39 +
 crypto/ec/ec_lib.c         |   28 +-
 crypto/ec/ecdh_ossl.c      |    4 +
 crypto/ec/ecdsa_ossl.c     |   15 +
 crypto/ec/ecp_mont.c       |    1 +
 crypto/ec/ecp_nist.c       |    1 +
 crypto/ec/ecp_nistp224.c   |    1 +
 crypto/ec/ecp_nistp256.c   |    1 +
 crypto/ec/ecp_nistp521.c   |    1 +
 crypto/ec/ecp_nistz256.c   |    1 +
 crypto/ec/ecp_smpl.c       |    1 +
 crypto/objects/obj_dat.h   |   40 +-
 crypto/objects/obj_mac.num |    6 +-
 crypto/objects/objects.txt |    6 +-
 include/openssl/ec.h       |    7 +
 include/openssl/obj_mac.h  |   20 +-
 ssl/ssl_rsa.c              |    5 +
 ssl/t1_lib.c               |   10 +-
 test/ecdhtest.c            |    7 +
 test/ecdsatest.c           |    2 +-
 test/ectest.c              |    6 +
 test/evptests.txt          |   42 +
 util/libeay.num            |    1 +
 35 files changed, 4258 insertions(+), 93 deletions(-)
 create mode 100644 crypto/ec/curve25519.c
 create mode 100644 crypto/ec/ec_25519.c

diff --git a/CHANGES b/CHANGES
index e0ac799..41926e9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,22 @@
 
  Changes between 1.0.2f and 1.1.0  [xx XXX xxxx]
 
+  *) Add X25519 support.
+     Integrate support for X25519 into EC library. This includes support
+     for public and private key encoding using the format documented in
+     draft-josefsson-pkix-newcurves-01: specifically X25519 uses the
+     OID from that draft, encodes public keys using little endian
+     format in the ECPoint structure and private keys using
+     little endian form in the privateKey field of the ECPrivateKey
+     structure. TLS support complies with draft-ietf-tls-rfc4492bis-06
+     and uses X25519(29).
+
+     Note: the current version supports key generation, public and
+     private key encoding and ECDH key agreement using the EC API.
+     Low level point operations such as EC_POINT_add(), EC_POINT_mul()
+     are NOT supported.
+     [Steve Henson]
+
   *) Deprecate SRP_VBASE_get_by_user.
      SRP_VBASE_get_by_user had inconsistent memory management behaviour.
      In order to fix an unavoidable memory leak (CVE-2016-0798),
diff --git a/apps/speed.c b/apps/speed.c
index 64faef5..97d8e56 100644
--- a/apps/speed.c
+++ b/apps/speed.c
@@ -201,8 +201,8 @@ static int do_multi(int multi);
 #define RSA_NUM         7
 #define DSA_NUM         3
 
-#define EC_NUM       16
-#define MAX_ECDH_SIZE 256
+#define EC_NUM          17
+#define MAX_ECDH_SIZE   256
 #define MISALIGN        64
 
 static const char *names[ALGOR_NUM] = {
@@ -509,6 +509,7 @@ static OPT_PAIR rsa_choices[] = {
 #define R_EC_B283    13
 #define R_EC_B409    14
 #define R_EC_B571    15
+#define R_EC_X25519  16
 #ifndef OPENSSL_NO_EC
 static OPT_PAIR ecdsa_choices[] = {
     {"ecdsap160", R_EC_P160},
@@ -546,6 +547,7 @@ static OPT_PAIR ecdh_choices[] = {
     {"ecdhb283", R_EC_B283},
     {"ecdhb409", R_EC_B409},
     {"ecdhb571", R_EC_B571},
+    {"ecdhx25519", R_EC_X25519},
     {NULL}
 };
 #endif
@@ -705,7 +707,9 @@ int speed_main(int argc, char **argv)
         NID_sect163k1, NID_sect233k1, NID_sect283k1,
         NID_sect409k1, NID_sect571k1, NID_sect163r2,
         NID_sect233r1, NID_sect283r1, NID_sect409r1,
-        NID_sect571r1
+        NID_sect571r1,
+        /* Other */
+        NID_X25519
     };
     static const char *test_curves_names[EC_NUM] = {
         /* Prime Curves */
@@ -715,7 +719,9 @@ int speed_main(int argc, char **argv)
         "nistk163", "nistk233", "nistk283",
         "nistk409", "nistk571", "nistb163",
         "nistb233", "nistb283", "nistb409",
-        "nistb571"
+        "nistb571",
+        /* Other */
+        "X25519"
     };
     static int test_curves_bits[EC_NUM] = {
         160, 192, 224,
@@ -723,7 +729,7 @@ int speed_main(int argc, char **argv)
         163, 233, 283,
         409, 571, 163,
         233, 283, 409,
-        571
+        571, 253 /* X25519 */
     };
 #endif
 #ifndef OPENSSL_NO_EC
diff --git a/crypto/ec/Makefile.in b/crypto/ec/Makefile.in
index 1aa22d4..decc174 100644
--- a/crypto/ec/Makefile.in
+++ b/crypto/ec/Makefile.in
@@ -22,14 +22,15 @@ LIBSRC=	ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c\
 	ec2_smpl.c ec2_mult.c ec_ameth.c ec_pmeth.c eck_prn.c \
 	ecp_nistp224.c ecp_nistp256.c ecp_nistp521.c ecp_nistputil.c \
 	ecp_oct.c ec2_oct.c ec_oct.c ec_kmeth.c ecdh_ossl.c ecdh_kdf.c \
-	ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c
+	ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c ec_25519.c curve25519.c
 
 LIBOBJ=	ec_lib.o ecp_smpl.o ecp_mont.o ecp_nist.o ec_cvt.o ec_mult.o\
 	ec_err.o ec_curve.o ec_check.o ec_print.o ec_asn1.o ec_key.o\
 	ec2_smpl.o ec2_mult.o ec_ameth.o ec_pmeth.o eck_prn.o \
 	ecp_nistp224.o ecp_nistp256.o ecp_nistp521.o ecp_nistputil.o \
 	ecp_oct.o ec2_oct.o ec_oct.o ec_kmeth.o ecdh_ossl.o ecdh_kdf.o \
-	ecdsa_ossl.o ecdsa_sign.o ecdsa_vrf.o $(EC_ASM)
+	ecdsa_ossl.o ecdsa_sign.o ecdsa_vrf.o ec_25519.o curve25519.o \
+	$(EC_ASM)
 
 SRC= $(LIBSRC)
 
diff --git a/crypto/ec/build.info b/crypto/ec/build.info
index 63ad9a4..39a9f47 100644
--- a/crypto/ec/build.info
+++ b/crypto/ec/build.info
@@ -5,7 +5,8 @@ SOURCE[../../libcrypto]=\
         ec2_smpl.c ec2_mult.c ec_ameth.c ec_pmeth.c eck_prn.c \
         ecp_nistp224.c ecp_nistp256.c ecp_nistp521.c ecp_nistputil.c \
         ecp_oct.c ec2_oct.c ec_oct.c ec_kmeth.c ecdh_ossl.c ecdh_kdf.c \
-        ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c {- $target{ec_asm_src} -}
+        ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c ec_25519.c curve25519.c \
+        {- $target{ec_asm_src} -}
 
 BEGINRAW[Makefile]
 {- $builddir -}/ecp_nistz256-x86.s:	{- $sourcedir -}/asm/ecp_nistz256-x86.pl
diff --git a/crypto/ec/curve25519.c b/crypto/ec/curve25519.c
new file mode 100644
index 0000000..b20834c
--- /dev/null
+++ b/crypto/ec/curve25519.c
@@ -0,0 +1,3592 @@
+/* ====================================================================
+ * Copyright (c) 2016 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing at OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
+ * 20141124 (http://bench.cr.yp.to/supercop.html).
+ *
+ * The field functions are shared by Ed25519 and X25519 where possible. */
+
+#include <string.h>
+#include "ec_lcl.h"
+
+
+/* fe means field element. Here the field is \Z/(2^255-19). An element t,
+ * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+ * t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
+ * context.  */
+typedef int32_t fe[10];
+
+static uint64_t load_3(const uint8_t *in) {
+  uint64_t result;
+  result = (uint64_t)in[0];
+  result |= ((uint64_t)in[1]) << 8;
+  result |= ((uint64_t)in[2]) << 16;
+  return result;
+}
+
+static uint64_t load_4(const uint8_t *in) {
+  uint64_t result;
+  result = (uint64_t)in[0];
+  result |= ((uint64_t)in[1]) << 8;
+  result |= ((uint64_t)in[2]) << 16;
+  result |= ((uint64_t)in[3]) << 24;
+  return result;
+}
+
+static void fe_frombytes(fe h, const uint8_t *s) {
+  /* Ignores top bit of h. */
+  int64_t h0 = load_4(s);
+  int64_t h1 = load_3(s + 4) << 6;
+  int64_t h2 = load_3(s + 7) << 5;
+  int64_t h3 = load_3(s + 10) << 3;
+  int64_t h4 = load_3(s + 13) << 2;
+  int64_t h5 = load_4(s + 16);
+  int64_t h6 = load_3(s + 20) << 7;
+  int64_t h7 = load_3(s + 23) << 5;
+  int64_t h8 = load_3(s + 26) << 4;
+  int64_t h9 = (load_3(s + 29) & 8388607) << 2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* Preconditions:
+ *  |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+ *
+ * Write p=2^255-19; q=floor(h/p).
+ * Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+ *
+ * Proof:
+ *   Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+ *   Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+ *
+ *   Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+ *   Then 0<y<1.
+ *
+ *   Write r=h-pq.
+ *   Have 0<=r<=p-1=2^255-20.
+ *   Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+ *
+ *   Write x=r+19(2^-255)r+y.
+ *   Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+ *
+ *   Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+ *   so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q. */
+static void fe_tobytes(uint8_t *s, const fe h) {
+  int32_t h0 = h[0];
+  int32_t h1 = h[1];
+  int32_t h2 = h[2];
+  int32_t h3 = h[3];
+  int32_t h4 = h[4];
+  int32_t h5 = h[5];
+  int32_t h6 = h[6];
+  int32_t h7 = h[7];
+  int32_t h8 = h[8];
+  int32_t h9 = h[9];
+  int32_t q;
+  int32_t carry0;
+  int32_t carry1;
+  int32_t carry2;
+  int32_t carry3;
+  int32_t carry4;
+  int32_t carry5;
+  int32_t carry6;
+  int32_t carry7;
+  int32_t carry8;
+  int32_t carry9;
+
+  q = (19 * h9 + (((int32_t) 1) << 24)) >> 25;
+  q = (h0 + q) >> 26;
+  q = (h1 + q) >> 25;
+  q = (h2 + q) >> 26;
+  q = (h3 + q) >> 25;
+  q = (h4 + q) >> 26;
+  q = (h5 + q) >> 25;
+  q = (h6 + q) >> 26;
+  q = (h7 + q) >> 25;
+  q = (h8 + q) >> 26;
+  q = (h9 + q) >> 25;
+
+  /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+  h0 += 19 * q;
+  /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+  carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+  carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+  carry9 = h9 >> 25;               h9 -= carry9 << 25;
+                  /* h10 = carry9 */
+
+  /* Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+   * Have h0+...+2^230 h9 between 0 and 2^255-1;
+   * evidently 2^255 h10-2^255 q = 0.
+   * Goal: Output h0+...+2^230 h9.  */
+
+  s[0] = h0 >> 0;
+  s[1] = h0 >> 8;
+  s[2] = h0 >> 16;
+  s[3] = (h0 >> 24) | (h1 << 2);
+  s[4] = h1 >> 6;
+  s[5] = h1 >> 14;
+  s[6] = (h1 >> 22) | (h2 << 3);
+  s[7] = h2 >> 5;
+  s[8] = h2 >> 13;
+  s[9] = (h2 >> 21) | (h3 << 5);
+  s[10] = h3 >> 3;
+  s[11] = h3 >> 11;
+  s[12] = (h3 >> 19) | (h4 << 6);
+  s[13] = h4 >> 2;
+  s[14] = h4 >> 10;
+  s[15] = h4 >> 18;
+  s[16] = h5 >> 0;
+  s[17] = h5 >> 8;
+  s[18] = h5 >> 16;
+  s[19] = (h5 >> 24) | (h6 << 1);
+  s[20] = h6 >> 7;
+  s[21] = h6 >> 15;
+  s[22] = (h6 >> 23) | (h7 << 3);
+  s[23] = h7 >> 5;
+  s[24] = h7 >> 13;
+  s[25] = (h7 >> 21) | (h8 << 4);
+  s[26] = h8 >> 4;
+  s[27] = h8 >> 12;
+  s[28] = (h8 >> 20) | (h9 << 6);
+  s[29] = h9 >> 2;
+  s[30] = h9 >> 10;
+  s[31] = h9 >> 18;
+}
+
+/* h = f */
+static void fe_copy(fe h, const fe f) {
+  memmove(h, f, sizeof(int32_t) * 10);
+}
+
+/* h = 0 */
+static void fe_0(fe h) { memset(h, 0, sizeof(int32_t) * 10); }
+
+/* h = 1 */
+static void fe_1(fe h) {
+  memset(h, 0, sizeof(int32_t) * 10);
+  h[0] = 1;
+}
+
+/* h = f + g
+ * Can overlap h with f or g.
+ *
+ * Preconditions:
+ *    |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ *    |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ *
+ * Postconditions:
+ *    |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */
+static void fe_add(fe h, const fe f, const fe g) {
+  unsigned i;
+  for (i = 0; i < 10; i++) {
+    h[i] = f[i] + g[i];
+  }
+}
+
+/* h = f - g
+ * Can overlap h with f or g.
+ *
+ * Preconditions:
+ *    |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ *    |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ *
+ * Postconditions:
+ *    |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */
+static void fe_sub(fe h, const fe f, const fe g) {
+  unsigned i;
+  for (i = 0; i < 10; i++) {
+    h[i] = f[i] - g[i];
+  }
+}
+
+/* h = f * g
+ * Can overlap h with f or g.
+ *
+ * Preconditions:
+ *    |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+ *    |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+ *
+ * Postconditions:
+ *    |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+ *
+ * Notes on implementation strategy:
+ *
+ * Using schoolbook multiplication.
+ * Karatsuba would save a little in some cost models.
+ *
+ * Most multiplications by 2 and 19 are 32-bit precomputations;
+ * cheaper than 64-bit postcomputations.
+ *
+ * There is one remaining multiplication by 19 in the carry chain;
+ * one *19 precomputation can be merged into this,
+ * but the resulting data flow is considerably less clean.
+ *
+ * There are 12 carries below.
+ * 10 of them are 2-way parallelizable and vectorizable.
+ * Can get away with 11 carries, but then data flow is much deeper.
+ *
+ * With tighter constraints on inputs can squeeze carries into int32. */
+static void fe_mul(fe h, const fe f, const fe g) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t g0 = g[0];
+  int32_t g1 = g[1];
+  int32_t g2 = g[2];
+  int32_t g3 = g[3];
+  int32_t g4 = g[4];
+  int32_t g5 = g[5];
+  int32_t g6 = g[6];
+  int32_t g7 = g[7];
+  int32_t g8 = g[8];
+  int32_t g9 = g[9];
+  int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */
+  int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+  int32_t g3_19 = 19 * g3;
+  int32_t g4_19 = 19 * g4;
+  int32_t g5_19 = 19 * g5;
+  int32_t g6_19 = 19 * g6;
+  int32_t g7_19 = 19 * g7;
+  int32_t g8_19 = 19 * g8;
+  int32_t g9_19 = 19 * g9;
+  int32_t f1_2 = 2 * f1;
+  int32_t f3_2 = 2 * f3;
+  int32_t f5_2 = 2 * f5;
+  int32_t f7_2 = 2 * f7;
+  int32_t f9_2 = 2 * f9;
+  int64_t f0g0    = f0   * (int64_t) g0;
+  int64_t f0g1    = f0   * (int64_t) g1;
+  int64_t f0g2    = f0   * (int64_t) g2;
+  int64_t f0g3    = f0   * (int64_t) g3;
+  int64_t f0g4    = f0   * (int64_t) g4;
+  int64_t f0g5    = f0   * (int64_t) g5;
+  int64_t f0g6    = f0   * (int64_t) g6;
+  int64_t f0g7    = f0   * (int64_t) g7;
+  int64_t f0g8    = f0   * (int64_t) g8;
+  int64_t f0g9    = f0   * (int64_t) g9;
+  int64_t f1g0    = f1   * (int64_t) g0;
+  int64_t f1g1_2  = f1_2 * (int64_t) g1;
+  int64_t f1g2    = f1   * (int64_t) g2;
+  int64_t f1g3_2  = f1_2 * (int64_t) g3;
+  int64_t f1g4    = f1   * (int64_t) g4;
+  int64_t f1g5_2  = f1_2 * (int64_t) g5;
+  int64_t f1g6    = f1   * (int64_t) g6;
+  int64_t f1g7_2  = f1_2 * (int64_t) g7;
+  int64_t f1g8    = f1   * (int64_t) g8;
+  int64_t f1g9_38 = f1_2 * (int64_t) g9_19;
+  int64_t f2g0    = f2   * (int64_t) g0;
+  int64_t f2g1    = f2   * (int64_t) g1;
+  int64_t f2g2    = f2   * (int64_t) g2;
+  int64_t f2g3    = f2   * (int64_t) g3;
+  int64_t f2g4    = f2   * (int64_t) g4;
+  int64_t f2g5    = f2   * (int64_t) g5;
+  int64_t f2g6    = f2   * (int64_t) g6;
+  int64_t f2g7    = f2   * (int64_t) g7;
+  int64_t f2g8_19 = f2   * (int64_t) g8_19;
+  int64_t f2g9_19 = f2   * (int64_t) g9_19;
+  int64_t f3g0    = f3   * (int64_t) g0;
+  int64_t f3g1_2  = f3_2 * (int64_t) g1;
+  int64_t f3g2    = f3   * (int64_t) g2;
+  int64_t f3g3_2  = f3_2 * (int64_t) g3;
+  int64_t f3g4    = f3   * (int64_t) g4;
+  int64_t f3g5_2  = f3_2 * (int64_t) g5;
+  int64_t f3g6    = f3   * (int64_t) g6;
+  int64_t f3g7_38 = f3_2 * (int64_t) g7_19;
+  int64_t f3g8_19 = f3   * (int64_t) g8_19;
+  int64_t f3g9_38 = f3_2 * (int64_t) g9_19;
+  int64_t f4g0    = f4   * (int64_t) g0;
+  int64_t f4g1    = f4   * (int64_t) g1;
+  int64_t f4g2    = f4   * (int64_t) g2;
+  int64_t f4g3    = f4   * (int64_t) g3;
+  int64_t f4g4    = f4   * (int64_t) g4;
+  int64_t f4g5    = f4   * (int64_t) g5;
+  int64_t f4g6_19 = f4   * (int64_t) g6_19;
+  int64_t f4g7_19 = f4   * (int64_t) g7_19;
+  int64_t f4g8_19 = f4   * (int64_t) g8_19;
+  int64_t f4g9_19 = f4   * (int64_t) g9_19;
+  int64_t f5g0    = f5   * (int64_t) g0;
+  int64_t f5g1_2  = f5_2 * (int64_t) g1;
+  int64_t f5g2    = f5   * (int64_t) g2;
+  int64_t f5g3_2  = f5_2 * (int64_t) g3;
+  int64_t f5g4    = f5   * (int64_t) g4;
+  int64_t f5g5_38 = f5_2 * (int64_t) g5_19;
+  int64_t f5g6_19 = f5   * (int64_t) g6_19;
+  int64_t f5g7_38 = f5_2 * (int64_t) g7_19;
+  int64_t f5g8_19 = f5   * (int64_t) g8_19;
+  int64_t f5g9_38 = f5_2 * (int64_t) g9_19;
+  int64_t f6g0    = f6   * (int64_t) g0;
+  int64_t f6g1    = f6   * (int64_t) g1;
+  int64_t f6g2    = f6   * (int64_t) g2;
+  int64_t f6g3    = f6   * (int64_t) g3;
+  int64_t f6g4_19 = f6   * (int64_t) g4_19;
+  int64_t f6g5_19 = f6   * (int64_t) g5_19;
+  int64_t f6g6_19 = f6   * (int64_t) g6_19;
+  int64_t f6g7_19 = f6   * (int64_t) g7_19;
+  int64_t f6g8_19 = f6   * (int64_t) g8_19;
+  int64_t f6g9_19 = f6   * (int64_t) g9_19;
+  int64_t f7g0    = f7   * (int64_t) g0;
+  int64_t f7g1_2  = f7_2 * (int64_t) g1;
+  int64_t f7g2    = f7   * (int64_t) g2;
+  int64_t f7g3_38 = f7_2 * (int64_t) g3_19;
+  int64_t f7g4_19 = f7   * (int64_t) g4_19;
+  int64_t f7g5_38 = f7_2 * (int64_t) g5_19;
+  int64_t f7g6_19 = f7   * (int64_t) g6_19;
+  int64_t f7g7_38 = f7_2 * (int64_t) g7_19;
+  int64_t f7g8_19 = f7   * (int64_t) g8_19;
+  int64_t f7g9_38 = f7_2 * (int64_t) g9_19;
+  int64_t f8g0    = f8   * (int64_t) g0;
+  int64_t f8g1    = f8   * (int64_t) g1;
+  int64_t f8g2_19 = f8   * (int64_t) g2_19;
+  int64_t f8g3_19 = f8   * (int64_t) g3_19;
+  int64_t f8g4_19 = f8   * (int64_t) g4_19;
+  int64_t f8g5_19 = f8   * (int64_t) g5_19;
+  int64_t f8g6_19 = f8   * (int64_t) g6_19;
+  int64_t f8g7_19 = f8   * (int64_t) g7_19;
+  int64_t f8g8_19 = f8   * (int64_t) g8_19;
+  int64_t f8g9_19 = f8   * (int64_t) g9_19;
+  int64_t f9g0    = f9   * (int64_t) g0;
+  int64_t f9g1_38 = f9_2 * (int64_t) g1_19;
+  int64_t f9g2_19 = f9   * (int64_t) g2_19;
+  int64_t f9g3_38 = f9_2 * (int64_t) g3_19;
+  int64_t f9g4_19 = f9   * (int64_t) g4_19;
+  int64_t f9g5_38 = f9_2 * (int64_t) g5_19;
+  int64_t f9g6_19 = f9   * (int64_t) g6_19;
+  int64_t f9g7_38 = f9_2 * (int64_t) g7_19;
+  int64_t f9g8_19 = f9   * (int64_t) g8_19;
+  int64_t f9g9_38 = f9_2 * (int64_t) g9_19;
+  int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+  int64_t h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+  int64_t h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+  int64_t h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+  int64_t h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+  int64_t h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+  int64_t h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
+  int64_t h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
+  int64_t h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
+  int64_t h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  /* |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+   *   i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+   * |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+   *   i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 */
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  /* |h0| <= 2^25 */
+  /* |h4| <= 2^25 */
+  /* |h1| <= 1.71*2^59 */
+  /* |h5| <= 1.71*2^59 */
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  /* |h1| <= 2^24; from now on fits into int32 */
+  /* |h5| <= 2^24; from now on fits into int32 */
+  /* |h2| <= 1.41*2^60 */
+  /* |h6| <= 1.41*2^60 */
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  /* |h2| <= 2^25; from now on fits into int32 unchanged */
+  /* |h6| <= 2^25; from now on fits into int32 unchanged */
+  /* |h3| <= 1.71*2^59 */
+  /* |h7| <= 1.71*2^59 */
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+  /* |h3| <= 2^24; from now on fits into int32 unchanged */
+  /* |h7| <= 2^24; from now on fits into int32 unchanged */
+  /* |h4| <= 1.72*2^34 */
+  /* |h8| <= 1.41*2^60 */
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+  /* |h4| <= 2^25; from now on fits into int32 unchanged */
+  /* |h8| <= 2^25; from now on fits into int32 unchanged */
+  /* |h5| <= 1.01*2^24 */
+  /* |h9| <= 1.71*2^59 */
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  /* |h9| <= 2^24; from now on fits into int32 unchanged */
+  /* |h0| <= 1.1*2^39 */
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  /* |h0| <= 2^25; from now on fits into int32 unchanged */
+  /* |h1| <= 1.01*2^24 */
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* h = f * f
+ * Can overlap h with f.
+ *
+ * Preconditions:
+ *    |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+ *
+ * Postconditions:
+ *    |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+ *
+ * See fe_mul.c for discussion of implementation strategy. */
+static void fe_sq(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t f0_2 = 2 * f0;
+  int32_t f1_2 = 2 * f1;
+  int32_t f2_2 = 2 * f2;
+  int32_t f3_2 = 2 * f3;
+  int32_t f4_2 = 2 * f4;
+  int32_t f5_2 = 2 * f5;
+  int32_t f6_2 = 2 * f6;
+  int32_t f7_2 = 2 * f7;
+  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+  int64_t f0f0    = f0   * (int64_t) f0;
+  int64_t f0f1_2  = f0_2 * (int64_t) f1;
+  int64_t f0f2_2  = f0_2 * (int64_t) f2;
+  int64_t f0f3_2  = f0_2 * (int64_t) f3;
+  int64_t f0f4_2  = f0_2 * (int64_t) f4;
+  int64_t f0f5_2  = f0_2 * (int64_t) f5;
+  int64_t f0f6_2  = f0_2 * (int64_t) f6;
+  int64_t f0f7_2  = f0_2 * (int64_t) f7;
+  int64_t f0f8_2  = f0_2 * (int64_t) f8;
+  int64_t f0f9_2  = f0_2 * (int64_t) f9;
+  int64_t f1f1_2  = f1_2 * (int64_t) f1;
+  int64_t f1f2_2  = f1_2 * (int64_t) f2;
+  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+  int64_t f1f4_2  = f1_2 * (int64_t) f4;
+  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+  int64_t f1f6_2  = f1_2 * (int64_t) f6;
+  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+  int64_t f1f8_2  = f1_2 * (int64_t) f8;
+  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+  int64_t f2f2    = f2   * (int64_t) f2;
+  int64_t f2f3_2  = f2_2 * (int64_t) f3;
+  int64_t f2f4_2  = f2_2 * (int64_t) f4;
+  int64_t f2f5_2  = f2_2 * (int64_t) f5;
+  int64_t f2f6_2  = f2_2 * (int64_t) f6;
+  int64_t f2f7_2  = f2_2 * (int64_t) f7;
+  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+  int64_t f2f9_38 = f2   * (int64_t) f9_38;
+  int64_t f3f3_2  = f3_2 * (int64_t) f3;
+  int64_t f3f4_2  = f3_2 * (int64_t) f4;
+  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+  int64_t f3f6_2  = f3_2 * (int64_t) f6;
+  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+  int64_t f4f4    = f4   * (int64_t) f4;
+  int64_t f4f5_2  = f4_2 * (int64_t) f5;
+  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+  int64_t f4f7_38 = f4   * (int64_t) f7_38;
+  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+  int64_t f4f9_38 = f4   * (int64_t) f9_38;
+  int64_t f5f5_38 = f5   * (int64_t) f5_38;
+  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+  int64_t f6f6_19 = f6   * (int64_t) f6_19;
+  int64_t f6f7_38 = f6   * (int64_t) f7_38;
+  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+  int64_t f6f9_38 = f6   * (int64_t) f9_38;
+  int64_t f7f7_38 = f7   * (int64_t) f7_38;
+  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+  int64_t f8f8_19 = f8   * (int64_t) f8_19;
+  int64_t f8f9_38 = f8   * (int64_t) f9_38;
+  int64_t f9f9_38 = f9   * (int64_t) f9_38;
+  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+static void fe_invert(fe out, const fe z) {
+  fe t0;
+  fe t1;
+  fe t2;
+  fe t3;
+  int i;
+
+  fe_sq(t0, z);
+  for (i = 1; i < 1; ++i) {
+    fe_sq(t0, t0);
+  }
+  fe_sq(t1, t0);
+  for (i = 1; i < 2; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(t1, z, t1);
+  fe_mul(t0, t0, t1);
+  fe_sq(t2, t0);
+  for (i = 1; i < 1; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t1, t2);
+  fe_sq(t2, t1);
+  for (i = 1; i < 5; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t2, t1);
+  for (i = 1; i < 10; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t2, t2, t1);
+  fe_sq(t3, t2);
+  for (i = 1; i < 20; ++i) {
+    fe_sq(t3, t3);
+  }
+  fe_mul(t2, t3, t2);
+  fe_sq(t2, t2);
+  for (i = 1; i < 10; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t2, t1);
+  for (i = 1; i < 50; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t2, t2, t1);
+  fe_sq(t3, t2);
+  for (i = 1; i < 100; ++i) {
+    fe_sq(t3, t3);
+  }
+  fe_mul(t2, t3, t2);
+  fe_sq(t2, t2);
+  for (i = 1; i < 50; ++i) {
+    fe_sq(t2, t2);
+  }
+  fe_mul(t1, t2, t1);
+  fe_sq(t1, t1);
+  for (i = 1; i < 5; ++i) {
+    fe_sq(t1, t1);
+  }
+  fe_mul(out, t1, t0);
+}
+
+/* h = -f
+ *
+ * Preconditions:
+ *    |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ *
+ * Postconditions:
+ *    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. */
+static void fe_neg(fe h, const fe f) {
+  unsigned i;
+  for (i = 0; i < 10; i++) {
+    h[i] = -f[i];
+  }
+}
+
+/* Replace (f,g) with (g,g) if b == 1;
+ * replace (f,g) with (f,g) if b == 0.
+ *
+ * Preconditions: b in {0,1}. */
+static void fe_cmov(fe f, const fe g, unsigned b) {
+  size_t i;
+  b = 0-b;
+  for (i = 0; i < 10; i++) {
+    int32_t x = f[i] ^ g[i];
+    x &= b;
+    f[i] ^= x;
+  }
+}
+
+/* h = 2 * f * f
+ * Can overlap h with f.
+ *
+ * Preconditions:
+ *    |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+ *
+ * Postconditions:
+ *    |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+ *
+ * See fe_mul.c for discussion of implementation strategy. */
+static void fe_sq2(fe h, const fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int32_t f0_2 = 2 * f0;
+  int32_t f1_2 = 2 * f1;
+  int32_t f2_2 = 2 * f2;
+  int32_t f3_2 = 2 * f3;
+  int32_t f4_2 = 2 * f4;
+  int32_t f5_2 = 2 * f5;
+  int32_t f6_2 = 2 * f6;
+  int32_t f7_2 = 2 * f7;
+  int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */
+  int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */
+  int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */
+  int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */
+  int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */
+  int64_t f0f0    = f0   * (int64_t) f0;
+  int64_t f0f1_2  = f0_2 * (int64_t) f1;
+  int64_t f0f2_2  = f0_2 * (int64_t) f2;
+  int64_t f0f3_2  = f0_2 * (int64_t) f3;
+  int64_t f0f4_2  = f0_2 * (int64_t) f4;
+  int64_t f0f5_2  = f0_2 * (int64_t) f5;
+  int64_t f0f6_2  = f0_2 * (int64_t) f6;
+  int64_t f0f7_2  = f0_2 * (int64_t) f7;
+  int64_t f0f8_2  = f0_2 * (int64_t) f8;
+  int64_t f0f9_2  = f0_2 * (int64_t) f9;
+  int64_t f1f1_2  = f1_2 * (int64_t) f1;
+  int64_t f1f2_2  = f1_2 * (int64_t) f2;
+  int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+  int64_t f1f4_2  = f1_2 * (int64_t) f4;
+  int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+  int64_t f1f6_2  = f1_2 * (int64_t) f6;
+  int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+  int64_t f1f8_2  = f1_2 * (int64_t) f8;
+  int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+  int64_t f2f2    = f2   * (int64_t) f2;
+  int64_t f2f3_2  = f2_2 * (int64_t) f3;
+  int64_t f2f4_2  = f2_2 * (int64_t) f4;
+  int64_t f2f5_2  = f2_2 * (int64_t) f5;
+  int64_t f2f6_2  = f2_2 * (int64_t) f6;
+  int64_t f2f7_2  = f2_2 * (int64_t) f7;
+  int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+  int64_t f2f9_38 = f2   * (int64_t) f9_38;
+  int64_t f3f3_2  = f3_2 * (int64_t) f3;
+  int64_t f3f4_2  = f3_2 * (int64_t) f4;
+  int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+  int64_t f3f6_2  = f3_2 * (int64_t) f6;
+  int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+  int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+  int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+  int64_t f4f4    = f4   * (int64_t) f4;
+  int64_t f4f5_2  = f4_2 * (int64_t) f5;
+  int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+  int64_t f4f7_38 = f4   * (int64_t) f7_38;
+  int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+  int64_t f4f9_38 = f4   * (int64_t) f9_38;
+  int64_t f5f5_38 = f5   * (int64_t) f5_38;
+  int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+  int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+  int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+  int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+  int64_t f6f6_19 = f6   * (int64_t) f6_19;
+  int64_t f6f7_38 = f6   * (int64_t) f7_38;
+  int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+  int64_t f6f9_38 = f6   * (int64_t) f9_38;
+  int64_t f7f7_38 = f7   * (int64_t) f7_38;
+  int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+  int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+  int64_t f8f8_19 = f8   * (int64_t) f8_19;
+  int64_t f8f9_38 = f8   * (int64_t) f9_38;
+  int64_t f9f9_38 = f9   * (int64_t) f9_38;
+  int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+  int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+  int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+  int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+  int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+  int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+  int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+  int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+  int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+  int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  h0 += h0;
+  h1 += h1;
+  h2 += h2;
+  h3 += h3;
+  h4 += h4;
+  h5 += h5;
+  h6 += h6;
+  h7 += h7;
+  h8 += h8;
+  h9 += h9;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+/* ge means group element.
+
+ * Here the group is the set of pairs (x,y) of field elements (see fe.h)
+ * satisfying -x^2 + y^2 = 1 + d x^2y^2
+ * where d = -121665/121666.
+ *
+ * Representations:
+ *   ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+ *   ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+ *   ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+ *   ge_precomp (Duif): (y+x,y-x,2dxy) */
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+} ge_p2;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p3;
+
+typedef struct {
+  fe X;
+  fe Y;
+  fe Z;
+  fe T;
+} ge_p1p1;
+
+typedef struct {
+  fe yplusx;
+  fe yminusx;
+  fe xy2d;
+} ge_precomp;
+
+typedef struct {
+  fe YplusX;
+  fe YminusX;
+  fe Z;
+  fe T2d;
+} ge_cached;
+
+static const fe d = {-10913610, 13857413, -15372611, 6949391,   114729,
+                     -8787816,  -6275908, -3247719,  -18696448, -12055116};
+
+static const fe sqrtm1 = {-32595792, -7943725,  9377950,  3500415, 12389472,
+                          -272473,   -25146209, -2005654, 326686,  11406482};
+
+static void ge_p3_0(ge_p3 *h) {
+  fe_0(h->X);
+  fe_1(h->Y);
+  fe_1(h->Z);
+  fe_0(h->T);
+}
+
+static void ge_precomp_0(ge_precomp *h) {
+  fe_1(h->yplusx);
+  fe_1(h->yminusx);
+  fe_0(h->xy2d);
+}
+
+/* r = p */
+static void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
+  fe_copy(r->X, p->X);
+  fe_copy(r->Y, p->Y);
+  fe_copy(r->Z, p->Z);
+}
+
+static const fe d2 = {-21827239, -5839606,  -30745221, 13898782, 229458,
+                      15978800,  -12551817, -6495438,  29715968, 9444199};
+
+/* r = p */
+static void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
+  fe_mul(r->X, p->X, p->T);
+  fe_mul(r->Y, p->Y, p->Z);
+  fe_mul(r->Z, p->Z, p->T);
+}
+
+/* r = p */
+static void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
+  fe_mul(r->X, p->X, p->T);
+  fe_mul(r->Y, p->Y, p->Z);
+  fe_mul(r->Z, p->Z, p->T);
+  fe_mul(r->T, p->X, p->Y);
+}
+
+/* r = 2 * p */
+static void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
+  fe t0;
+
+  fe_sq(r->X, p->X);
+  fe_sq(r->Z, p->Y);
+  fe_sq2(r->T, p->Z);
+  fe_add(r->Y, p->X, p->Y);
+  fe_sq(t0, r->Y);
+  fe_add(r->Y, r->Z, r->X);
+  fe_sub(r->Z, r->Z, r->X);
+  fe_sub(r->X, t0, r->Y);
+  fe_sub(r->T, r->T, r->Z);
+}
+
+/* r = 2 * p */
+static void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
+  ge_p2 q;
+  ge_p3_to_p2(&q, p);
+  ge_p2_dbl(r, &q);
+}
+
+/* r = p + q */
+static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
+  fe t0;
+
+  fe_add(r->X, p->Y, p->X);
+  fe_sub(r->Y, p->Y, p->X);
+  fe_mul(r->Z, r->X, q->yplusx);
+  fe_mul(r->Y, r->Y, q->yminusx);
+  fe_mul(r->T, q->xy2d, p->T);
+  fe_add(t0, p->Z, p->Z);
+  fe_sub(r->X, r->Z, r->Y);
+  fe_add(r->Y, r->Z, r->Y);
+  fe_add(r->Z, t0, r->T);
+  fe_sub(r->T, t0, r->T);
+}
+
+static uint8_t equal(signed char b, signed char c) {
+  uint8_t ub = b;
+  uint8_t uc = c;
+  uint8_t x = ub ^ uc; /* 0: yes; 1..255: no */
+  uint32_t y = x;      /* 0: yes; 1..255: no */
+  y -= 1;              /* 4294967295: yes; 0..254: no */
+  y >>= 31;            /* 1: yes; 0: no */
+  return y;
+}
+
+static void cmov(ge_precomp *t, ge_precomp *u, uint8_t b) {
+  fe_cmov(t->yplusx, u->yplusx, b);
+  fe_cmov(t->yminusx, u->yminusx, b);
+  fe_cmov(t->xy2d, u->xy2d, b);
+}
+
+#if defined(OPENSSL_SMALL)
+
+/* This block of code replaces the standard base-point table with a much smaller
+ * one. The standard table is 30,720 bytes while this one is just 960.
+ *
+ * This table contains 15 pairs of group elements, (x, y), where each field
+ * element is serialised with |fe_tobytes|. If |i| is the index of the group
+ * element then consider i+1 as a four-bit number: (i₀, i₁, i₂, i₃) (where i₀
+ * is the most significant bit). The value of the group element is then:
+ * (i₀×2^192 + i₁×2^128 + i₂×2^64 + i₃)G, where G is the generator. */
+static const uint8_t k25519SmallPrecomp[15 * 2 * 32] = {
+    0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95,
+    0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
+    0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21, 0x58, 0x66, 0x66, 0x66,
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+    0x66, 0x66, 0x66, 0x66, 0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e,
+    0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, 0x96, 0x8a, 0xa0, 0xb4,
+    0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62,
+    0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba,
+    0x08, 0xb6, 0x10, 0x54, 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd,
+    0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03, 0xa2, 0xfb, 0xcc, 0x61,
+    0x67, 0x06, 0x70, 0x1a, 0xc4, 0x78, 0x3a, 0xff, 0x32, 0x62, 0xdd, 0x2c,
+    0xab, 0x50, 0x19, 0x3b, 0xf2, 0x9b, 0x7d, 0xb8, 0xfd, 0x4f, 0x29, 0x9c,
+    0xa7, 0x91, 0xba, 0x0e, 0x46, 0x5e, 0x51, 0xfe, 0x1d, 0xbf, 0xe5, 0xe5,
+    0x9b, 0x95, 0x0d, 0x67, 0xf8, 0xd1, 0xb5, 0x5a, 0xa1, 0x93, 0x2c, 0xc3,
+    0xde, 0x0e, 0x97, 0x85, 0x2d, 0x7f, 0xea, 0xab, 0x3e, 0x47, 0x30, 0x18,
+    0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2,
+    0xc9, 0x85, 0xe6, 0x98, 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95,
+    0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c, 0x6b, 0xa6, 0xf5, 0x4b,
+    0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90,
+    0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52,
+    0xe6, 0x99, 0x2c, 0x5f, 0x9a, 0x96, 0x0c, 0x68, 0x29, 0xfd, 0xe2, 0xfb,
+    0xe6, 0xbc, 0xec, 0x31, 0x08, 0xec, 0xe6, 0xb0, 0x53, 0x60, 0xc3, 0x8c,
+    0xbe, 0xc1, 0xb3, 0x8a, 0x8f, 0xe4, 0x88, 0x2b, 0x55, 0xe5, 0x64, 0x6e,
+    0x9b, 0xd0, 0xaf, 0x7b, 0x64, 0x2a, 0x35, 0x25, 0x10, 0x52, 0xc5, 0x9e,
+    0x58, 0x11, 0x39, 0x36, 0x45, 0x51, 0xb8, 0x39, 0x93, 0xfc, 0x9d, 0x6a,
+    0xbe, 0x58, 0xcb, 0xa4, 0x0f, 0x51, 0x3c, 0x38, 0x05, 0xca, 0xab, 0x43,
+    0x63, 0x0e, 0xf3, 0x8b, 0x41, 0xa6, 0xf8, 0x9b, 0x53, 0x70, 0x80, 0x53,
+    0x86, 0x5e, 0x8f, 0xe3, 0xc3, 0x0d, 0x18, 0xc8, 0x4b, 0x34, 0x1f, 0xd8,
+    0x1d, 0xbc, 0xf2, 0x6d, 0x34, 0x3a, 0xbe, 0xdf, 0xd9, 0xf6, 0xf3, 0x89,
+    0xa1, 0xe1, 0x94, 0x9f, 0x5d, 0x4c, 0x5d, 0xe9, 0xa1, 0x49, 0x92, 0xef,
+    0x0e, 0x53, 0x81, 0x89, 0x58, 0x87, 0xa6, 0x37, 0xf1, 0xdd, 0x62, 0x60,
+    0x63, 0x5a, 0x9d, 0x1b, 0x8c, 0xc6, 0x7d, 0x52, 0xea, 0x70, 0x09, 0x6a,
+    0xe1, 0x32, 0xf3, 0x73, 0x21, 0x1f, 0x07, 0x7b, 0x7c, 0x9b, 0x49, 0xd8,
+    0xc0, 0xf3, 0x25, 0x72, 0x6f, 0x9d, 0xed, 0x31, 0x67, 0x36, 0x36, 0x54,
+    0x40, 0x92, 0x71, 0xe6, 0x11, 0x28, 0x11, 0xad, 0x93, 0x32, 0x85, 0x7b,
+    0x3e, 0xb7, 0x3b, 0x49, 0x13, 0x1c, 0x07, 0xb0, 0x2e, 0x93, 0xaa, 0xfd,
+    0xfd, 0x28, 0x47, 0x3d, 0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb,
+    0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, 0x7d, 0x17, 0x7e, 0x1c,
+    0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b,
+    0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63,
+    0x12, 0x7e, 0x02, 0x1d, 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a,
+    0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61, 0x38, 0x68, 0xb0, 0x07,
+    0xa3, 0xfc, 0xcc, 0x85, 0x10, 0x7f, 0x4c, 0x65, 0x65, 0xb3, 0xfa, 0xfa,
+    0xa5, 0x53, 0x6f, 0xdb, 0x74, 0x4c, 0x56, 0x46, 0x03, 0xe2, 0xd5, 0x7a,
+    0x29, 0x1c, 0xc6, 0x02, 0xbc, 0x59, 0xf2, 0x04, 0x75, 0x63, 0xc0, 0x84,
+    0x2f, 0x60, 0x1c, 0x67, 0x76, 0xfd, 0x63, 0x86, 0xf3, 0xfa, 0xbf, 0xdc,
+    0xd2, 0x2d, 0x90, 0x91, 0xbd, 0x33, 0xa9, 0xe5, 0x66, 0x0c, 0xda, 0x42,
+    0x27, 0xca, 0xf4, 0x66, 0xc2, 0xec, 0x92, 0x14, 0x57, 0x06, 0x63, 0xd0,
+    0x4d, 0x15, 0x06, 0xeb, 0x69, 0x58, 0x4f, 0x77, 0xc5, 0x8b, 0xc7, 0xf0,
+    0x8e, 0xed, 0x64, 0xa0, 0xb3, 0x3c, 0x66, 0x71, 0xc6, 0x2d, 0xda, 0x0a,
+    0x0d, 0xfe, 0x70, 0x27, 0x64, 0xf8, 0x27, 0xfa, 0xf6, 0x5f, 0x30, 0xa5,
+    0x0d, 0x6c, 0xda, 0xf2, 0x62, 0x5e, 0x78, 0x47, 0xd3, 0x66, 0x00, 0x1c,
+    0xfd, 0x56, 0x1f, 0x5d, 0x3f, 0x6f, 0xf4, 0x4c, 0xd8, 0xfd, 0x0e, 0x27,
+    0xc9, 0x5c, 0x2b, 0xbc, 0xc0, 0xa4, 0xe7, 0x23, 0x29, 0x02, 0x9f, 0x31,
+    0xd6, 0xe9, 0xd7, 0x96, 0xf4, 0xe0, 0x5e, 0x0b, 0x0e, 0x13, 0xee, 0x3c,
+    0x09, 0xed, 0xf2, 0x3d, 0x76, 0x91, 0xc3, 0xa4, 0x97, 0xae, 0xd4, 0x87,
+    0xd0, 0x5d, 0xf6, 0x18, 0x47, 0x1f, 0x1d, 0x67, 0xf2, 0xcf, 0x63, 0xa0,
+    0x91, 0x27, 0xf8, 0x93, 0x45, 0x75, 0x23, 0x3f, 0xd1, 0xf1, 0xad, 0x23,
+    0xdd, 0x64, 0x93, 0x96, 0x41, 0x70, 0x7f, 0xf7, 0xf5, 0xa9, 0x89, 0xa2,
+    0x34, 0xb0, 0x8d, 0x1b, 0xae, 0x19, 0x15, 0x49, 0x58, 0x23, 0x6d, 0x87,
+    0x15, 0x4f, 0x81, 0x76, 0xfb, 0x23, 0xb5, 0xea, 0xcf, 0xac, 0x54, 0x8d,
+    0x4e, 0x42, 0x2f, 0xeb, 0x0f, 0x63, 0xdb, 0x68, 0x37, 0xa8, 0xcf, 0x8b,
+    0xab, 0xf5, 0xa4, 0x6e, 0x96, 0x2a, 0xb2, 0xd6, 0xbe, 0x9e, 0xbd, 0x0d,
+    0xb4, 0x42, 0xa9, 0xcf, 0x01, 0x83, 0x8a, 0x17, 0x47, 0x76, 0xc4, 0xc6,
+    0x83, 0x04, 0x95, 0x0b, 0xfc, 0x11, 0xc9, 0x62, 0xb8, 0x0c, 0x76, 0x84,
+    0xd9, 0xb9, 0x37, 0xfa, 0xfc, 0x7c, 0xc2, 0x6d, 0x58, 0x3e, 0xb3, 0x04,
+    0xbb, 0x8c, 0x8f, 0x48, 0xbc, 0x91, 0x27, 0xcc, 0xf9, 0xb7, 0x22, 0x19,
+    0x83, 0x2e, 0x09, 0xb5, 0x72, 0xd9, 0x54, 0x1c, 0x4d, 0xa1, 0xea, 0x0b,
+    0xf1, 0xc6, 0x08, 0x72, 0x46, 0x87, 0x7a, 0x6e, 0x80, 0x56, 0x0a, 0x8a,
+    0xc0, 0xdd, 0x11, 0x6b, 0xd6, 0xdd, 0x47, 0xdf, 0x10, 0xd9, 0xd8, 0xea,
+    0x7c, 0xb0, 0x8f, 0x03, 0x00, 0x2e, 0xc1, 0x8f, 0x44, 0xa8, 0xd3, 0x30,
+    0x06, 0x89, 0xa2, 0xf9, 0x34, 0xad, 0xdc, 0x03, 0x85, 0xed, 0x51, 0xa7,
+    0x82, 0x9c, 0xe7, 0x5d, 0x52, 0x93, 0x0c, 0x32, 0x9a, 0x5b, 0xe1, 0xaa,
+    0xca, 0xb8, 0x02, 0x6d, 0x3a, 0xd4, 0xb1, 0x3a, 0xf0, 0x5f, 0xbe, 0xb5,
+    0x0d, 0x10, 0x6b, 0x38, 0x32, 0xac, 0x76, 0x80, 0xbd, 0xca, 0x94, 0x71,
+    0x7a, 0xf2, 0xc9, 0x35, 0x2a, 0xde, 0x9f, 0x42, 0x49, 0x18, 0x01, 0xab,
+    0xbc, 0xef, 0x7c, 0x64, 0x3f, 0x58, 0x3d, 0x92, 0x59, 0xdb, 0x13, 0xdb,
+    0x58, 0x6e, 0x0a, 0xe0, 0xb7, 0x91, 0x4a, 0x08, 0x20, 0xd6, 0x2e, 0x3c,
+    0x45, 0xc9, 0x8b, 0x17, 0x79, 0xe7, 0xc7, 0x90, 0x99, 0x3a, 0x18, 0x25,
+};
+
+static void ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]) {
+  /* k25519SmallPrecomp is first expanded into matching |ge_precomp|
+   * elements. */
+  ge_precomp multiples[15];
+
+  unsigned i;
+  for (i = 0; i < 15; i++) {
+    const uint8_t *bytes = &k25519SmallPrecomp[i*(2 * 32)];
+    fe x, y;
+    fe_frombytes(x, bytes);
+    fe_frombytes(y, bytes + 32);
+
+    ge_precomp *out = &multiples[i];
+    fe_add(out->yplusx, y, x);
+    fe_sub(out->yminusx, y, x);
+    fe_mul(out->xy2d, x, y);
+    fe_mul(out->xy2d, out->xy2d, d2);
+  }
+
+  /* See the comment above |k25519SmallPrecomp| about the structure of the
+   * precomputed elements. This loop does 64 additions and 64 doublings to
+   * calculate the result. */
+  ge_p3_0(h);
+
+  for (i = 63; i < 64; i--) {
+    unsigned j;
+    signed char index = 0;
+
+    for (j = 0; j < 4; j++) {
+      const uint8_t bit = 1 & (a[(8 * j) + (i / 8)] >> (i & 7));
+      index |= (bit << j);
+    }
+
+    ge_precomp e;
+    ge_precomp_0(&e);
+
+    for (j = 1; j < 16; j++) {
+      cmov(&e, &multiples[j-1], equal(index, j));
+    }
+
+    ge_cached cached;
+    ge_p1p1 r;
+    ge_p3_to_cached(&cached, h);
+    ge_add(&r, h, &cached);
+    ge_p1p1_to_p3(h, &r);
+
+    ge_madd(&r, h, &e);
+    ge_p1p1_to_p3(h, &r);
+  }
+}
+
+#else
+
+/* k25519Precomp[i][j] = (j+1)*256^i*B */
+static ge_precomp k25519Precomp[32][8] = {
+    {
+        {
+            {25967493, -14356035, 29566456, 3660896, -12694345, 4014787,
+             27544626, -11754271, -6079156, 2047605},
+            {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692,
+             5043384, 19500929, -15469378},
+            {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380,
+             29287919, 11864899, -24514362, -4438546},
+        },
+        {
+            {-12815894, -12976347, -21581243, 11784320, -25355658, -2750717,
+             -11717903, -3814571, -358445, -10211303},
+            {-21703237, 6903825, 27185491, 6451973, -29577724, -9554005,
+             -15616551, 11189268, -26829678, -5319081},
+            {26966642, 11152617, 32442495, 15396054, 14353839, -12752335,
+             -3128826, -9541118, -15472047, -4166697},
+        },
+        {
+            {15636291, -9688557, 24204773, -7912398, 616977, -16685262,
+             27787600, -14772189, 28944400, -1550024},
+            {16568933, 4717097, -11556148, -1102322, 15682896, -11807043,
+             16354577, -11775962, 7689662, 11199574},
+            {30464156, -5976125, -11779434, -15670865, 23220365, 15915852,
+             7512774, 10017326, -17749093, -9920357},
+        },
+        {
+            {-17036878, 13921892, 10945806, -6033431, 27105052, -16084379,
+             -28926210, 15006023, 3284568, -6276540},
+            {23599295, -8306047, -11193664, -7687416, 13236774, 10506355,
+             7464579, 9656445, 13059162, 10374397},
+            {7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664,
+             -3839045, -641708, -101325},
+        },
+        {
+            {10861363, 11473154, 27284546, 1981175, -30064349, 12577861,
+             32867885, 14515107, -15438304, 10819380},
+            {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668,
+             12483688, -12668491, 5581306},
+            {19563160, 16186464, -29386857, 4097519, 10237984, -4348115,
+             28542350, 13850243, -23678021, -15815942},
+        },
+        {
+            {-15371964, -12862754, 32573250, 4720197, -26436522, 5875511,
+             -19188627, -15224819, -9818940, -12085777},
+            {-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240,
+             -15689887, 1762328, 14866737},
+            {-18199695, -15951423, -10473290, 1707278, -17185920, 3916101,
+             -28236412, 3959421, 27914454, 4383652},
+        },
+        {
+            {5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852,
+             5230134, -23952439, -15175766},
+            {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722,
+             20654025, 16520125, 30598449, 7715701},
+            {28881845, 14381568, 9657904, 3680757, -20181635, 7843316,
+             -31400660, 1370708, 29794553, -1409300},
+        },
+        {
+            {14499471, -2729599, -33191113, -4254652, 28494862, 14271267,
+             30290735, 10876454, -33154098, 2381726},
+            {-7195431, -2655363, -14730155, 462251, -27724326, 3941372,
+             -6236617, 3696005, -32300832, 15351955},
+            {27431194, 8222322, 16448760, -3907995, -18707002, 11938355,
+             -32961401, -2970515, 29551813, 10109425},
+        },
+    },
+    {
+        {
+            {-13657040, -13155431, -31283750, 11777098, 21447386, 6519384,
+             -2378284, -1627556, 10092783, -4764171},
+            {27939166, 14210322, 4677035, 16277044, -22964462, -12398139,
+             -32508754, 12005538, -17810127, 12803510},
+            {17228999, -15661624, -1233527, 300140, -1224870, -11714777,
+             30364213, -9038194, 18016357, 4397660},
+        },
+        {
+            {-10958843, -7690207, 4776341, -14954238, 27850028, -15602212,
+             -26619106, 14544525, -17477504, 982639},
+            {29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899,
+             -4120128, -21047696, 9934963},
+            {5793303, 16271923, -24131614, -10116404, 29188560, 1206517,
+             -14747930, 4559895, -30123922, -10897950},
+        },
+        {
+            {-27643952, -11493006, 16282657, -11036493, 28414021, -15012264,
+             24191034, 4541697, -13338309, 5500568},
+            {12650548, -1497113, 9052871, 11355358, -17680037, -8400164,
+             -17430592, 12264343, 10874051, 13524335},
+            {25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038,
+             5080568, -22528059, 5376628},
+        },
+        {
+            {-26088264, -4011052, -17013699, -3537628, -6726793, 1920897,
+             -22321305, -9447443, 4535768, 1569007},
+            {-2255422, 14606630, -21692440, -8039818, 28430649, 8775819,
+             -30494562, 3044290, 31848280, 12543772},
+            {-22028579, 2943893, -31857513, 6777306, 13784462, -4292203,
+             -27377195, -2062731, 7718482, 14474653},
+        },
+        {
+            {2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965,
+             -7236665, 24316168, -5253567},
+            {13741529, 10911568, -33233417, -8603737, -20177830, -1033297,
+             33040651, -13424532, -20729456, 8321686},
+            {21060490, -2212744, 15712757, -4336099, 1639040, 10656336,
+             23845965, -11874838, -9984458, 608372},
+        },
+        {
+            {-13672732, -15087586, -10889693, -7557059, -6036909, 11305547,
+             1123968, -6780577, 27229399, 23887},
+            {-23244140, -294205, -11744728, 14712571, -29465699, -2029617,
+             12797024, -6440308, -1633405, 16678954},
+            {-29500620, 4770662, -16054387, 14001338, 7830047, 9564805,
+             -1508144, -4795045, -17169265, 4904953},
+        },
+        {
+            {24059557, 14617003, 19037157, -15039908, 19766093, -14906429,
+             5169211, 16191880, 2128236, -4326833},
+            {-16981152, 4124966, -8540610, -10653797, 30336522, -14105247,
+             -29806336, 916033, -6882542, -2986532},
+            {-22630907, 12419372, -7134229, -7473371, -16478904, 16739175,
+             285431, 2763829, 15736322, 4143876},
+        },
+        {
+            {2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801,
+             -14594663, 23527084, -16458268},
+            {33431127, -11130478, -17838966, -15626900, 8909499, 8376530,
+             -32625340, 4087881, -15188911, -14416214},
+            {1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055,
+             4357868, -4774191, -16323038},
+        },
+    },
+    {
+        {
+            {6721966, 13833823, -23523388, -1551314, 26354293, -11863321,
+             23365147, -3949732, 7390890, 2759800},
+            {4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353,
+             -4264057, 1244380, -12919645},
+            {-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413,
+             9208236, 15886429, 16489664},
+        },
+        {
+            {1996075, 10375649, 14346367, 13311202, -6874135, -16438411,
+             -13693198, 398369, -30606455, -712933},
+            {-25307465, 9795880, -2777414, 14878809, -33531835, 14780363,
+             13348553, 12076947, -30836462, 5113182},
+            {-17770784, 11797796, 31950843, 13929123, -25888302, 12288344,
+             -30341101, -7336386, 13847711, 5387222},
+        },
+        {
+            {-18582163, -3416217, 17824843, -2340966, 22744343, -10442611,
+             8763061, 3617786, -19600662, 10370991},
+            {20246567, -14369378, 22358229, -543712, 18507283, -10413996,
+             14554437, -8746092, 32232924, 16763880},
+            {9648505, 10094563, 26416693, 14745928, -30374318, -6472621,
+             11094161, 15689506, 3140038, -16510092},
+        },
+        {
+            {-16160072, 5472695, 31895588, 4744994, 8823515, 10365685,
+             -27224800, 9448613, -28774454, 366295},
+            {19153450, 11523972, -11096490, -6503142, -24647631, 5420647,
+             28344573, 8041113, 719605, 11671788},
+            {8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916,
+             -15266516, 27000813, -10195553},
+        },
+        {
+            {-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065,
+             5336097, 6750977, -14521026},
+            {11836410, -3979488, 26297894, 16080799, 23455045, 15735944,
+             1695823, -8819122, 8169720, 16220347},
+            {-18115838, 8653647, 17578566, -6092619, -8025777, -16012763,
+             -11144307, -2627664, -5990708, -14166033},
+        },
+        {
+            {-23308498, -10968312, 15213228, -10081214, -30853605, -11050004,
+             27884329, 2847284, 2655861, 1738395},
+            {-27537433, -14253021, -25336301, -8002780, -9370762, 8129821,
+             21651608, -3239336, -19087449, -11005278},
+            {1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092,
+             5821408, 10478196, 8544890},
+        },
+        {
+            {32173121, -16129311, 24896207, 3921497, 22579056, -3410854,
+             19270449, 12217473, 17789017, -3395995},
+            {-30552961, -2228401, -15578829, -10147201, 13243889, 517024,
+             15479401, -3853233, 30460520, 1052596},
+            {-11614875, 13323618, 32618793, 8175907, -15230173, 12596687,
+             27491595, -4612359, 3179268, -9478891},
+        },
+        {
+            {31947069, -14366651, -4640583, -15339921, -15125977, -6039709,
+             -14756777, -16411740, 19072640, -9511060},
+            {11685058, 11822410, 3158003, -13952594, 33402194, -4165066,
+             5977896, -5215017, 473099, 5040608},
+            {-20290863, 8198642, -27410132, 11602123, 1290375, -2799760,
+             28326862, 1721092, -19558642, -3131606},
+        },
+    },
+    {
+        {
+            {7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786,
+             8076149, -27868496, 11538389},
+            {-19935666, 3899861, 18283497, -6801568, -15728660, -11249211,
+             8754525, 7446702, -5676054, 5797016},
+            {-11295600, -3793569, -15782110, -7964573, 12708869, -8456199,
+             2014099, -9050574, -2369172, -5877341},
+        },
+        {
+            {-22472376, -11568741, -27682020, 1146375, 18956691, 16640559,
+             1192730, -3714199, 15123619, 10811505},
+            {14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363,
+             15776356, -28886779, -11974553},
+            {-28241164, -8072475, -4978962, -5315317, 29416931, 1847569,
+             -20654173, -16484855, 4714547, -9600655},
+        },
+        {
+            {15200332, 8368572, 19679101, 15970074, -31872674, 1959451,
+             24611599, -4543832, -11745876, 12340220},
+            {12876937, -10480056, 33134381, 6590940, -6307776, 14872440,
+             9613953, 8241152, 15370987, 9608631},
+            {-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868,
+             15866074, -28210621, -8814099},
+        },
+        {
+            {26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233,
+             858697, 20571223, 8420556},
+            {14620715, 13067227, -15447274, 8264467, 14106269, 15080814,
+             33531827, 12516406, -21574435, -12476749},
+            {236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519,
+             7256740, 8791136, 15069930},
+        },
+        {
+            {1276410, -9371918, 22949635, -16322807, -23493039, -5702186,
+             14711875, 4874229, -30663140, -2331391},
+            {5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175,
+             -7912378, -33069337, 9234253},
+            {20590503, -9018988, 31529744, -7352666, -2706834, 10650548,
+             31559055, -11609587, 18979186, 13396066},
+        },
+        {
+            {24474287, 4968103, 22267082, 4407354, 24063882, -8325180,
+             -18816887, 13594782, 33514650, 7021958},
+            {-11566906, -6565505, -21365085, 15928892, -26158305, 4315421,
+             -25948728, -3916677, -21480480, 12868082},
+            {-28635013, 13504661, 19988037, -2132761, 21078225, 6443208,
+             -21446107, 2244500, -12455797, -8089383},
+        },
+        {
+            {-30595528, 13793479, -5852820, 319136, -25723172, -6263899,
+             33086546, 8957937, -15233648, 5540521},
+            {-11630176, -11503902, -8119500, -7643073, 2620056, 1022908,
+             -23710744, -1568984, -16128528, -14962807},
+            {23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819,
+             892185, -11513277, -15205948},
+        },
+        {
+            {9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819,
+             4763127, -19179614, 5867134},
+            {-32765025, 1927590, 31726409, -4753295, 23962434, -16019500,
+             27846559, 5931263, -29749703, -16108455},
+            {27461885, -2977536, 22380810, 1815854, -23033753, -3031938,
+             7283490, -15148073, -19526700, 7734629},
+        },
+    },
+    {
+        {
+            {-8010264, -9590817, -11120403, 6196038, 29344158, -13430885,
+             7585295, -3176626, 18549497, 15302069},
+            {-32658337, -6171222, -7672793, -11051681, 6258878, 13504381,
+             10458790, -6418461, -8872242, 8424746},
+            {24687205, 8613276, -30667046, -3233545, 1863892, -1830544,
+             19206234, 7134917, -11284482, -828919},
+        },
+        {
+            {11334899, -9218022, 8025293, 12707519, 17523892, -10476071,
+             10243738, -14685461, -5066034, 16498837},
+            {8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925,
+             -14124238, 6536641, 10543906},
+            {-28946384, 15479763, -17466835, 568876, -1497683, 11223454,
+             -2669190, -16625574, -27235709, 8876771},
+        },
+        {
+            {-25742899, -12566864, -15649966, -846607, -33026686, -796288,
+             -33481822, 15824474, -604426, -9039817},
+            {10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697,
+             -4890037, 1657394, 3084098},
+            {10477963, -7470260, 12119566, -13250805, 29016247, -5365589,
+             31280319, 14396151, -30233575, 15272409},
+        },
+        {
+            {-12288309, 3169463, 28813183, 16658753, 25116432, -5630466,
+             -25173957, -12636138, -25014757, 1950504},
+            {-26180358, 9489187, 11053416, -14746161, -31053720, 5825630,
+             -8384306, -8767532, 15341279, 8373727},
+            {28685821, 7759505, -14378516, -12002860, -31971820, 4079242,
+             298136, -10232602, -2878207, 15190420},
+        },
+        {
+            {-32932876, 13806336, -14337485, -15794431, -24004620, 10940928,
+             8669718, 2742393, -26033313, -6875003},
+            {-1580388, -11729417, -25979658, -11445023, -17411874, -10912854,
+             9291594, -16247779, -12154742, 6048605},
+            {-30305315, 14843444, 1539301, 11864366, 20201677, 1900163,
+             13934231, 5128323, 11213262, 9168384},
+        },
+        {
+            {-26280513, 11007847, 19408960, -940758, -18592965, -4328580,
+             -5088060, -11105150, 20470157, -16398701},
+            {-23136053, 9282192, 14855179, -15390078, -7362815, -14408560,
+             -22783952, 14461608, 14042978, 5230683},
+            {29969567, -2741594, -16711867, -8552442, 9175486, -2468974,
+             21556951, 3506042, -5933891, -12449708},
+        },
+        {
+            {-3144746, 8744661, 19704003, 4581278, -20430686, 6830683,
+             -21284170, 8971513, -28539189, 15326563},
+            {-19464629, 10110288, -17262528, -3503892, -23500387, 1355669,
+             -15523050, 15300988, -20514118, 9168260},
+            {-5353335, 4488613, -23803248, 16314347, 7780487, -15638939,
+             -28948358, 9601605, 33087103, -9011387},
+        },
+        {
+            {-19443170, -15512900, -20797467, -12445323, -29824447, 10229461,
+             -27444329, -15000531, -5996870, 15664672},
+            {23294591, -16632613, -22650781, -8470978, 27844204, 11461195,
+             13099750, -2460356, 18151676, 13417686},
+            {-24722913, -4176517, -31150679, 5988919, -26858785, 6685065,
+             1661597, -12551441, 15271676, -15452665},
+        },
+    },
+    {
+        {
+            {11433042, -13228665, 8239631, -5279517, -1985436, -725718,
+             -18698764, 2167544, -6921301, -13440182},
+            {-31436171, 15575146, 30436815, 12192228, -22463353, 9395379,
+             -9917708, -8638997, 12215110, 12028277},
+            {14098400, 6555944, 23007258, 5757252, -15427832, -12950502,
+             30123440, 4617780, -16900089, -655628},
+        },
+        {
+            {-4026201, -15240835, 11893168, 13718664, -14809462, 1847385,
+             -15819999, 10154009, 23973261, -12684474},
+            {-26531820, -3695990, -1908898, 2534301, -31870557, -16550355,
+             18341390, -11419951, 32013174, -10103539},
+            {-25479301, 10876443, -11771086, -14625140, -12369567, 1838104,
+             21911214, 6354752, 4425632, -837822},
+        },
+        {
+            {-10433389, -14612966, 22229858, -3091047, -13191166, 776729,
+             -17415375, -12020462, 4725005, 14044970},
+            {19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390,
+             -1411784, -19522291, -16109756},
+            {-24864089, 12986008, -10898878, -5558584, -11312371, -148526,
+             19541418, 8180106, 9282262, 10282508},
+        },
+        {
+            {-26205082, 4428547, -8661196, -13194263, 4098402, -14165257,
+             15522535, 8372215, 5542595, -10702683},
+            {-10562541, 14895633, 26814552, -16673850, -17480754, -2489360,
+             -2781891, 6993761, -18093885, 10114655},
+            {-20107055, -929418, 31422704, 10427861, -7110749, 6150669,
+             -29091755, -11529146, 25953725, -106158},
+        },
+        {
+            {-4234397, -8039292, -9119125, 3046000, 2101609, -12607294,
+             19390020, 6094296, -3315279, 12831125},
+            {-15998678, 7578152, 5310217, 14408357, -33548620, -224739,
+             31575954, 6326196, 7381791, -2421839},
+            {-20902779, 3296811, 24736065, -16328389, 18374254, 7318640,
+             6295303, 8082724, -15362489, 12339664},
+        },
+        {
+            {27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414,
+             15768922, 25091167, 14856294},
+            {-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300,
+             -12695493, -22182473, -9012899},
+            {-11423429, -5421590, 11632845, 3405020, 30536730, -11674039,
+             -27260765, 13866390, 30146206, 9142070},
+        },
+        {
+            {3924129, -15307516, -13817122, -10054960, 12291820, -668366,
+             -27702774, 9326384, -8237858, 4171294},
+            {-15921940, 16037937, 6713787, 16606682, -21612135, 2790944,
+             26396185, 3731949, 345228, -5462949},
+            {-21327538, 13448259, 25284571, 1143661, 20614966, -8849387,
+             2031539, -12391231, -16253183, -13582083},
+        },
+        {
+            {31016211, -16722429, 26371392, -14451233, -5027349, 14854137,
+             17477601, 3842657, 28012650, -16405420},
+            {-5075835, 9368966, -8562079, -4600902, -15249953, 6970560,
+             -9189873, 16292057, -8867157, 3507940},
+            {29439664, 3537914, 23333589, 6997794, -17555561, -11018068,
+             -15209202, -15051267, -9164929, 6580396},
+        },
+    },
+    {
+        {
+            {-12185861, -7679788, 16438269, 10826160, -8696817, -6235611,
+             17860444, -9273846, -2095802, 9304567},
+            {20714564, -4336911, 29088195, 7406487, 11426967, -5095705,
+             14792667, -14608617, 5289421, -477127},
+            {-16665533, -10650790, -6160345, -13305760, 9192020, -1802462,
+             17271490, 12349094, 26939669, -3752294},
+        },
+        {
+            {-12889898, 9373458, 31595848, 16374215, 21471720, 13221525,
+             -27283495, -12348559, -3698806, 117887},
+            {22263325, -6560050, 3984570, -11174646, -15114008, -566785,
+             28311253, 5358056, -23319780, 541964},
+            {16259219, 3261970, 2309254, -15534474, -16885711, -4581916,
+             24134070, -16705829, -13337066, -13552195},
+        },
+        {
+            {9378160, -13140186, -22845982, -12745264, 28198281, -7244098,
+             -2399684, -717351, 690426, 14876244},
+            {24977353, -314384, -8223969, -13465086, 28432343, -1176353,
+             -13068804, -12297348, -22380984, 6618999},
+            {-1538174, 11685646, 12944378, 13682314, -24389511, -14413193,
+             8044829, -13817328, 32239829, -5652762},
+        },
+        {
+            {-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647,
+             -10350059, 32779359, 5095274},
+            {-33008130, -5214506, -32264887, -3685216, 9460461, -9327423,
+             -24601656, 14506724, 21639561, -2630236},
+            {-16400943, -13112215, 25239338, 15531969, 3987758, -4499318,
+             -1289502, -6863535, 17874574, 558605},
+        },
+        {
+            {-13600129, 10240081, 9171883, 16131053, -20869254, 9599700,
+             33499487, 5080151, 2085892, 5119761},
+            {-22205145, -2519528, -16381601, 414691, -25019550, 2170430,
+             30634760, -8363614, -31999993, -5759884},
+            {-6845704, 15791202, 8550074, -1312654, 29928809, -12092256,
+             27534430, -7192145, -22351378, 12961482},
+        },
+        {
+            {-24492060, -9570771, 10368194, 11582341, -23397293, -2245287,
+             16533930, 8206996, -30194652, -5159638},
+            {-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630,
+             7031275, 7589640, 8945490},
+            {-32152748, 8917967, 6661220, -11677616, -1192060, -15793393,
+             7251489, -11182180, 24099109, -14456170},
+        },
+        {
+            {5019558, -7907470, 4244127, -14714356, -26933272, 6453165,
+             -19118182, -13289025, -6231896, -10280736},
+            {10853594, 10721687, 26480089, 5861829, -22995819, 1972175,
+             -1866647, -10557898, -3363451, -6441124},
+            {-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661,
+             -2008168, -13866408, 7421392},
+        },
+        {
+            {8139927, -6546497, 32257646, -5890546, 30375719, 1886181,
+             -21175108, 15441252, 28826358, -4123029},
+            {6267086, 9695052, 7709135, -16603597, -32869068, -1886135,
+             14795160, -7840124, 13746021, -1742048},
+            {28584902, 7787108, -6732942, -15050729, 22846041, -7571236,
+             -3181936, -363524, 4771362, -8419958},
+        },
+    },
+    {
+        {
+            {24949256, 6376279, -27466481, -8174608, -18646154, -9930606,
+             33543569, -12141695, 3569627, 11342593},
+            {26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886,
+             4608608, 7325975, -14801071},
+            {-11618399, -14554430, -24321212, 7655128, -1369274, 5214312,
+             -27400540, 10258390, -17646694, -8186692},
+        },
+        {
+            {11431204, 15823007, 26570245, 14329124, 18029990, 4796082,
+             -31446179, 15580664, 9280358, -3973687},
+            {-160783, -10326257, -22855316, -4304997, -20861367, -13621002,
+             -32810901, -11181622, -15545091, 4387441},
+            {-20799378, 12194512, 3937617, -5805892, -27154820, 9340370,
+             -24513992, 8548137, 20617071, -7482001},
+        },
+        {
+            {-938825, -3930586, -8714311, 16124718, 24603125, -6225393,
+             -13775352, -11875822, 24345683, 10325460},
+            {-19855277, -1568885, -22202708, 8714034, 14007766, 6928528,
+             16318175, -1010689, 4766743, 3552007},
+            {-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514,
+             14481909, 10988822, -3994762},
+        },
+        {
+            {15564307, -14311570, 3101243, 5684148, 30446780, -8051356,
+             12677127, -6505343, -8295852, 13296005},
+            {-9442290, 6624296, -30298964, -11913677, -4670981, -2057379,
+             31521204, 9614054, -30000824, 12074674},
+            {4771191, -135239, 14290749, -13089852, 27992298, 14998318,
+             -1413936, -1556716, 29832613, -16391035},
+        },
+        {
+            {7064884, -7541174, -19161962, -5067537, -18891269, -2912736,
+             25825242, 5293297, -27122660, 13101590},
+            {-2298563, 2439670, -7466610, 1719965, -27267541, -16328445,
+             32512469, -5317593, -30356070, -4190957},
+            {-30006540, 10162316, -33180176, 3981723, -16482138, -13070044,
+             14413974, 9515896, 19568978, 9628812},
+        },
+        {
+            {33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894,
+             -6106839, -6291786, 3437740},
+            {-18978877, 3884493, 19469877, 12726490, 15913552, 13614290,
+             -22961733, 70104, 7463304, 4176122},
+            {-27124001, 10659917, 11482427, -16070381, 12771467, -6635117,
+             -32719404, -5322751, 24216882, 5944158},
+        },
+        {
+            {8894125, 7450974, -2664149, -9765752, -28080517, -12389115,
+             19345746, 14680796, 11632993, 5847885},
+            {26942781, -2315317, 9129564, -4906607, 26024105, 11769399,
+             -11518837, 6367194, -9727230, 4782140},
+            {19916461, -4828410, -22910704, -11414391, 25606324, -5972441,
+             33253853, 8220911, 6358847, -1873857},
+        },
+        {
+            {801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388,
+             -4480480, -13538503, 1387155},
+            {19646058, 5720633, -11416706, 12814209, 11607948, 12749789,
+             14147075, 15156355, -21866831, 11835260},
+            {19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523,
+             15467869, -26560550, 5052483},
+        },
+    },
+    {
+        {
+            {-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123,
+             -12618185, 12228557, -7003677},
+            {32944382, 14922211, -22844894, 5188528, 21913450, -8719943,
+             4001465, 13238564, -6114803, 8653815},
+            {22865569, -4652735, 27603668, -12545395, 14348958, 8234005,
+             24808405, 5719875, 28483275, 2841751},
+        },
+        {
+            {-16420968, -1113305, -327719, -12107856, 21886282, -15552774,
+             -1887966, -315658, 19932058, -12739203},
+            {-11656086, 10087521, -8864888, -5536143, -19278573, -3055912,
+             3999228, 13239134, -4777469, -13910208},
+            {1382174, -11694719, 17266790, 9194690, -13324356, 9720081,
+             20403944, 11284705, -14013818, 3093230},
+        },
+        {
+            {16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424,
+             16271225, -24049421, -6691850},
+            {-21911077, -5927941, -4611316, -5560156, -31744103, -10785293,
+             24123614, 15193618, -21652117, -16739389},
+            {-9935934, -4289447, -25279823, 4372842, 2087473, 10399484,
+             31870908, 14690798, 17361620, 11864968},
+        },
+        {
+            {-11307610, 6210372, 13206574, 5806320, -29017692, -13967200,
+             -12331205, -7486601, -25578460, -16240689},
+            {14668462, -12270235, 26039039, 15305210, 25515617, 4542480,
+             10453892, 6577524, 9145645, -6443880},
+            {5974874, 3053895, -9433049, -10385191, -31865124, 3225009,
+             -7972642, 3936128, -5652273, -3050304},
+        },
+        {
+            {30625386, -4729400, -25555961, -12792866, -20484575, 7695099,
+             17097188, -16303496, -27999779, 1803632},
+            {-3553091, 9865099, -5228566, 4272701, -5673832, -16689700,
+             14911344, 12196514, -21405489, 7047412},
+            {20093277, 9920966, -11138194, -5343857, 13161587, 12044805,
+             -32856851, 4124601, -32343828, -10257566},
+        },
+        {
+            {-20788824, 14084654, -13531713, 7842147, 19119038, -13822605,
+             4752377, -8714640, -21679658, 2288038},
+            {-26819236, -3283715, 29965059, 3039786, -14473765, 2540457,
+             29457502, 14625692, -24819617, 12570232},
+            {-1063558, -11551823, 16920318, 12494842, 1278292, -5869109,
+             -21159943, -3498680, -11974704, 4724943},
+        },
+        {
+            {17960970, -11775534, -4140968, -9702530, -8876562, -1410617,
+             -12907383, -8659932, -29576300, 1903856},
+            {23134274, -14279132, -10681997, -1611936, 20684485, 15770816,
+             -12989750, 3190296, 26955097, 14109738},
+            {15308788, 5320727, -30113809, -14318877, 22902008, 7767164,
+             29425325, -11277562, 31960942, 11934971},
+        },
+        {
+            {-27395711, 8435796, 4109644, 12222639, -24627868, 14818669,
+             20638173, 4875028, 10491392, 1379718},
+            {-13159415, 9197841, 3875503, -8936108, -1383712, -5879801,
+             33518459, 16176658, 21432314, 12180697},
+            {-11787308, 11500838, 13787581, -13832590, -22430679, 10140205,
+             1465425, 12689540, -10301319, -13872883},
+        },
+    },
+    {
+        {
+            {5414091, -15386041, -21007664, 9643570, 12834970, 1186149,
+             -2622916, -1342231, 26128231, 6032912},
+            {-26337395, -13766162, 32496025, -13653919, 17847801, -12669156,
+             3604025, 8316894, -25875034, -10437358},
+            {3296484, 6223048, 24680646, -12246460, -23052020, 5903205,
+             -8862297, -4639164, 12376617, 3188849},
+        },
+        {
+            {29190488, -14659046, 27549113, -1183516, 3520066, -10697301,
+             32049515, -7309113, -16109234, -9852307},
+            {-14744486, -9309156, 735818, -598978, -20407687, -5057904,
+             25246078, -15795669, 18640741, -960977},
+            {-6928835, -16430795, 10361374, 5642961, 4910474, 12345252,
+             -31638386, -494430, 10530747, 1053335},
+        },
+        {
+            {-29265967, -14186805, -13538216, -12117373, -19457059, -10655384,
+             -31462369, -2948985, 24018831, 15026644},
+            {-22592535, -3145277, -2289276, 5953843, -13440189, 9425631,
+             25310643, 13003497, -2314791, -15145616},
+            {-27419985, -603321, -8043984, -1669117, -26092265, 13987819,
+             -27297622, 187899, -23166419, -2531735},
+        },
+        {
+            {-21744398, -13810475, 1844840, 5021428, -10434399, -15911473,
+             9716667, 16266922, -5070217, 726099},
+            {29370922, -6053998, 7334071, -15342259, 9385287, 2247707,
+             -13661962, -4839461, 30007388, -15823341},
+            {-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109,
+             730663, 9835848, 4555336},
+        },
+        {
+            {-23376435, 1410446, -22253753, -12899614, 30867635, 15826977,
+             17693930, 544696, -11985298, 12422646},
+            {31117226, -12215734, -13502838, 6561947, -9876867, -12757670,
+             -5118685, -4096706, 29120153, 13924425},
+            {-17400879, -14233209, 19675799, -2734756, -11006962, -5858820,
+             -9383939, -11317700, 7240931, -237388},
+        },
+        {
+            {-31361739, -11346780, -15007447, -5856218, -22453340, -12152771,
+             1222336, 4389483, 3293637, -15551743},
+            {-16684801, -14444245, 11038544, 11054958, -13801175, -3338533,
+             -24319580, 7733547, 12796905, -6335822},
+            {-8759414, -10817836, -25418864, 10783769, -30615557, -9746811,
+             -28253339, 3647836, 3222231, -11160462},
+        },
+        {
+            {18606113, 1693100, -25448386, -15170272, 4112353, 10045021,
+             23603893, -2048234, -7550776, 2484985},
+            {9255317, -3131197, -12156162, -1004256, 13098013, -9214866,
+             16377220, -2102812, -19802075, -3034702},
+            {-22729289, 7496160, -5742199, 11329249, 19991973, -3347502,
+             -31718148, 9936966, -30097688, -10618797},
+        },
+        {
+            {21878590, -5001297, 4338336, 13643897, -3036865, 13160960,
+             19708896, 5415497, -7360503, -4109293},
+            {27736861, 10103576, 12500508, 8502413, -3413016, -9633558,
+             10436918, -1550276, -23659143, -8132100},
+            {19492550, -12104365, -29681976, -852630, -3208171, 12403437,
+             30066266, 8367329, 13243957, 8709688},
+        },
+    },
+    {
+        {
+            {12015105, 2801261, 28198131, 10151021, 24818120, -4743133,
+             -11194191, -5645734, 5150968, 7274186},
+            {2831366, -12492146, 1478975, 6122054, 23825128, -12733586,
+             31097299, 6083058, 31021603, -9793610},
+            {-2529932, -2229646, 445613, 10720828, -13849527, -11505937,
+             -23507731, 16354465, 15067285, -14147707},
+        },
+        {
+            {7840942, 14037873, -33364863, 15934016, -728213, -3642706,
+             21403988, 1057586, -19379462, -12403220},
+            {915865, -16469274, 15608285, -8789130, -24357026, 6060030,
+             -17371319, 8410997, -7220461, 16527025},
+            {32922597, -556987, 20336074, -16184568, 10903705, -5384487,
+             16957574, 52992, 23834301, 6588044},
+        },
+        {
+            {32752030, 11232950, 3381995, -8714866, 22652988, -10744103,
+             17159699, 16689107, -20314580, -1305992},
+            {-4689649, 9166776, -25710296, -10847306, 11576752, 12733943,
+             7924251, -2752281, 1976123, -7249027},
+            {21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041,
+             -3371252, 12331345, -8237197},
+        },
+        {
+            {8651614, -4477032, -16085636, -4996994, 13002507, 2950805,
+             29054427, -5106970, 10008136, -4667901},
+            {31486080, 15114593, -14261250, 12951354, 14369431, -7387845,
+             16347321, -13662089, 8684155, -10532952},
+            {19443825, 11385320, 24468943, -9659068, -23919258, 2187569,
+             -26263207, -6086921, 31316348, 14219878},
+        },
+        {
+            {-28594490, 1193785, 32245219, 11392485, 31092169, 15722801,
+             27146014, 6992409, 29126555, 9207390},
+            {32382935, 1110093, 18477781, 11028262, -27411763, -7548111,
+             -4980517, 10843782, -7957600, -14435730},
+            {2814918, 7836403, 27519878, -7868156, -20894015, -11553689,
+             -21494559, 8550130, 28346258, 1994730},
+        },
+        {
+            {-19578299, 8085545, -14000519, -3948622, 2785838, -16231307,
+             -19516951, 7174894, 22628102, 8115180},
+            {-30405132, 955511, -11133838, -15078069, -32447087, -13278079,
+             -25651578, 3317160, -9943017, 930272},
+            {-15303681, -6833769, 28856490, 1357446, 23421993, 1057177,
+             24091212, -1388970, -22765376, -10650715},
+        },
+        {
+            {-22751231, -5303997, -12907607, -12768866, -15811511, -7797053,
+             -14839018, -16554220, -1867018, 8398970},
+            {-31969310, 2106403, -4736360, 1362501, 12813763, 16200670,
+             22981545, -6291273, 18009408, -15772772},
+            {-17220923, -9545221, -27784654, 14166835, 29815394, 7444469,
+             29551787, -3727419, 19288549, 1325865},
+        },
+        {
+            {15100157, -15835752, -23923978, -1005098, -26450192, 15509408,
+             12376730, -3479146, 33166107, -8042750},
+            {20909231, 13023121, -9209752, 16251778, -5778415, -8094914,
+             12412151, 10018715, 2213263, -13878373},
+            {32529814, -11074689, 30361439, -16689753, -9135940, 1513226,
+             22922121, 6382134, -5766928, 8371348},
+        },
+    },
+    {
+        {
+            {9923462, 11271500, 12616794, 3544722, -29998368, -1721626,
+             12891687, -8193132, -26442943, 10486144},
+            {-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726,
+             2610596, -23921530, -11455195},
+            {5408411, -1136691, -4969122, 10561668, 24145918, 14240566,
+             31319731, -4235541, 19985175, -3436086},
+        },
+        {
+            {-13994457, 16616821, 14549246, 3341099, 32155958, 13648976,
+             -17577068, 8849297, 65030, 8370684},
+            {-8320926, -12049626, 31204563, 5839400, -20627288, -1057277,
+             -19442942, 6922164, 12743482, -9800518},
+            {-2361371, 12678785, 28815050, 4759974, -23893047, 4884717,
+             23783145, 11038569, 18800704, 255233},
+        },
+        {
+            {-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847,
+             9066957, 19258688, -14753793},
+            {-2936654, -10827535, -10432089, 14516793, -3640786, 4372541,
+             -31934921, 2209390, -1524053, 2055794},
+            {580882, 16705327, 5468415, -2683018, -30926419, -14696000,
+             -7203346, -8994389, -30021019, 7394435},
+        },
+        {
+            {23838809, 1822728, -15738443, 15242727, 8318092, -3733104,
+             -21672180, -3492205, -4821741, 14799921},
+            {13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804,
+             13496856, -9056018, 7402518},
+            {2286874, -4435931, -20042458, -2008336, -13696227, 5038122,
+             11006906, -15760352, 8205061, 1607563},
+        },
+        {
+            {14414086, -8002132, 3331830, -3208217, 22249151, -5594188,
+             18364661, -2906958, 30019587, -9029278},
+            {-27688051, 1585953, -10775053, 931069, -29120221, -11002319,
+             -14410829, 12029093, 9944378, 8024},
+            {4368715, -3709630, 29874200, -15022983, -20230386, -11410704,
+             -16114594, -999085, -8142388, 5640030},
+        },
+        {
+            {10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887,
+             -16694564, 15219798, -14327783},
+            {27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605,
+             -1173195, -18342183, 9742717},
+            {6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614,
+             7406442, 12420155, 1994844},
+        },
+        {
+            {14012521, -5024720, -18384453, -9578469, -26485342, -3936439,
+             -13033478, -10909803, 24319929, -6446333},
+            {16412690, -4507367, 10772641, 15929391, -17068788, -4658621,
+             10555945, -10484049, -30102368, -4739048},
+            {22397382, -7767684, -9293161, -12792868, 17166287, -9755136,
+             -27333065, 6199366, 21880021, -12250760},
+        },
+        {
+            {-4283307, 5368523, -31117018, 8163389, -30323063, 3209128,
+             16557151, 8890729, 8840445, 4957760},
+            {-15447727, 709327, -6919446, -10870178, -29777922, 6522332,
+             -21720181, 12130072, -14796503, 5005757},
+            {-2114751, -14308128, 23019042, 15765735, -25269683, 6002752,
+             10183197, -13239326, -16395286, -2176112},
+        },
+    },
+    {
+        {
+            {-19025756, 1632005, 13466291, -7995100, -23640451, 16573537,
+             -32013908, -3057104, 22208662, 2000468},
+            {3065073, -1412761, -25598674, -361432, -17683065, -5703415,
+             -8164212, 11248527, -3691214, -7414184},
+            {10379208, -6045554, 8877319, 1473647, -29291284, -12507580,
+             16690915, 2553332, -3132688, 16400289},
+        },
+        {
+            {15716668, 1254266, -18472690, 7446274, -8448918, 6344164,
+             -22097271, -7285580, 26894937, 9132066},
+            {24158887, 12938817, 11085297, -8177598, -28063478, -4457083,
+             -30576463, 64452, -6817084, -2692882},
+            {13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710,
+             -3418511, -4688006, 2364226},
+        },
+        {
+            {16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024,
+             -11697457, 15445875, -7798101},
+            {29004207, -7867081, 28661402, -640412, -12794003, -7943086,
+             31863255, -4135540, -278050, -15759279},
+            {-6122061, -14866665, -28614905, 14569919, -10857999, -3591829,
+             10343412, -6976290, -29828287, -10815811},
+        },
+        {
+            {27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636,
+             15372179, 17293797, 960709},
+            {20263915, 11434237, -5765435, 11236810, 13505955, -10857102,
+             -16111345, 6493122, -19384511, 7639714},
+            {-2830798, -14839232, 25403038, -8215196, -8317012, -16173699,
+             18006287, -16043750, 29994677, -15808121},
+        },
+        {
+            {9769828, 5202651, -24157398, -13631392, -28051003, -11561624,
+             -24613141, -13860782, -31184575, 709464},
+            {12286395, 13076066, -21775189, -1176622, -25003198, 4057652,
+             -32018128, -8890874, 16102007, 13205847},
+            {13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170,
+             8525972, 10151379, 10394400},
+        },
+        {
+            {4024660, -16137551, 22436262, 12276534, -9099015, -2686099,
+             19698229, 11743039, -33302334, 8934414},
+            {-15879800, -4525240, -8580747, -2934061, 14634845, -698278,
+             -9449077, 3137094, -11536886, 11721158},
+            {17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229,
+             8835153, -9205489, -1280045},
+        },
+        {
+            {-461409, -7830014, 20614118, 16688288, -7514766, -4807119,
+             22300304, 505429, 6108462, -6183415},
+            {-5070281, 12367917, -30663534, 3234473, 32617080, -8422642,
+             29880583, -13483331, -26898490, -7867459},
+            {-31975283, 5726539, 26934134, 10237677, -3173717, -605053,
+             24199304, 3795095, 7592688, -14992079},
+        },
+        {
+            {21594432, -14964228, 17466408, -4077222, 32537084, 2739898,
+             6407723, 12018833, -28256052, 4298412},
+            {-20650503, -11961496, -27236275, 570498, 3767144, -1717540,
+             13891942, -1569194, 13717174, 10805743},
+            {-14676630, -15644296, 15287174, 11927123, 24177847, -8175568,
+             -796431, 14860609, -26938930, -5863836},
+        },
+    },
+    {
+        {
+            {12962541, 5311799, -10060768, 11658280, 18855286, -7954201,
+             13286263, -12808704, -4381056, 9882022},
+            {18512079, 11319350, -20123124, 15090309, 18818594, 5271736,
+             -22727904, 3666879, -23967430, -3299429},
+            {-6789020, -3146043, 16192429, 13241070, 15898607, -14206114,
+             -10084880, -6661110, -2403099, 5276065},
+        },
+        {
+            {30169808, -5317648, 26306206, -11750859, 27814964, 7069267,
+             7152851, 3684982, 1449224, 13082861},
+            {10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382,
+             15056736, -21016438, -8202000},
+            {-33150110, 3261608, 22745853, 7948688, 19370557, -15177665,
+             -26171976, 6482814, -10300080, -11060101},
+        },
+        {
+            {32869458, -5408545, 25609743, 15678670, -10687769, -15471071,
+             26112421, 2521008, -22664288, 6904815},
+            {29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737,
+             3841096, -29003639, -6657642},
+            {10340844, -6630377, -18656632, -2278430, 12621151, -13339055,
+             30878497, -11824370, -25584551, 5181966},
+        },
+        {
+            {25940115, -12658025, 17324188, -10307374, -8671468, 15029094,
+             24396252, -16450922, -2322852, -12388574},
+            {-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390,
+             12641087, 20603771, -6561742},
+            {-18882287, -11673380, 24849422, 11501709, 13161720, -4768874,
+             1925523, 11914390, 4662781, 7820689},
+        },
+        {
+            {12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456,
+             12172924, 16136752, 15264020},
+            {-10349955, -14680563, -8211979, 2330220, -17662549, -14545780,
+             10658213, 6671822, 19012087, 3772772},
+            {3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732,
+             -15762884, 20527771, 12988982},
+        },
+        {
+            {-14822485, -5797269, -3707987, 12689773, -898983, -10914866,
+             -24183046, -10564943, 3299665, -12424953},
+            {-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197,
+             6461331, -25583147, 8991218},
+            {-17226263, 1816362, -1673288, -6086439, 31783888, -8175991,
+             -32948145, 7417950, -30242287, 1507265},
+        },
+        {
+            {29692663, 6829891, -10498800, 4334896, 20945975, -11906496,
+             -28887608, 8209391, 14606362, -10647073},
+            {-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695,
+             9761487, 4170404, -2085325},
+            {-11587470, 14855945, -4127778, -1531857, -26649089, 15084046,
+             22186522, 16002000, -14276837, -8400798},
+        },
+        {
+            {-4811456, 13761029, -31703877, -2483919, -3312471, 7869047,
+             -7113572, -9620092, 13240845, 10965870},
+            {-7742563, -8256762, -14768334, -13656260, -23232383, 12387166,
+             4498947, 14147411, 29514390, 4302863},
+            {-13413405, -12407859, 20757302, -13801832, 14785143, 8976368,
+             -5061276, -2144373, 17846988, -13971927},
+        },
+    },
+    {
+        {
+            {-2244452, -754728, -4597030, -1066309, -6247172, 1455299,
+             -21647728, -9214789, -5222701, 12650267},
+            {-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813,
+             13770293, -19134326, 10958663},
+            {22470984, 12369526, 23446014, -5441109, -21520802, -9698723,
+             -11772496, -11574455, -25083830, 4271862},
+        },
+        {
+            {-25169565, -10053642, -19909332, 15361595, -5984358, 2159192,
+             75375, -4278529, -32526221, 8469673},
+            {15854970, 4148314, -8893890, 7259002, 11666551, 13824734,
+             -30531198, 2697372, 24154791, -9460943},
+            {15446137, -15806644, 29759747, 14019369, 30811221, -9610191,
+             -31582008, 12840104, 24913809, 9815020},
+        },
+        {
+            {-4709286, -5614269, -31841498, -12288893, -14443537, 10799414,
+             -9103676, 13438769, 18735128, 9466238},
+            {11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821,
+             -10896103, -22728655, 16199064},
+            {14576810, 379472, -26786533, -8317236, -29426508, -10812974,
+             -102766, 1876699, 30801119, 2164795},
+        },
+        {
+            {15995086, 3199873, 13672555, 13712240, -19378835, -4647646,
+             -13081610, -15496269, -13492807, 1268052},
+            {-10290614, -3659039, -3286592, 10948818, 23037027, 3794475,
+             -3470338, -12600221, -17055369, 3565904},
+            {29210088, -9419337, -5919792, -4952785, 10834811, -13327726,
+             -16512102, -10820713, -27162222, -14030531},
+        },
+        {
+            {-13161890, 15508588, 16663704, -8156150, -28349942, 9019123,
+             -29183421, -3769423, 2244111, -14001979},
+            {-5152875, -3800936, -9306475, -6071583, 16243069, 14684434,
+             -25673088, -16180800, 13491506, 4641841},
+            {10813417, 643330, -19188515, -728916, 30292062, -16600078,
+             27548447, -7721242, 14476989, -12767431},
+        },
+        {
+            {10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937,
+             -1644259, -27912810, 12651324},
+            {-31185513, -813383, 22271204, 11835308, 10201545, 15351028,
+             17099662, 3988035, 21721536, -3148940},
+            {10202177, -6545839, -31373232, -9574638, -32150642, -8119683,
+             -12906320, 3852694, 13216206, 14842320},
+        },
+        {
+            {-15815640, -10601066, -6538952, -7258995, -6984659, -6581778,
+             -31500847, 13765824, -27434397, 9900184},
+            {14465505, -13833331, -32133984, -14738873, -27443187, 12990492,
+             33046193, 15796406, -7051866, -8040114},
+            {30924417, -8279620, 6359016, -12816335, 16508377, 9071735,
+             -25488601, 15413635, 9524356, -7018878},
+        },
+        {
+            {12274201, -13175547, 32627641, -1785326, 6736625, 13267305,
+             5237659, -5109483, 15663516, 4035784},
+            {-2951309, 8903985, 17349946, 601635, -16432815, -4612556,
+             -13732739, -15889334, -22258478, 4659091},
+            {-16916263, -4952973, -30393711, -15158821, 20774812, 15897498,
+             5736189, 15026997, -2178256, -13455585},
+        },
+    },
+    {
+        {
+            {-8858980, -2219056, 28571666, -10155518, -474467, -10105698,
+             -3801496, 278095, 23440562, -290208},
+            {10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275,
+             11551483, -16571960, -7442864},
+            {17932739, -12437276, -24039557, 10749060, 11316803, 7535897,
+             22503767, 5561594, -3646624, 3898661},
+        },
+        {
+            {7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531,
+             7152530, 21831162, 1245233},
+            {26958459, -14658026, 4314586, 8346991, -5677764, 11960072,
+             -32589295, -620035, -30402091, -16716212},
+            {-12165896, 9166947, 33491384, 13673479, 29787085, 13096535,
+             6280834, 14587357, -22338025, 13987525},
+        },
+        {
+            {-24349909, 7778775, 21116000, 15572597, -4833266, -5357778,
+             -4300898, -5124639, -7469781, -2858068},
+            {9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781,
+             6439245, -14581012, 4091397},
+            {-8426427, 1470727, -28109679, -1596990, 3978627, -5123623,
+             -19622683, 12092163, 29077877, -14741988},
+        },
+        {
+            {5269168, -6859726, -13230211, -8020715, 25932563, 1763552,
+             -5606110, -5505881, -20017847, 2357889},
+            {32264008, -15407652, -5387735, -1160093, -2091322, -3946900,
+             23104804, -12869908, 5727338, 189038},
+            {14609123, -8954470, -6000566, -16622781, -14577387, -7743898,
+             -26745169, 10942115, -25888931, -14884697},
+        },
+        {
+            {20513500, 5557931, -15604613, 7829531, 26413943, -2019404,
+             -21378968, 7471781, 13913677, -5137875},
+            {-25574376, 11967826, 29233242, 12948236, -6754465, 4713227,
+             -8940970, 14059180, 12878652, 8511905},
+            {-25656801, 3393631, -2955415, -7075526, -2250709, 9366908,
+             -30223418, 6812974, 5568676, -3127656},
+        },
+        {
+            {11630004, 12144454, 2116339, 13606037, 27378885, 15676917,
+             -17408753, -13504373, -14395196, 8070818},
+            {27117696, -10007378, -31282771, -5570088, 1127282, 12772488,
+             -29845906, 10483306, -11552749, -1028714},
+            {10637467, -5688064, 5674781, 1072708, -26343588, -6982302,
+             -1683975, 9177853, -27493162, 15431203},
+        },
+        {
+            {20525145, 10892566, -12742472, 12779443, -29493034, 16150075,
+             -28240519, 14943142, -15056790, -7935931},
+            {-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767,
+             -3239766, -3356550, 9594024},
+            {-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683,
+             -6492290, 13352335, -10977084},
+        },
+        {
+            {-1931799, -5407458, 3304649, -12884869, 17015806, -4877091,
+             -29783850, -7752482, -13215537, -319204},
+            {20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742,
+             15077870, -22750759, 14523817},
+            {27406042, -6041657, 27423596, -4497394, 4996214, 10002360,
+             -28842031, -4545494, -30172742, -4805667},
+        },
+    },
+    {
+        {
+            {11374242, 12660715, 17861383, -12540833, 10935568, 1099227,
+             -13886076, -9091740, -27727044, 11358504},
+            {-12730809, 10311867, 1510375, 10778093, -2119455, -9145702,
+             32676003, 11149336, -26123651, 4985768},
+            {-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043,
+             13794114, -19414307, -15621255},
+        },
+        {
+            {6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603,
+             6970005, -1691065, -9004790},
+            {1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622,
+             -5475723, -16796596, -5031438},
+            {-22273315, -13524424, -64685, -4334223, -18605636, -10921968,
+             -20571065, -7007978, -99853, -10237333},
+        },
+        {
+            {17747465, 10039260, 19368299, -4050591, -20630635, -16041286,
+             31992683, -15857976, -29260363, -5511971},
+            {31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999,
+             -3744247, 4882242, -10626905},
+            {29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198,
+             3272828, -5190932, -4162409},
+        },
+        {
+            {12501286, 4044383, -8612957, -13392385, -32430052, 5136599,
+             -19230378, -3529697, 330070, -3659409},
+            {6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522,
+             -8573892, -271295, 12071499},
+            {-8365515, -4042521, 25133448, -4517355, -6211027, 2265927,
+             -32769618, 1936675, -5159697, 3829363},
+        },
+        {
+            {28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550,
+             -6567787, 26333140, 14267664},
+            {-11067219, 11871231, 27385719, -10559544, -4585914, -11189312,
+             10004786, -8709488, -21761224, 8930324},
+            {-21197785, -16396035, 25654216, -1725397, 12282012, 11008919,
+             1541940, 4757911, -26491501, -16408940},
+        },
+        {
+            {13537262, -7759490, -20604840, 10961927, -5922820, -13218065,
+             -13156584, 6217254, -15943699, 13814990},
+            {-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681,
+             9257833, -1956526, -1776914},
+            {-25045300, -10191966, 15366585, 15166509, -13105086, 8423556,
+             -29171540, 12361135, -18685978, 4578290},
+        },
+        {
+            {24579768, 3711570, 1342322, -11180126, -27005135, 14124956,
+             -22544529, 14074919, 21964432, 8235257},
+            {-6528613, -2411497, 9442966, -5925588, 12025640, -1487420,
+             -2981514, -1669206, 13006806, 2355433},
+            {-16304899, -13605259, -6632427, -5142349, 16974359, -10911083,
+             27202044, 1719366, 1141648, -12796236},
+        },
+        {
+            {-12863944, -13219986, -8318266, -11018091, -6810145, -4843894,
+             13475066, -3133972, 32674895, 13715045},
+            {11423335, -5468059, 32344216, 8962751, 24989809, 9241752,
+             -13265253, 16086212, -28740881, -15642093},
+            {-1409668, 12530728, -6368726, 10847387, 19531186, -14132160,
+             -11709148, 7791794, -27245943, 4383347},
+        },
+    },
+    {
+        {
+            {-28970898, 5271447, -1266009, -9736989, -12455236, 16732599,
+             -4862407, -4906449, 27193557, 6245191},
+            {-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898,
+             3260492, 22510453, 8577507},
+            {-12632451, 11257346, -32692994, 13548177, -721004, 10879011,
+             31168030, 13952092, -29571492, -3635906},
+        },
+        {
+            {3877321, -9572739, 32416692, 5405324, -11004407, -13656635,
+             3759769, 11935320, 5611860, 8164018},
+            {-16275802, 14667797, 15906460, 12155291, -22111149, -9039718,
+             32003002, -8832289, 5773085, -8422109},
+            {-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725,
+             12376320, 31632953, 190926},
+        },
+        {
+            {-24593607, -16138885, -8423991, 13378746, 14162407, 6901328,
+             -8288749, 4508564, -25341555, -3627528},
+            {8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941,
+             -14786005, -1672488, 827625},
+            {-32720583, -16289296, -32503547, 7101210, 13354605, 2659080,
+             -1800575, -14108036, -24878478, 1541286},
+        },
+        {
+            {2901347, -1117687, 3880376, -10059388, -17620940, -3612781,
+             -21802117, -3567481, 20456845, -1885033},
+            {27019610, 12299467, -13658288, -1603234, -12861660, -4861471,
+             -19540150, -5016058, 29439641, 15138866},
+            {21536104, -6626420, -32447818, -10690208, -22408077, 5175814,
+             -5420040, -16361163, 7779328, 109896},
+        },
+        {
+            {30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390,
+             12180118, 23177719, -554075},
+            {26572847, 3405927, -31701700, 12890905, -19265668, 5335866,
+             -6493768, 2378492, 4439158, -13279347},
+            {-22716706, 3489070, -9225266, -332753, 18875722, -1140095,
+             14819434, -12731527, -17717757, -5461437},
+        },
+        {
+            {-5056483, 16566551, 15953661, 3767752, -10436499, 15627060,
+             -820954, 2177225, 8550082, -15114165},
+            {-18473302, 16596775, -381660, 15663611, 22860960, 15585581,
+             -27844109, -3582739, -23260460, -8428588},
+            {-32480551, 15707275, -8205912, -5652081, 29464558, 2713815,
+             -22725137, 15860482, -21902570, 1494193},
+        },
+        {
+            {-19562091, -14087393, -25583872, -9299552, 13127842, 759709,
+             21923482, 16529112, 8742704, 12967017},
+            {-28464899, 1553205, 32536856, -10473729, -24691605, -406174,
+             -8914625, -2933896, -29903758, 15553883},
+            {21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572,
+             14513274, 19375923, -12647961},
+        },
+        {
+            {8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818,
+             -6222716, 2862653, 9455043},
+            {29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124,
+             -2990080, 15511449, 4789663},
+            {-20679756, 7004547, 8824831, -9434977, -4045704, -3750736,
+             -5754762, 108893, 23513200, 16652362},
+        },
+    },
+    {
+        {
+            {-33256173, 4144782, -4476029, -6579123, 10770039, -7155542,
+             -6650416, -12936300, -18319198, 10212860},
+            {2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801,
+             2600940, -9988298, -12506466},
+            {-24645692, 13317462, -30449259, -15653928, 21365574, -10869657,
+             11344424, 864440, -2499677, -16710063},
+        },
+        {
+            {-26432803, 6148329, -17184412, -14474154, 18782929, -275997,
+             -22561534, 211300, 2719757, 4940997},
+            {-1323882, 3911313, -6948744, 14759765, -30027150, 7851207,
+             21690126, 8518463, 26699843, 5276295},
+            {-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586,
+             149635, -15452774, 7159369},
+        },
+        {
+            {9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009,
+             8312176, 22477218, -8403385},
+            {18155857, -16504990, 19744716, 9006923, 15154154, -10538976,
+             24256460, -4864995, -22548173, 9334109},
+            {2986088, -4911893, 10776628, -3473844, 10620590, -7083203,
+             -21413845, 14253545, -22587149, 536906},
+        },
+        {
+            {4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551,
+             10589625, 10838060, -15420424},
+            {-19342404, 867880, 9277171, -3218459, -14431572, -1986443,
+             19295826, -15796950, 6378260, 699185},
+            {7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039,
+             15693155, -5045064, -13373962},
+        },
+        {
+            {-7737563, -5869402, -14566319, -7406919, 11385654, 13201616,
+             31730678, -10962840, -3918636, -9669325},
+            {10188286, -15770834, -7336361, 13427543, 22223443, 14896287,
+             30743455, 7116568, -21786507, 5427593},
+            {696102, 13206899, 27047647, -10632082, 15285305, -9853179,
+             10798490, -4578720, 19236243, 12477404},
+        },
+        {
+            {-11229439, 11243796, -17054270, -8040865, -788228, -8167967,
+             -3897669, 11180504, -23169516, 7733644},
+            {17800790, -14036179, -27000429, -11766671, 23887827, 3149671,
+             23466177, -10538171, 10322027, 15313801},
+            {26246234, 11968874, 32263343, -5468728, 6830755, -13323031,
+             -15794704, -101982, -24449242, 10890804},
+        },
+        {
+            {-31365647, 10271363, -12660625, -6267268, 16690207, -13062544,
+             -14982212, 16484931, 25180797, -5334884},
+            {-586574, 10376444, -32586414, -11286356, 19801893, 10997610,
+             2276632, 9482883, 316878, 13820577},
+            {-9882808, -4510367, -2115506, 16457136, -11100081, 11674996,
+             30756178, -7515054, 30696930, -3712849},
+        },
+        {
+            {32988917, -9603412, 12499366, 7910787, -10617257, -11931514,
+             -7342816, -9985397, -32349517, 7392473},
+            {-8855661, 15927861, 9866406, -3649411, -2396914, -16655781,
+             -30409476, -9134995, 25112947, -2926644},
+            {-2504044, -436966, 25621774, -5678772, 15085042, -5479877,
+             -24884878, -13526194, 5537438, -13914319},
+        },
+    },
+    {
+        {
+            {-11225584, 2320285, -9584280, 10149187, -33444663, 5808648,
+             -14876251, -1729667, 31234590, 6090599},
+            {-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721,
+             15878753, -6970405, -9034768},
+            {-27757857, 247744, -15194774, -9002551, 23288161, -10011936,
+             -23869595, 6503646, 20650474, 1804084},
+        },
+        {
+            {-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995,
+             -10329713, 27842616, -202328},
+            {-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656,
+             5031932, -11375082, 12714369},
+            {20807691, -7270825, 29286141, 11421711, -27876523, -13868230,
+             -21227475, 1035546, -19733229, 12796920},
+        },
+        {
+            {12076899, -14301286, -8785001, -11848922, -25012791, 16400684,
+             -17591495, -12899438, 3480665, -15182815},
+            {-32361549, 5457597, 28548107, 7833186, 7303070, -11953545,
+             -24363064, -15921875, -33374054, 2771025},
+            {-21389266, 421932, 26597266, 6860826, 22486084, -6737172,
+             -17137485, -4210226, -24552282, 15673397},
+        },
+        {
+            {-20184622, 2338216, 19788685, -9620956, -4001265, -8740893,
+             -20271184, 4733254, 3727144, -12934448},
+            {6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594,
+             7975683, 31123697, -10958981},
+            {30069250, -11435332, 30434654, 2958439, 18399564, -976289,
+             12296869, 9204260, -16432438, 9648165},
+        },
+        {
+            {32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266,
+             5248604, -26008332, -11377501},
+            {17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711,
+             15298639, 2662509, -16297073},
+            {-1172927, -7558695, -4366770, -4287744, -21346413, -8434326,
+             32087529, -1222777, 32247248, -14389861},
+        },
+        {
+            {14312628, 1221556, 17395390, -8700143, -4945741, -8684635,
+             -28197744, -9637817, -16027623, -13378845},
+            {-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502,
+             9803137, 17597934, 2346211},
+            {18510800, 15337574, 26171504, 981392, -22241552, 7827556,
+             -23491134, -11323352, 3059833, -11782870},
+        },
+        {
+            {10141598, 6082907, 17829293, -1947643, 9830092, 13613136,
+             -25556636, -5544586, -33502212, 3592096},
+            {33114168, -15889352, -26525686, -13343397, 33076705, 8716171,
+             1151462, 1521897, -982665, -6837803},
+            {-32939165, -4255815, 23947181, -324178, -33072974, -12305637,
+             -16637686, 3891704, 26353178, 693168},
+        },
+        {
+            {30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294,
+             -400668, 31375464, 14369965},
+            {-14370654, -7772529, 1510301, 6434173, -18784789, -6262728,
+             32732230, -13108839, 17901441, 16011505},
+            {18171223, -11934626, -12500402, 15197122, -11038147, -15230035,
+             -19172240, -16046376, 8764035, 12309598},
+        },
+    },
+    {
+        {
+            {5975908, -5243188, -19459362, -9681747, -11541277, 14015782,
+             -23665757, 1228319, 17544096, -10593782},
+            {5811932, -1715293, 3442887, -2269310, -18367348, -8359541,
+             -18044043, -15410127, -5565381, 12348900},
+            {-31399660, 11407555, 25755363, 6891399, -3256938, 14872274,
+             -24849353, 8141295, -10632534, -585479},
+        },
+        {
+            {-12675304, 694026, -5076145, 13300344, 14015258, -14451394,
+             -9698672, -11329050, 30944593, 1130208},
+            {8247766, -6710942, -26562381, -7709309, -14401939, -14648910,
+             4652152, 2488540, 23550156, -271232},
+            {17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737,
+             -5908146, -408818, -137719},
+        },
+        {
+            {16091085, -16253926, 18599252, 7340678, 2137637, -1221657,
+             -3364161, 14550936, 3260525, -7166271},
+            {-4910104, -13332887, 18550887, 10864893, -16459325, -7291596,
+             -23028869, -13204905, -12748722, 2701326},
+            {-8574695, 16099415, 4629974, -16340524, -20786213, -6005432,
+             -10018363, 9276971, 11329923, 1862132},
+        },
+        {
+            {14763076, -15903608, -30918270, 3689867, 3511892, 10313526,
+             -21951088, 12219231, -9037963, -940300},
+            {8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216,
+             -2909717, -15438168, 11595570},
+            {15214962, 3537601, -26238722, -14058872, 4418657, -15230761,
+             13947276, 10730794, -13489462, -4363670},
+        },
+        {
+            {-2538306, 7682793, 32759013, 263109, -29984731, -7955452,
+             -22332124, -10188635, 977108, 699994},
+            {-12466472, 4195084, -9211532, 550904, -15565337, 12917920,
+             19118110, -439841, -30534533, -14337913},
+            {31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237,
+             -10051775, 12493932, -5409317},
+        },
+        {
+            {-25680606, 5260744, -19235809, -6284470, -3695942, 16566087,
+             27218280, 2607121, 29375955, 6024730},
+            {842132, -2794693, -4763381, -8722815, 26332018, -12405641,
+             11831880, 6985184, -9940361, 2854096},
+            {-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645,
+             960770, 12121869, 16648078},
+        },
+        {
+            {-15218652, 14667096, -13336229, 2013717, 30598287, -464137,
+             -31504922, -7882064, 20237806, 2838411},
+            {-19288047, 4453152, 15298546, -16178388, 22115043, -15972604,
+             12544294, -13470457, 1068881, -12499905},
+            {-9558883, -16518835, 33238498, 13506958, 30505848, -1114596,
+             -8486907, -2630053, 12521378, 4845654},
+        },
+        {
+            {-28198521, 10744108, -2958380, 10199664, 7759311, -13088600,
+             3409348, -873400, -6482306, -12885870},
+            {-23561822, 6230156, -20382013, 10655314, -24040585, -11621172,
+             10477734, -1240216, -3113227, 13974498},
+            {12966261, 15550616, -32038948, -1615346, 21025980, -629444,
+             5642325, 7188737, 18895762, 12629579},
+        },
+    },
+    {
+        {
+            {14741879, -14946887, 22177208, -11721237, 1279741, 8058600,
+             11758140, 789443, 32195181, 3895677},
+            {10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575,
+             -3566119, -8982069, 4429647},
+            {-2453894, 15725973, -20436342, -10410672, -5803908, -11040220,
+             -7135870, -11642895, 18047436, -15281743},
+        },
+        {
+            {-25173001, -11307165, 29759956, 11776784, -22262383, -15820455,
+             10993114, -12850837, -17620701, -9408468},
+            {21987233, 700364, -24505048, 14972008, -7774265, -5718395,
+             32155026, 2581431, -29958985, 8773375},
+            {-25568350, 454463, -13211935, 16126715, 25240068, 8594567,
+             20656846, 12017935, -7874389, -13920155},
+        },
+        {
+            {6028182, 6263078, -31011806, -11301710, -818919, 2461772,
+             -31841174, -5468042, -1721788, -2776725},
+            {-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845,
+             -4166698, 28408820, 6816612},
+            {-10358094, -8237829, 19549651, -12169222, 22082623, 16147817,
+             20613181, 13982702, -10339570, 5067943},
+        },
+        {
+            {-30505967, -3821767, 12074681, 13582412, -19877972, 2443951,
+             -19719286, 12746132, 5331210, -10105944},
+            {30528811, 3601899, -1957090, 4619785, -27361822, -15436388,
+             24180793, -12570394, 27679908, -1648928},
+            {9402404, -13957065, 32834043, 10838634, -26580150, -13237195,
+             26653274, -8685565, 22611444, -12715406},
+        },
+        {
+            {22190590, 1118029, 22736441, 15130463, -30460692, -5991321,
+             19189625, -4648942, 4854859, 6622139},
+            {-8310738, -2953450, -8262579, -3388049, -10401731, -271929,
+             13424426, -3567227, 26404409, 13001963},
+            {-31241838, -15415700, -2994250, 8939346, 11562230, -12840670,
+             -26064365, -11621720, -15405155, 11020693},
+        },
+        {
+            {1866042, -7949489, -7898649, -10301010, 12483315, 13477547,
+             3175636, -12424163, 28761762, 1406734},
+            {-448555, -1777666, 13018551, 3194501, -9580420, -11161737,
+             24760585, -4347088, 25577411, -13378680},
+            {-24290378, 4759345, -690653, -1852816, 2066747, 10693769,
+             -29595790, 9884936, -9368926, 4745410},
+        },
+        {
+            {-9141284, 6049714, -19531061, -4341411, -31260798, 9944276,
+             -15462008, -11311852, 10931924, -11931931},
+            {-16561513, 14112680, -8012645, 4817318, -8040464, -11414606,
+             -22853429, 10856641, -20470770, 13434654},
+            {22759489, -10073434, -16766264, -1871422, 13637442, -10168091,
+             1765144, -12654326, 28445307, -5364710},
+        },
+        {
+            {29875063, 12493613, 2795536, -3786330, 1710620, 15181182,
+             -10195717, -8788675, 9074234, 1167180},
+            {-26205683, 11014233, -9842651, -2635485, -26908120, 7532294,
+             -18716888, -9535498, 3843903, 9367684},
+            {-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123,
+             8601684, -139197, 4242895},
+        },
+    },
+    {
+        {
+            {22092954, -13191123, -2042793, -11968512, 32186753, -11517388,
+             -6574341, 2470660, -27417366, 16625501},
+            {-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857,
+             2602725, -27351616, 14247413},
+            {6314175, -10264892, -32772502, 15957557, -10157730, 168750,
+             -8618807, 14290061, 27108877, -1180880},
+        },
+        {
+            {-8586597, -7170966, 13241782, 10960156, -32991015, -13794596,
+             33547976, -11058889, -27148451, 981874},
+            {22833440, 9293594, -32649448, -13618667, -9136966, 14756819,
+             -22928859, -13970780, -10479804, -16197962},
+            {-7768587, 3326786, -28111797, 10783824, 19178761, 14905060,
+             22680049, 13906969, -15933690, 3797899},
+        },
+        {
+            {21721356, -4212746, -12206123, 9310182, -3882239, -13653110,
+             23740224, -2709232, 20491983, -8042152},
+            {9209270, -15135055, -13256557, -6167798, -731016, 15289673,
+             25947805, 15286587, 30997318, -6703063},
+            {7392032, 16618386, 23946583, -8039892, -13265164, -1533858,
+             -14197445, -2321576, 17649998, -250080},
+        },
+        {
+            {-9301088, -14193827, 30609526, -3049543, -25175069, -1283752,
+             -15241566, -9525724, -2233253, 7662146},
+            {-17558673, 1763594, -33114336, 15908610, -30040870, -12174295,
+             7335080, -8472199, -3174674, 3440183},
+            {-19889700, -5977008, -24111293, -9688870, 10799743, -16571957,
+             40450, -4431835, 4862400, 1133},
+        },
+        {
+            {-32856209, -7873957, -5422389, 14860950, -16319031, 7956142,
+             7258061, 311861, -30594991, -7379421},
+            {-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763,
+             16527196, 18278453, 15405622},
+            {-4381906, 8508652, -19898366, -3674424, -5984453, 15149970,
+             -13313598, 843523, -21875062, 13626197},
+        },
+        {
+            {2281448, -13487055, -10915418, -2609910, 1879358, 16164207,
+             -10783882, 3953792, 13340839, 15928663},
+            {31727126, -7179855, -18437503, -8283652, 2875793, -16390330,
+             -25269894, -7014826, -23452306, 5964753},
+            {4100420, -5959452, -17179337, 6017714, -18705837, 12227141,
+             -26684835, 11344144, 2538215, -7570755},
+        },
+        {
+            {-9433605, 6123113, 11159803, -2156608, 30016280, 14966241,
+             -20474983, 1485421, -629256, -15958862},
+            {-26804558, 4260919, 11851389, 9658551, -32017107, 16367492,
+             -20205425, -13191288, 11659922, -11115118},
+            {26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568,
+             -10170080, 33100372, -1306171},
+        },
+        {
+            {15121113, -5201871, -10389905, 15427821, -27509937, -15992507,
+             21670947, 4486675, -5931810, -14466380},
+            {16166486, -9483733, -11104130, 6023908, -31926798, -1364923,
+             2340060, -16254968, -10735770, -10039824},
+            {28042865, -3557089, -12126526, 12259706, -3717498, -6945899,
+             6766453, -8689599, 18036436, 5803270},
+        },
+    },
+    {
+        {
+            {-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391,
+             4598332, -6159431, -14117438},
+            {-31031306, -14256194, 17332029, -2383520, 31312682, -5967183,
+             696309, 50292, -20095739, 11763584},
+            {-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117,
+             -12613632, -19773211, -10713562},
+        },
+        {
+            {30464590, -11262872, -4127476, -12734478, 19835327, -7105613,
+             -24396175, 2075773, -17020157, 992471},
+            {18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841,
+             8080033, -11574335, -10601610},
+            {19598397, 10334610, 12555054, 2555664, 18821899, -10339780,
+             21873263, 16014234, 26224780, 16452269},
+        },
+        {
+            {-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804,
+             -7618186, -20533829, 3698650},
+            {14187449, 3448569, -10636236, -10810935, -22663880, -3433596,
+             7268410, -10890444, 27394301, 12015369},
+            {19695761, 16087646, 28032085, 12999827, 6817792, 11427614,
+             20244189, -1312777, -13259127, -3402461},
+        },
+        {
+            {30860103, 12735208, -1888245, -4699734, -16974906, 2256940,
+             -8166013, 12298312, -8550524, -10393462},
+            {-5719826, -11245325, -1910649, 15569035, 26642876, -7587760,
+             -5789354, -15118654, -4976164, 12651793},
+            {-2848395, 9953421, 11531313, -5282879, 26895123, -12697089,
+             -13118820, -16517902, 9768698, -2533218},
+        },
+        {
+            {-24719459, 1894651, -287698, -4704085, 15348719, -8156530,
+             32767513, 12765450, 4940095, 10678226},
+            {18860224, 15980149, -18987240, -1562570, -26233012, -11071856,
+             -7843882, 13944024, -24372348, 16582019},
+            {-15504260, 4970268, -29893044, 4175593, -20993212, -2199756,
+             -11704054, 15444560, -11003761, 7989037},
+        },
+        {
+            {31490452, 5568061, -2412803, 2182383, -32336847, 4531686,
+             -32078269, 6200206, -19686113, -14800171},
+            {-17308668, -15879940, -31522777, -2831, -32887382, 16375549,
+             8680158, -16371713, 28550068, -6857132},
+            {-28126887, -5688091, 16837845, -1820458, -6850681, 12700016,
+             -30039981, 4364038, 1155602, 5988841},
+        },
+        {
+            {21890435, -13272907, -12624011, 12154349, -7831873, 15300496,
+             23148983, -4470481, 24618407, 8283181},
+            {-33136107, -10512751, 9975416, 6841041, -31559793, 16356536,
+             3070187, -7025928, 1466169, 10740210},
+            {-1509399, -15488185, -13503385, -10655916, 32799044, 909394,
+             -13938903, -5779719, -32164649, -15327040},
+        },
+        {
+            {3960823, -14267803, -28026090, -15918051, -19404858, 13146868,
+             15567327, 951507, -3260321, -573935},
+            {24740841, 5052253, -30094131, 8961361, 25877428, 6165135,
+             -24368180, 14397372, -7380369, -6144105},
+            {-28888365, 3510803, -28103278, -1158478, -11238128, -10631454,
+             -15441463, -14453128, -1625486, -6494814},
+        },
+    },
+    {
+        {
+            {793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843,
+             -4885251, -9906200, -621852},
+            {5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374,
+             1468826, -6171428, -15186581},
+            {-4859255, -3779343, -2917758, -6748019, 7778750, 11688288,
+             -30404353, -9871238, -1558923, -9863646},
+        },
+        {
+            {10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958,
+             14783338, -30581476, -15757844},
+            {10566929, 12612572, -31944212, 11118703, -12633376, 12362879,
+             21752402, 8822496, 24003793, 14264025},
+            {27713862, -7355973, -11008240, 9227530, 27050101, 2504721,
+             23886875, -13117525, 13958495, -5732453},
+        },
+        {
+            {-23481610, 4867226, -27247128, 3900521, 29838369, -8212291,
+             -31889399, -10041781, 7340521, -15410068},
+            {4646514, -8011124, -22766023, -11532654, 23184553, 8566613,
+             31366726, -1381061, -15066784, -10375192},
+            {-17270517, 12723032, -16993061, 14878794, 21619651, -6197576,
+             27584817, 3093888, -8843694, 3849921},
+        },
+        {
+            {-9064912, 2103172, 25561640, -15125738, -5239824, 9582958,
+             32477045, -9017955, 5002294, -15550259},
+            {-12057553, -11177906, 21115585, -13365155, 8808712, -12030708,
+             16489530, 13378448, -25845716, 12741426},
+            {-5946367, 10645103, -30911586, 15390284, -3286982, -7118677,
+             24306472, 15852464, 28834118, -7646072},
+        },
+        {
+            {-17335748, -9107057, -24531279, 9434953, -8472084, -583362,
+             -13090771, 455841, 20461858, 5491305},
+            {13669248, -16095482, -12481974, -10203039, -14569770, -11893198,
+             -24995986, 11293807, -28588204, -9421832},
+            {28497928, 6272777, -33022994, 14470570, 8906179, -1225630,
+             18504674, -14165166, 29867745, -8795943},
+        },
+        {
+            {-16207023, 13517196, -27799630, -13697798, 24009064, -6373891,
+             -6367600, -13175392, 22853429, -4012011},
+            {24191378, 16712145, -13931797, 15217831, 14542237, 1646131,
+             18603514, -11037887, 12876623, -2112447},
+            {17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753,
+             608397, 16031844, 3723494},
+        },
+        {
+            {-28632773, 12763728, -20446446, 7577504, 33001348, -13017745,
+             17558842, -7872890, 23896954, -4314245},
+            {-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064,
+             7229064, -9919646, -8826859},
+            {28816045, 298879, -28165016, -15920938, 19000928, -1665890,
+             -12680833, -2949325, -18051778, -2082915},
+        },
+        {
+            {16000882, -344896, 3493092, -11447198, -29504595, -13159789,
+             12577740, 16041268, -19715240, 7847707},
+            {10151868, 10572098, 27312476, 7922682, 14825339, 4723128,
+             -32855931, -6519018, -10020567, 3852848},
+            {-11430470, 15697596, -21121557, -4420647, 5386314, 15063598,
+             16514493, -15932110, 29330899, -15076224},
+        },
+    },
+    {
+        {
+            {-25499735, -4378794, -15222908, -6901211, 16615731, 2051784,
+             3303702, 15490, -27548796, 12314391},
+            {15683520, -6003043, 18109120, -9980648, 15337968, -5997823,
+             -16717435, 15921866, 16103996, -3731215},
+            {-23169824, -10781249, 13588192, -1628807, -3798557, -1074929,
+             -19273607, 5402699, -29815713, -9841101},
+        },
+        {
+            {23190676, 2384583, -32714340, 3462154, -29903655, -1529132,
+             -11266856, 8911517, -25205859, 2739713},
+            {21374101, -3554250, -33524649, 9874411, 15377179, 11831242,
+             -33529904, 6134907, 4931255, 11987849},
+            {-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539,
+             13861388, -30076310, 10117930},
+        },
+        {
+            {-29501170, -10744872, -26163768, 13051539, -25625564, 5089643,
+             -6325503, 6704079, 12890019, 15728940},
+            {-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376,
+             -10428139, 12885167, 8311031},
+            {-17516482, 5352194, 10384213, -13811658, 7506451, 13453191,
+             26423267, 4384730, 1888765, -5435404},
+        },
+        {
+            {-25817338, -3107312, -13494599, -3182506, 30896459, -13921729,
+             -32251644, -12707869, -19464434, -3340243},
+            {-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245,
+             14845197, 17151279, -9854116},
+            {-24830458, -12733720, -15165978, 10367250, -29530908, -265356,
+             22825805, -7087279, -16866484, 16176525},
+        },
+        {
+            {-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182,
+             -10363426, -28746253, -10197509},
+            {-10626600, -4486402, -13320562, -5125317, 3432136, -6393229,
+             23632037, -1940610, 32808310, 1099883},
+            {15030977, 5768825, -27451236, -2887299, -6427378, -15361371,
+             -15277896, -6809350, 2051441, -15225865},
+        },
+        {
+            {-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398,
+             -14154188, -22686354, 16633660},
+            {4577086, -16752288, 13249841, -15304328, 19958763, -14537274,
+             18559670, -10759549, 8402478, -9864273},
+            {-28406330, -1051581, -26790155, -907698, -17212414, -11030789,
+             9453451, -14980072, 17983010, 9967138},
+        },
+        {
+            {-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990,
+             7806337, 17507396, 3651560},
+            {-10420457, -4118111, 14584639, 15971087, -15768321, 8861010,
+             26556809, -5574557, -18553322, -11357135},
+            {2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121,
+             8459447, -5605463, -7621941},
+        },
+        {
+            {-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813,
+             -849066, 17258084, -7977739},
+            {18164541, -10595176, -17154882, -1542417, 19237078, -9745295,
+             23357533, -15217008, 26908270, 12150756},
+            {-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168,
+             -5537701, -32302074, 16215819},
+        },
+    },
+    {
+        {
+            {-6898905, 9824394, -12304779, -4401089, -31397141, -6276835,
+             32574489, 12532905, -7503072, -8675347},
+            {-27343522, -16515468, -27151524, -10722951, 946346, 16291093,
+             254968, 7168080, 21676107, -1943028},
+            {21260961, -8424752, -16831886, -11920822, -23677961, 3968121,
+             -3651949, -6215466, -3556191, -7913075},
+        },
+        {
+            {16544754, 13250366, -16804428, 15546242, -4583003, 12757258,
+             -2462308, -8680336, -18907032, -9662799},
+            {-2415239, -15577728, 18312303, 4964443, -15272530, -12653564,
+             26820651, 16690659, 25459437, -4564609},
+            {-25144690, 11425020, 28423002, -11020557, -6144921, -15826224,
+             9142795, -2391602, -6432418, -1644817},
+        },
+        {
+            {-23104652, 6253476, 16964147, -3768872, -25113972, -12296437,
+             -27457225, -16344658, 6335692, 7249989},
+            {-30333227, 13979675, 7503222, -12368314, -11956721, -4621693,
+             -30272269, 2682242, 25993170, -12478523},
+            {4364628, 5930691, 32304656, -10044554, -8054781, 15091131,
+             22857016, -10598955, 31820368, 15075278},
+        },
+        {
+            {31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788,
+             -9650886, -17970238, 12833045},
+            {19073683, 14851414, -24403169, -11860168, 7625278, 11091125,
+             -19619190, 2074449, -9413939, 14905377},
+            {24483667, -11935567, -2518866, -11547418, -1553130, 15355506,
+             -25282080, 9253129, 27628530, -7555480},
+        },
+        {
+            {17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324,
+             -9157582, -14110875, 15297016},
+            {510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417,
+             -11864220, 8683221, 2921426},
+            {18606791, 11874196, 27155355, -5281482, -24031742, 6265446,
+             -25178240, -1278924, 4674690, 13890525},
+        },
+        {
+            {13609624, 13069022, -27372361, -13055908, 24360586, 9592974,
+             14977157, 9835105, 4389687, 288396},
+            {9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062,
+             8317628, 23388070, 16052080},
+            {12720016, 11937594, -31970060, -5028689, 26900120, 8561328,
+             -20155687, -11632979, -14754271, -10812892},
+        },
+        {
+            {15961858, 14150409, 26716931, -665832, -22794328, 13603569,
+             11829573, 7467844, -28822128, 929275},
+            {11038231, -11582396, -27310482, -7316562, -10498527, -16307831,
+             -23479533, -9371869, -21393143, 2465074},
+            {20017163, -4323226, 27915242, 1529148, 12396362, 15675764,
+             13817261, -9658066, 2463391, -4622140},
+        },
+        {
+            {-16358878, -12663911, -12065183, 4996454, -1256422, 1073572,
+             9583558, 12851107, 4003896, 12673717},
+            {-1731589, -15155870, -3262930, 16143082, 19294135, 13385325,
+             14741514, -9103726, 7903886, 2348101},
+            {24536016, -16515207, 12715592, -3862155, 1511293, 10047386,
+             -3842346, -7129159, -28377538, 10048127},
+        },
+    },
+    {
+        {
+            {-12622226, -6204820, 30718825, 2591312, -10617028, 12192840,
+             18873298, -7297090, -32297756, 15221632},
+            {-26478122, -11103864, 11546244, -1852483, 9180880, 7656409,
+             -21343950, 2095755, 29769758, 6593415},
+            {-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345,
+             -6118678, 30958054, 8292160},
+        },
+        {
+            {31429822, -13959116, 29173532, 15632448, 12174511, -2760094,
+             32808831, 3977186, 26143136, -3148876},
+            {22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633,
+             -1674433, -3758243, -2304625},
+            {-15491917, 8012313, -2514730, -12702462, -23965846, -10254029,
+             -1612713, -1535569, -16664475, 8194478},
+        },
+        {
+            {27338066, -7507420, -7414224, 10140405, -19026427, -6589889,
+             27277191, 8855376, 28572286, 3005164},
+            {26287124, 4821776, 25476601, -4145903, -3764513, -15788984,
+             -18008582, 1182479, -26094821, -13079595},
+            {-7171154, 3178080, 23970071, 6201893, -17195577, -4489192,
+             -21876275, -13982627, 32208683, -1198248},
+        },
+        {
+            {-16657702, 2817643, -10286362, 14811298, 6024667, 13349505,
+             -27315504, -10497842, -27672585, -11539858},
+            {15941029, -9405932, -21367050, 8062055, 31876073, -238629,
+             -15278393, -1444429, 15397331, -4130193},
+            {8934485, -13485467, -23286397, -13423241, -32446090, 14047986,
+             31170398, -1441021, -27505566, 15087184},
+        },
+        {
+            {-18357243, -2156491, 24524913, -16677868, 15520427, -6360776,
+             -15502406, 11461896, 16788528, -5868942},
+            {-1947386, 16013773, 21750665, 3714552, -17401782, -16055433,
+             -3770287, -10323320, 31322514, -11615635},
+            {21426655, -5650218, -13648287, -5347537, -28812189, -4920970,
+             -18275391, -14621414, 13040862, -12112948},
+        },
+        {
+            {11293895, 12478086, -27136401, 15083750, -29307421, 14748872,
+             14555558, -13417103, 1613711, 4896935},
+            {-25894883, 15323294, -8489791, -8057900, 25967126, -13425460,
+             2825960, -4897045, -23971776, -11267415},
+            {-15924766, -5229880, -17443532, 6410664, 3622847, 10243618,
+             20615400, 12405433, -23753030, -8436416},
+        },
+        {
+            {-7091295, 12556208, -20191352, 9025187, -17072479, 4333801,
+             4378436, 2432030, 23097949, -566018},
+            {4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264,
+             10103221, -18512313, 2424778},
+            {366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678,
+             1344109, -3642553, 12412659},
+        },
+        {
+            {-24001791, 7690286, 14929416, -168257, -32210835, -13412986,
+             24162697, -15326504, -3141501, 11179385},
+            {18289522, -14724954, 8056945, 16430056, -21729724, 7842514,
+             -6001441, -1486897, -18684645, -11443503},
+            {476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959,
+             13403813, 11052904, 5219329},
+        },
+    },
+    {
+        {
+            {20678546, -8375738, -32671898, 8849123, -5009758, 14574752,
+             31186971, -3973730, 9014762, -8579056},
+            {-13644050, -10350239, -15962508, 5075808, -1514661, -11534600,
+             -33102500, 9160280, 8473550, -3256838},
+            {24900749, 14435722, 17209120, -15292541, -22592275, 9878983,
+             -7689309, -16335821, -24568481, 11788948},
+        },
+        {
+            {-3118155, -11395194, -13802089, 14797441, 9652448, -6845904,
+             -20037437, 10410733, -24568470, -1458691},
+            {-15659161, 16736706, -22467150, 10215878, -9097177, 7563911,
+             11871841, -12505194, -18513325, 8464118},
+            {-23400612, 8348507, -14585951, -861714, -3950205, -6373419,
+             14325289, 8628612, 33313881, -8370517},
+        },
+        {
+            {-20186973, -4967935, 22367356, 5271547, -1097117, -4788838,
+             -24805667, -10236854, -8940735, -5818269},
+            {-6948785, -1795212, -32625683, -16021179, 32635414, -7374245,
+             15989197, -12838188, 28358192, -4253904},
+            {-23561781, -2799059, -32351682, -1661963, -9147719, 10429267,
+             -16637684, 4072016, -5351664, 5596589},
+        },
+        {
+            {-28236598, -3390048, 12312896, 6213178, 3117142, 16078565,
+             29266239, 2557221, 1768301, 15373193},
+            {-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902,
+             -4504991, -24660491, 3442910},
+            {-30210571, 5124043, 14181784, 8197961, 18964734, -11939093,
+             22597931, 7176455, -18585478, 13365930},
+        },
+        {
+            {-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107,
+             -8570186, -9689599, -3031667},
+            {25008904, -10771599, -4305031, -9638010, 16265036, 15721635,
+             683793, -11823784, 15723479, -15163481},
+            {-9660625, 12374379, -27006999, -7026148, -7724114, -12314514,
+             11879682, 5400171, 519526, -1235876},
+        },
+        {
+            {22258397, -16332233, -7869817, 14613016, -22520255, -2950923,
+             -20353881, 7315967, 16648397, 7605640},
+            {-8081308, -8464597, -8223311, 9719710, 19259459, -15348212,
+             23994942, -5281555, -9468848, 4763278},
+            {-21699244, 9220969, -15730624, 1084137, -25476107, -2852390,
+             31088447, -7764523, -11356529, 728112},
+        },
+        {
+            {26047220, -11751471, -6900323, -16521798, 24092068, 9158119,
+             -4273545, -12555558, -29365436, -5498272},
+            {17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007,
+             12327945, 10750447, 10014012},
+            {-10312768, 3936952, 9156313, -8897683, 16498692, -994647,
+             -27481051, -666732, 3424691, 7540221},
+        },
+        {
+            {30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422,
+             -16317219, -9244265, 15258046},
+            {13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406,
+             2711395, 1062915, -5136345},
+            {-19240248, -11254599, -29509029, -7499965, -5835763, 13005411,
+             -6066489, 12194497, 32960380, 1459310},
+        },
+    },
+    {
+        {
+            {19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197,
+             -6101885, 18638003, -11174937},
+            {31395534, 15098109, 26581030, 8030562, -16527914, -5007134,
+             9012486, -7584354, -6643087, -5442636},
+            {-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222,
+             9677543, -32294889, -6456008},
+        },
+        {
+            {-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579,
+             -7839692, -7852844, -8138429},
+            {-15236356, -15433509, 7766470, 746860, 26346930, -10221762,
+             -27333451, 10754588, -9431476, 5203576},
+            {31834314, 14135496, -770007, 5159118, 20917671, -16768096,
+             -7467973, -7337524, 31809243, 7347066},
+        },
+        {
+            {-9606723, -11874240, 20414459, 13033986, 13716524, -11691881,
+             19797970, -12211255, 15192876, -2087490},
+            {-12663563, -2181719, 1168162, -3804809, 26747877, -14138091,
+             10609330, 12694420, 33473243, -13382104},
+            {33184999, 11180355, 15832085, -11385430, -1633671, 225884,
+             15089336, -11023903, -6135662, 14480053},
+        },
+        {
+            {31308717, -5619998, 31030840, -1897099, 15674547, -6582883,
+             5496208, 13685227, 27595050, 8737275},
+            {-20318852, -15150239, 10933843, -16178022, 8335352, -7546022,
+             -31008351, -12610604, 26498114, 66511},
+            {22644454, -8761729, -16671776, 4884562, -3105614, -13559366,
+             30540766, -4286747, -13327787, -7515095},
+        },
+        {
+            {-28017847, 9834845, 18617207, -2681312, -3401956, -13307506,
+             8205540, 13585437, -17127465, 15115439},
+            {23711543, -672915, 31206561, -8362711, 6164647, -9709987,
+             -33535882, -1426096, 8236921, 16492939},
+            {-23910559, -13515526, -26299483, -4503841, 25005590, -7687270,
+             19574902, 10071562, 6708380, -6222424},
+        },
+        {
+            {2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017,
+             9328700, 29955601, -11678310},
+            {3096359, 9271816, -21620864, -15521844, -14847996, -7592937,
+             -25892142, -12635595, -9917575, 6216608},
+            {-32615849, 338663, -25195611, 2510422, -29213566, -13820213,
+             24822830, -6146567, -26767480, 7525079},
+        },
+        {
+            {-23066649, -13985623, 16133487, -7896178, -3389565, 778788,
+             -910336, -2782495, -19386633, 11994101},
+            {21691500, -13624626, -641331, -14367021, 3285881, -3483596,
+             -25064666, 9718258, -7477437, 13381418},
+            {18445390, -4202236, 14979846, 11622458, -1727110, -3582980,
+             23111648, -6375247, 28535282, 15779576},
+        },
+        {
+            {30098053, 3089662, -9234387, 16662135, -21306940, 11308411,
+             -14068454, 12021730, 9955285, -16303356},
+            {9734894, -14576830, -7473633, -9138735, 2060392, 11313496,
+             -18426029, 9924399, 20194861, 13380996},
+            {-26378102, -7965207, -22167821, 15789297, -18055342, -6168792,
+             -1984914, 15707771, 26342023, 10146099},
+        },
+    },
+    {
+        {
+            {-26016874, -219943, 21339191, -41388, 19745256, -2878700,
+             -29637280, 2227040, 21612326, -545728},
+            {-13077387, 1184228, 23562814, -5970442, -20351244, -6348714,
+             25764461, 12243797, -20856566, 11649658},
+            {-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944,
+             6114064, 33514190, 2333242},
+        },
+        {
+            {-21433588, -12421821, 8119782, 7219913, -21830522, -9016134,
+             -6679750, -12670638, 24350578, -13450001},
+            {-4116307, -11271533, -23886186, 4843615, -30088339, 690623,
+             -31536088, -10406836, 8317860, 12352766},
+            {18200138, -14475911, -33087759, -2696619, -23702521, -9102511,
+             -23552096, -2287550, 20712163, 6719373},
+        },
+        {
+            {26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530,
+             -3763210, 26224235, -3297458},
+            {-17168938, -14854097, -3395676, -16369877, -19954045, 14050420,
+             21728352, 9493610, 18620611, -16428628},
+            {-13323321, 13325349, 11432106, 5964811, 18609221, 6062965,
+             -5269471, -9725556, -30701573, -16479657},
+        },
+        {
+            {-23860538, -11233159, 26961357, 1640861, -32413112, -16737940,
+             12248509, -5240639, 13735342, 1934062},
+            {25089769, 6742589, 17081145, -13406266, 21909293, -16067981,
+             -15136294, -3765346, -21277997, 5473616},
+            {31883677, -7961101, 1083432, -11572403, 22828471, 13290673,
+             -7125085, 12469656, 29111212, -5451014},
+        },
+        {
+            {24244947, -15050407, -26262976, 2791540, -14997599, 16666678,
+             24367466, 6388839, -10295587, 452383},
+            {-25640782, -3417841, 5217916, 16224624, 19987036, -4082269,
+             -24236251, -5915248, 15766062, 8407814},
+            {-20406999, 13990231, 15495425, 16395525, 5377168, 15166495,
+             -8917023, -4388953, -8067909, 2276718},
+        },
+        {
+            {30157918, 12924066, -17712050, 9245753, 19895028, 3368142,
+             -23827587, 5096219, 22740376, -7303417},
+            {2041139, -14256350, 7783687, 13876377, -25946985, -13352459,
+             24051124, 13742383, -15637599, 13295222},
+            {33338237, -8505733, 12532113, 7977527, 9106186, -1715251,
+             -17720195, -4612972, -4451357, -14669444},
+        },
+        {
+            {-20045281, 5454097, -14346548, 6447146, 28862071, 1883651,
+             -2469266, -4141880, 7770569, 9620597},
+            {23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528,
+             -1694323, -33502340, -14767970},
+            {1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801,
+             1220118, 30494170, -11440799},
+        },
+        {
+            {-5037580, -13028295, -2970559, -3061767, 15640974, -6701666,
+             -26739026, 926050, -1684339, -13333647},
+            {13908495, -3549272, 30919928, -6273825, -21521863, 7989039,
+             9021034, 9078865, 3353509, 4033511},
+            {-29663431, -15113610, 32259991, -344482, 24295849, -12912123,
+             23161163, 8839127, 27485041, 7356032},
+        },
+    },
+    {
+        {
+            {9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142,
+             2625015, 28431036, -16771834},
+            {-23839233, -8311415, -25945511, 7480958, -17681669, -8354183,
+             -22545972, 14150565, 15970762, 4099461},
+            {29262576, 16756590, 26350592, -8793563, 8529671, -11208050,
+             13617293, -9937143, 11465739, 8317062},
+        },
+        {
+            {-25493081, -6962928, 32500200, -9419051, -23038724, -2302222,
+             14898637, 3848455, 20969334, -5157516},
+            {-20384450, -14347713, -18336405, 13884722, -33039454, 2842114,
+             -21610826, -3649888, 11177095, 14989547},
+            {-24496721, -11716016, 16959896, 2278463, 12066309, 10137771,
+             13515641, 2581286, -28487508, 9930240},
+        },
+        {
+            {-17751622, -2097826, 16544300, -13009300, -15914807, -14949081,
+             18345767, -13403753, 16291481, -5314038},
+            {-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774,
+             6957617, 4368891, 9788741},
+            {16660756, 7281060, -10830758, 12911820, 20108584, -8101676,
+             -21722536, -8613148, 16250552, -11111103},
+        },
+        {
+            {-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584,
+             10604807, -30190403, 4782747},
+            {-1354539, 14736941, -7367442, -13292886, 7710542, -14155590,
+             -9981571, 4383045, 22546403, 437323},
+            {31665577, -12180464, -16186830, 1491339, -18368625, 3294682,
+             27343084, 2786261, -30633590, -14097016},
+        },
+        {
+            {-14467279, -683715, -33374107, 7448552, 19294360, 14334329,
+             -19690631, 2355319, -19284671, -6114373},
+            {15121312, -15796162, 6377020, -6031361, -10798111, -12957845,
+             18952177, 15496498, -29380133, 11754228},
+            {-2637277, -13483075, 8488727, -14303896, 12728761, -1622493,
+             7141596, 11724556, 22761615, -10134141},
+        },
+        {
+            {16918416, 11729663, -18083579, 3022987, -31015732, -13339659,
+             -28741185, -12227393, 32851222, 11717399},
+            {11166634, 7338049, -6722523, 4531520, -29468672, -7302055,
+             31474879, 3483633, -1193175, -4030831},
+            {-185635, 9921305, 31456609, -13536438, -12013818, 13348923,
+             33142652, 6546660, -19985279, -3948376},
+        },
+        {
+            {-32460596, 11266712, -11197107, -7899103, 31703694, 3855903,
+             -8537131, -12833048, -30772034, -15486313},
+            {-18006477, 12709068, 3991746, -6479188, -21491523, -10550425,
+             -31135347, -16049879, 10928917, 3011958},
+            {-6957757, -15594337, 31696059, 334240, 29576716, 14796075,
+             -30831056, -12805180, 18008031, 10258577},
+        },
+        {
+            {-22448644, 15655569, 7018479, -4410003, -30314266, -1201591,
+             -1853465, 1367120, 25127874, 6671743},
+            {29701166, -14373934, -10878120, 9279288, -17568, 13127210,
+             21382910, 11042292, 25838796, 4642684},
+            {-20430234, 14955537, -24126347, 8124619, -5369288, -5990470,
+             30468147, -13900640, 18423289, 4177476},
+        },
+    },
+};
+
+static uint8_t negative(signed char b) {
+  uint32_t x = b;
+  x >>= 31; /* 1: yes; 0: no */
+  return x;
+}
+
+static void table_select(ge_precomp *t, int pos, signed char b) {
+  ge_precomp minust;
+  uint8_t bnegative = negative(b);
+  uint8_t babs = b - (((-bnegative) & b) << 1);
+
+  ge_precomp_0(t);
+  cmov(t, &k25519Precomp[pos][0], equal(babs, 1));
+  cmov(t, &k25519Precomp[pos][1], equal(babs, 2));
+  cmov(t, &k25519Precomp[pos][2], equal(babs, 3));
+  cmov(t, &k25519Precomp[pos][3], equal(babs, 4));
+  cmov(t, &k25519Precomp[pos][4], equal(babs, 5));
+  cmov(t, &k25519Precomp[pos][5], equal(babs, 6));
+  cmov(t, &k25519Precomp[pos][6], equal(babs, 7));
+  cmov(t, &k25519Precomp[pos][7], equal(babs, 8));
+  fe_copy(minust.yplusx, t->yminusx);
+  fe_copy(minust.yminusx, t->yplusx);
+  fe_neg(minust.xy2d, t->xy2d);
+  cmov(t, &minust, bnegative);
+}
+
+/* h = a * B
+ * where a = a[0]+256*a[1]+...+256^31 a[31]
+ * B is the Ed25519 base point (x,4/5) with x positive.
+ *
+ * Preconditions:
+ *   a[31] <= 127 */
+static void ge_scalarmult_base(ge_p3 *h, const uint8_t *a) {
+  signed char e[64];
+  signed char carry;
+  ge_p1p1 r;
+  ge_p2 s;
+  ge_precomp t;
+  int i;
+
+  for (i = 0; i < 32; ++i) {
+    e[2 * i + 0] = (a[i] >> 0) & 15;
+    e[2 * i + 1] = (a[i] >> 4) & 15;
+  }
+  /* each e[i] is between 0 and 15 */
+  /* e[63] is between 0 and 7 */
+
+  carry = 0;
+  for (i = 0; i < 63; ++i) {
+    e[i] += carry;
+    carry = e[i] + 8;
+    carry >>= 4;
+    e[i] -= carry << 4;
+  }
+  e[63] += carry;
+  /* each e[i] is between -8 and 8 */
+
+  ge_p3_0(h);
+  for (i = 1; i < 64; i += 2) {
+    table_select(&t, i / 2, e[i]);
+    ge_madd(&r, h, &t);
+    ge_p1p1_to_p3(h, &r);
+  }
+
+  ge_p3_dbl(&r, h);
+  ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s);
+  ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s);
+  ge_p1p1_to_p2(&s, &r);
+  ge_p2_dbl(&r, &s);
+  ge_p1p1_to_p3(h, &r);
+
+  for (i = 0; i < 64; i += 2) {
+    table_select(&t, i / 2, e[i]);
+    ge_madd(&r, h, &t);
+    ge_p1p1_to_p3(h, &r);
+  }
+}
+
+#endif
+
+#if defined(OPENSSL_X25519_X86_64)
+
+static void x25519_scalar_mult(uint8_t out[32], const uint8_t scalar[32],
+                               const uint8_t point[32]) {
+  x25519_x86_64(out, scalar, point);
+}
+
+#else
+
+/* Replace (f,g) with (g,f) if b == 1;
+ * replace (f,g) with (f,g) if b == 0.
+ *
+ * Preconditions: b in {0,1}. */
+static void fe_cswap(fe f, fe g, unsigned int b) {
+  size_t i;
+  b = 0-b;
+  for (i = 0; i < 10; i++) {
+    int32_t x = f[i] ^ g[i];
+    x &= b;
+    f[i] ^= x;
+    g[i] ^= x;
+  }
+}
+
+/* h = f * 121666
+ * Can overlap h with f.
+ *
+ * Preconditions:
+ *    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+ *
+ * Postconditions:
+ *    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. */
+static void fe_mul121666(fe h, fe f) {
+  int32_t f0 = f[0];
+  int32_t f1 = f[1];
+  int32_t f2 = f[2];
+  int32_t f3 = f[3];
+  int32_t f4 = f[4];
+  int32_t f5 = f[5];
+  int32_t f6 = f[6];
+  int32_t f7 = f[7];
+  int32_t f8 = f[8];
+  int32_t f9 = f[9];
+  int64_t h0 = f0 * (int64_t) 121666;
+  int64_t h1 = f1 * (int64_t) 121666;
+  int64_t h2 = f2 * (int64_t) 121666;
+  int64_t h3 = f3 * (int64_t) 121666;
+  int64_t h4 = f4 * (int64_t) 121666;
+  int64_t h5 = f5 * (int64_t) 121666;
+  int64_t h6 = f6 * (int64_t) 121666;
+  int64_t h7 = f7 * (int64_t) 121666;
+  int64_t h8 = f8 * (int64_t) 121666;
+  int64_t h9 = f9 * (int64_t) 121666;
+  int64_t carry0;
+  int64_t carry1;
+  int64_t carry2;
+  int64_t carry3;
+  int64_t carry4;
+  int64_t carry5;
+  int64_t carry6;
+  int64_t carry7;
+  int64_t carry8;
+  int64_t carry9;
+
+  carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+  carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+  carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+  carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+  carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+  carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+  carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+  carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+  carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+  carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+  h[0] = h0;
+  h[1] = h1;
+  h[2] = h2;
+  h[3] = h3;
+  h[4] = h4;
+  h[5] = h5;
+  h[6] = h6;
+  h[7] = h7;
+  h[8] = h8;
+  h[9] = h9;
+}
+
+static void x25519_scalar_mult_generic(uint8_t out[32],
+                                       const uint8_t scalar[32],
+                                       const uint8_t point[32]) {
+  fe x1, x2, z2, x3, z3, tmp0, tmp1;
+  uint8_t e[32];
+  unsigned swap = 0;
+  int pos;
+
+  memcpy(e, scalar, 32);
+  e[0] &= 248;
+  e[31] &= 127;
+  e[31] |= 64;
+  fe_frombytes(x1, point);
+  fe_1(x2);
+  fe_0(z2);
+  fe_copy(x3, x1);
+  fe_1(z3);
+
+  for (pos = 254; pos >= 0; --pos) {
+    unsigned b = 1 & (e[pos / 8] >> (pos & 7));
+    swap ^= b;
+    fe_cswap(x2, x3, swap);
+    fe_cswap(z2, z3, swap);
+    swap = b;
+    fe_sub(tmp0, x3, z3);
+    fe_sub(tmp1, x2, z2);
+    fe_add(x2, x2, z2);
+    fe_add(z2, x3, z3);
+    fe_mul(z3, tmp0, x2);
+    fe_mul(z2, z2, tmp1);
+    fe_sq(tmp0, tmp1);
+    fe_sq(tmp1, x2);
+    fe_add(x3, z3, z2);
+    fe_sub(z2, z3, z2);
+    fe_mul(x2, tmp1, tmp0);
+    fe_sub(tmp1, tmp1, tmp0);
+    fe_sq(z2, z2);
+    fe_mul121666(z3, tmp1);
+    fe_sq(x3, x3);
+    fe_add(tmp0, tmp0, z3);
+    fe_mul(z3, x1, z2);
+    fe_mul(z2, tmp1, tmp0);
+  }
+  fe_cswap(x2, x3, swap);
+  fe_cswap(z2, z3, swap);
+
+  fe_invert(z2, z2);
+  fe_mul(x2, x2, z2);
+  fe_tobytes(out, x2);
+}
+
+static void x25519_scalar_mult(uint8_t out[32], const uint8_t scalar[32],
+                               const uint8_t point[32]) {
+  x25519_scalar_mult_generic(out, scalar, point);
+}
+
+#endif  /* OPENSSL_X25519_X86_64 */
+
+int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
+           const uint8_t peer_public_value[32]) {
+  static const uint8_t kZeros[32] = {0};
+  x25519_scalar_mult(out_shared_key, private_key, peer_public_value);
+  /* The all-zero output results when the input is a point of small order. */
+  return CRYPTO_memcmp(kZeros, out_shared_key, 32) != 0;
+}
+
+#if defined(OPENSSL_X25519_X86_64)
+
+/* When |OPENSSL_X25519_X86_64| is set, base point multiplication is done with
+ * the Montgomery ladder because it's faster. Otherwise it's done using the
+ * Ed25519 tables. */
+
+void X25519_public_from_private(uint8_t out_public_value[32],
+                                const uint8_t private_key[32]) {
+  static const uint8_t kMongomeryBasePoint[32] = {9};
+  x25519_scalar_mult(out_public_value, private_key, kMongomeryBasePoint);
+}
+
+#else
+
+void X25519_public_from_private(uint8_t out_public_value[32],
+                                const uint8_t private_key[32]) {
+  uint8_t e[32];
+  ge_p3 A;
+  fe zplusy, zminusy, zminusy_inv;
+
+  memcpy(e, private_key, 32);
+  e[0] &= 248;
+  e[31] &= 127;
+  e[31] |= 64;
+
+  ge_scalarmult_base(&A, e);
+
+  /* We only need the u-coordinate of the curve25519 point. The map is
+   * u=(y+1)/(1-y). Since y=Y/Z, this gives u=(Z+Y)/(Z-Y). */
+  fe_add(zplusy, A.Z, A.Y);
+  fe_sub(zminusy, A.Z, A.Y);
+  fe_invert(zminusy_inv, zminusy);
+  fe_mul(zplusy, zplusy, zminusy_inv);
+  fe_tobytes(out_public_value, zplusy);
+}
+
+#endif  /* OPENSSL_X25519_X86_64 */
diff --git a/crypto/ec/ec2_smpl.c b/crypto/ec/ec2_smpl.c
index c2ff3f6..4204366 100644
--- a/crypto/ec/ec2_smpl.c
+++ b/crypto/ec/ec2_smpl.c
@@ -85,6 +85,7 @@ const EC_METHOD *EC_GF2m_simple_method(void)
         ec_GF2m_simple_group_set_curve,
         ec_GF2m_simple_group_get_curve,
         ec_GF2m_simple_group_get_degree,
+        0, /* group_order_bits */
         ec_GF2m_simple_group_check_discriminant,
         ec_GF2m_simple_point_init,
         ec_GF2m_simple_point_finish,
diff --git a/crypto/ec/ec_25519.c b/crypto/ec/ec_25519.c
new file mode 100644
index 0000000..3e6609a
--- /dev/null
+++ b/crypto/ec/ec_25519.c
@@ -0,0 +1,381 @@
+/*
+ * Written by Dr Stephen N Henson (steve at openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2016 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing at OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <string.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include "ec_lcl.h"
+
+/* Length of Curve 25519 keys */
+#define EC_X25519_KEYLEN    32
+/* Group degree and order bits */
+#define EC_X25519_BITS      253
+
+/* Copy Curve25519 public key buffer, allocating is necessary */
+static int x25519_init_public(EC_POINT *pub, const void *src)
+{
+    if (pub->custom_data == NULL) {
+        pub->custom_data = OPENSSL_malloc(EC_X25519_KEYLEN);
+        if (pub->custom_data == NULL)
+            return 0;
+    }
+    if (src != NULL)
+        memcpy(pub->custom_data, src, EC_X25519_KEYLEN);
+    return 1;
+}
+
+/* Copy Curve25519 private key buffer, allocating is necessary */
+static int x25519_init_private(EC_KEY *dst, const void *src)
+{
+    if (dst->custom_data == NULL) {
+        dst->custom_data = OPENSSL_secure_malloc(EC_X25519_KEYLEN);
+        if (dst->custom_data == NULL)
+            return 0;
+    }
+    if (src != NULL)
+        memcpy(dst->custom_data, src, EC_X25519_KEYLEN);
+    return 1;
+}
+
+static int x25519_group_init(EC_GROUP *grp)
+{
+    return 1;
+}
+
+static int x25519_group_copy(EC_GROUP *dst, const EC_GROUP *src)
+{
+    return 1;
+}
+
+static int x25519_group_get_degree(const EC_GROUP *src)
+{
+    return EC_X25519_BITS;
+}
+
+static int x25519_group_order_bits(const EC_GROUP *src)
+{
+    return EC_X25519_BITS;
+}
+
+static int x25519_set_private(EC_KEY *eckey, const BIGNUM *priv_key)
+{
+    if (BN_num_bytes(priv_key) > EC_X25519_KEYLEN)
+        return 0;
+    if (x25519_init_private(eckey, NULL))
+        return 0;
+    /* Convert BIGNUM form private key to internal format */
+    if (BN_bn2lebinpad(priv_key, eckey->custom_data, EC_X25519_KEYLEN)
+        != EC_X25519_KEYLEN)
+        return 0;
+    return 1;
+}
+
+static int x25519_keycheck(const EC_KEY *eckey)
+{
+    const char *pubkey;
+    if (eckey->pub_key == NULL)
+        return 0;
+    pubkey = eckey->pub_key->custom_data;
+    if (pubkey == NULL)
+        return 0;
+    if (eckey->custom_data != NULL) {
+        uint8_t tmp[EC_X25519_KEYLEN];
+        /* Check eckey->priv_key exists and matches eckey->custom_data */
+        if (eckey->priv_key == NULL)
+            return 0;
+        if (BN_bn2lebinpad(eckey->priv_key, tmp, EC_X25519_KEYLEN)
+            != EC_X25519_KEYLEN
+            || CRYPTO_memcmp(tmp, eckey->custom_data,
+                             EC_X25519_KEYLEN) != 0) {
+            OPENSSL_cleanse(tmp, EC_X25519_KEYLEN);
+            return 0;
+        }
+        X25519_public_from_private(tmp, eckey->custom_data);
+        if (CRYPTO_memcmp(pubkey, tmp, EC_X25519_KEYLEN) == 0)
+            return 1;
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+static int x25519_keygenpub(EC_KEY *eckey)
+{
+    X25519_public_from_private(eckey->pub_key->custom_data,
+                               eckey->custom_data);
+    return 1;
+}
+
+static int x25519_keygen(EC_KEY *eckey)
+{
+    unsigned char *key;
+    if (x25519_init_private(eckey, NULL) == 0)
+        return 0;
+    key = eckey->custom_data;
+    if (RAND_bytes(key, EC_X25519_KEYLEN) <= 0)
+        return 0;
+    key[0] &= 248;
+    key[31] &= 127;
+    key[31] |= 64;
+    /*
+     * Although the private key is kept as an array in eckey->custom_data
+     * Set eckey->priv_key too so existing code which uses
+     * EC_KEY_get0_private_key() still works.
+     */
+    if (eckey->priv_key == NULL)
+        eckey->priv_key = BN_secure_new();
+    if (eckey->priv_key == NULL)
+        return 0;
+    if (BN_lebin2bn(eckey->custom_data, EC_X25519_KEYLEN, eckey->priv_key) ==
+        NULL)
+        return 0;
+    if (eckey->pub_key == NULL)
+        eckey->pub_key = EC_POINT_new(eckey->group);
+    if (eckey->pub_key == NULL)
+        return 0;
+    return x25519_keygenpub(eckey);
+}
+
+static void x25519_keyfinish(EC_KEY *eckey)
+{
+    OPENSSL_secure_free(eckey->custom_data);
+    eckey->custom_data = NULL;
+}
+
+static int x25519_keycopy(EC_KEY *dest, const EC_KEY *src)
+{
+    if (src->custom_data == NULL)
+        return 0;
+    return x25519_init_private(dest, src->custom_data);
+}
+
+static int x25519_oct2priv(EC_KEY *eckey, unsigned char *buf, size_t len)
+{
+    if (len != EC_X25519_KEYLEN)
+        return 0;
+    if (x25519_init_private(eckey, buf) == 0)
+        return 0;
+    /*
+     * Although the private key is kept as an array in eckey->custom_data
+     * Set eckey->priv_key too so existing code which uses
+     * EC_KEY_get0_private_key() still works.
+     */
+    if (eckey->priv_key == NULL)
+        eckey->priv_key = BN_secure_new();
+    if (eckey->priv_key == NULL)
+        return 0;
+    if (BN_lebin2bn(buf, EC_X25519_KEYLEN, eckey->priv_key) == NULL)
+        return 0;
+    return 1;
+}
+
+static size_t x25519_priv2oct(const EC_KEY *eckey,
+                              unsigned char *buf, size_t len)
+{
+    size_t keylen = EC_X25519_KEYLEN;
+    if (eckey->custom_data == NULL)
+        return 0;
+    if (buf != NULL) {
+        if (len < keylen)
+            return 0;
+        memcpy(buf, eckey->custom_data, keylen);
+    }
+    return keylen;
+}
+
+static int x25519_point_init(EC_POINT *pt)
+{
+    return x25519_init_public(pt, NULL);
+}
+
+static void x25519_point_finish(EC_POINT *pt)
+{
+    OPENSSL_free(pt->custom_data);
+    pt->custom_data = NULL;
+}
+
+static void x25519_point_clear_finish(EC_POINT *pt)
+{
+    OPENSSL_clear_free(pt->custom_data, EC_X25519_KEYLEN);
+    pt->custom_data = NULL;
+}
+
+static int x25519_point_copy(EC_POINT *dst, const EC_POINT *src)
+{
+    memcpy(dst->custom_data, src->custom_data, EC_X25519_KEYLEN);
+    return 1;
+}
+
+static size_t x25519_point2oct(const EC_GROUP *grp, const EC_POINT *pt,
+                               point_conversion_form_t form,
+                               unsigned char *buf, size_t len, BN_CTX *ctx)
+{
+    if (buf != NULL) {
+        if (len < EC_X25519_KEYLEN)
+            return 0;
+        memcpy(buf, pt->custom_data, EC_X25519_KEYLEN);
+    }
+    return EC_X25519_KEYLEN;
+}
+
+static int x25519_oct2point(const EC_GROUP *grp, EC_POINT *pt,
+                            const unsigned char *buf, size_t len, BN_CTX *ctx)
+{
+    unsigned char *pubkey = pt->custom_data;
+    if (len != EC_X25519_KEYLEN)
+        return 0;
+    memcpy(pubkey, buf, EC_X25519_KEYLEN);
+    /* Mask off MSB */
+    pubkey[EC_X25519_KEYLEN - 1] &= 0x7F;
+    return 1;
+}
+
+static int x25519_point_cmp(const EC_GROUP *group, const EC_POINT *a,
+                            const EC_POINT *b, BN_CTX *ctx)
+{
+    /* Shouldn't happen as initialised to non-zero */
+    if (a->custom_data == NULL || b->custom_data == NULL)
+        return -1;
+
+    if (CRYPTO_memcmp(a->custom_data, b->custom_data, EC_X25519_KEYLEN) == 0)
+        return 0;
+
+    return 1;
+}
+
+static int x25519_compute_key(void *out, size_t outlen,
+                              const EC_POINT *pub_key, const EC_KEY *ecdh,
+                              void *(*KDF) (const void *in, size_t inlen,
+                                            void *out, size_t *outlen))
+{
+    unsigned char *key;
+    int ret = -1;
+    if (ecdh->custom_data == NULL)
+        return -1;
+    key = OPENSSL_malloc(EC_X25519_KEYLEN);
+    if (key == NULL)
+        return -1;
+    if (X25519(key, ecdh->custom_data, pub_key->custom_data) == 0)
+        goto err;
+    if (KDF) {
+        if (KDF(key, EC_X25519_KEYLEN, out, &outlen) == NULL)
+            goto err;
+        ret = outlen;
+    } else {
+        if (outlen > EC_X25519_KEYLEN)
+            outlen = EC_X25519_KEYLEN;
+        memcpy(out, key, outlen);
+        ret = outlen;
+    }
+
+ err:
+    OPENSSL_clear_free(key, EC_X25519_KEYLEN);
+    return ret;
+}
+
+const EC_METHOD *ec_x25519_meth(void)
+{
+    static const EC_METHOD ret = {
+        EC_FLAGS_CUSTOM_CURVE | EC_FLAGS_NO_SIGN,
+        NID_undef,
+        x25519_group_init,      /* group_init */
+        0,                      /* group_finish */
+        0,                      /* group_clear_finish */
+        x25519_group_copy,      /* group_copy */
+        0,                      /* group_set_curve */
+        0,                      /* group_get_curve */
+        x25519_group_get_degree,
+        x25519_group_order_bits,
+        0,                      /* group_check_discriminant */
+        x25519_point_init,
+        x25519_point_finish,
+        x25519_point_clear_finish,
+        x25519_point_copy,
+        0,                      /* point_set_to_infinity */
+        0,                      /* set_Jprojective_coordinates_GFp */
+        0,                      /* get_Jprojective_coordinates_GFp */
+        0,                      /* point_set_affine_coordinates */
+        0,                      /* point_get_affine_coordinates */
+        0,                      /* point_set_compressed_coordinates */
+        x25519_point2oct,
+        x25519_oct2point,
+        0,                      /* simple_add */
+        0,                      /* simple_dbl */
+        0,                      /* simple_invert */
+        0,                      /* simple_is_at_infinity */
+        0,                      /* simple_is_on_curve */
+        x25519_point_cmp,
+        0,                      /* simple_make_affine */
+        0,                      /* simple_points_make_affine */
+        0,                      /* points_mul */
+        0,                      /* precompute_mult */
+        0,                      /* have_precompute_mult */
+        0,                      /* field_mul */
+        0,                      /* field_sqr */
+        0,                      /* field_div */
+        0,                      /* field_encode */
+        0,                      /* field_decode */
+        0,                      /* field_set_to_one */
+        x25519_priv2oct,
+        x25519_oct2priv,
+        x25519_set_private,
+        x25519_keygen,
+        x25519_keycheck,
+        x25519_keygenpub,
+        x25519_keycopy,
+        x25519_keyfinish,
+        x25519_compute_key
+    };
+
+    return &ret;
+}
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index d56e6cd..4e02e5a 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -342,7 +342,7 @@ static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
             ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB);
             goto err;
         }
-    } else                      /* nid == NID_X9_62_characteristic_two_field */
+    } else if (nid == NID_X9_62_characteristic_two_field)
 #ifdef OPENSSL_NO_EC2M
     {
         ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_GF2M_NOT_SUPPORTED);
@@ -417,6 +417,10 @@ static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
         }
     }
 #endif
+    else {
+        ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_UNSUPPORTED_FIELD);
+        goto err;
+    }
 
     ok = 1;
 
@@ -1035,24 +1039,16 @@ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
 
         pub_oct = ASN1_STRING_data(priv_key->publicKey);
         pub_oct_len = ASN1_STRING_length(priv_key->publicKey);
-        /*
-         * The first byte - point conversion form - must be present.
-         */
-        if (pub_oct_len <= 0) {
-            ECerr(EC_F_D2I_ECPRIVATEKEY, EC_R_BUFFER_TOO_SMALL);
-            goto err;
-        }
-        /* Save the point conversion form. */
-        ret->conv_form = (point_conversion_form_t) (pub_oct[0] & ~0x01);
-        if (!EC_POINT_oct2point(ret->group, ret->pub_key,
-                                pub_oct, (size_t)(pub_oct_len), NULL)) {
+        if (!EC_KEY_oct2key(ret, pub_oct, pub_oct_len, NULL)) {
             ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
             goto err;
         }
     } else {
-        if (!EC_POINT_mul
-            (ret->group, ret->pub_key, ret->priv_key, NULL, NULL, NULL)) {
-            ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+        if (ret->group->meth->keygenpub != NULL) {
+            if (ret->group->meth->keygenpub(ret) == 0)
+                goto err;
+        } else if (!EC_POINT_mul(ret->group, ret->pub_key, ret->priv_key, NULL,
+                                 NULL, NULL)) {
             goto err;
         }
         /* Remember the original private-key-only encoding. */
@@ -1195,17 +1191,10 @@ EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len)
         return 0;
     }
     ret = *a;
-    if (ret->pub_key == NULL &&
-        (ret->pub_key = EC_POINT_new(ret->group)) == NULL) {
-        ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_MALLOC_FAILURE);
-        return 0;
-    }
-    if (!EC_POINT_oct2point(ret->group, ret->pub_key, *in, len, NULL)) {
+    if (!EC_KEY_oct2key(ret, *in, len, NULL)) {
         ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_EC_LIB);
         return 0;
     }
-    /* save the point conversion form */
-    ret->conv_form = (point_conversion_form_t) (*in[0] & ~0x01);
     *in += len;
     return ret;
 }
diff --git a/crypto/ec/ec_check.c b/crypto/ec/ec_check.c
index aa35322..601559f 100644
--- a/crypto/ec/ec_check.c
+++ b/crypto/ec/ec_check.c
@@ -62,6 +62,10 @@ int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
     BN_CTX *new_ctx = NULL;
     EC_POINT *point = NULL;
 
+    /* Custom curves assumed to be correct */
+    if ((group->meth->flags & EC_FLAGS_CUSTOM_CURVE) != 0)
+        return 1;
+
     if (ctx == NULL) {
         ctx = new_ctx = BN_CTX_new();
         if (ctx == NULL) {
diff --git a/crypto/ec/ec_curve.c b/crypto/ec/ec_curve.c
index 107beb5..a95d519 100644
--- a/crypto/ec/ec_curve.c
+++ b/crypto/ec/ec_curve.c
@@ -3020,6 +3020,7 @@ static const ec_list_element curve_list[] = {
      "RFC 5639 curve over a 512 bit prime field"},
     {NID_brainpoolP512t1, &_EC_brainpoolP512t1.h, 0,
      "RFC 5639 curve over a 512 bit prime field"},
+    {NID_X25519, NULL, ec_x25519_meth, "X25519"},
 };
 
 #define curve_list_length OSSL_NELEM(curve_list)
@@ -3037,6 +3038,10 @@ static EC_GROUP *ec_group_new_from_data(const ec_list_element curve)
     const EC_CURVE_DATA *data;
     const unsigned char *params;
 
+    /* If no curve data curve method must handle everything */
+    if (curve.data == NULL)
+        return EC_GROUP_new(curve.meth != NULL ? curve.meth() : NULL);
+
     if ((ctx = BN_CTX_new()) == NULL) {
         ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_MALLOC_FAILURE);
         goto err;
diff --git a/crypto/ec/ec_err.c b/crypto/ec/ec_err.c
index b4edc21..399e4c7 100644
--- a/crypto/ec/ec_err.c
+++ b/crypto/ec/ec_err.c
@@ -1,4 +1,3 @@
-/* crypto/ec/ec_err.c */
 /* ====================================================================
  * Copyright (c) 1999-2016 The OpenSSL Project.  All rights reserved.
  *
@@ -275,6 +274,8 @@ static ERR_STRING_DATA EC_str_reasons[] = {
     {ERR_REASON(EC_R_BIGNUM_OUT_OF_RANGE), "bignum out of range"},
     {ERR_REASON(EC_R_BUFFER_TOO_SMALL), "buffer too small"},
     {ERR_REASON(EC_R_COORDINATES_OUT_OF_RANGE), "coordinates out of range"},
+    {ERR_REASON(EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING),
+     "curve does not support signing"},
     {ERR_REASON(EC_R_D2I_ECPKPARAMETERS_FAILURE),
      "d2i ecpkparameters failure"},
     {ERR_REASON(EC_R_DECODE_ERROR), "decode error"},
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index c382e7e..e59d2c6 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -111,6 +111,9 @@ void EC_KEY_free(EC_KEY *r)
     ENGINE_finish(r->engine);
 #endif
 
+    if (r->group && r->group->meth->keyfinish)
+        r->group->meth->keyfinish(r);
+
     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_EC_KEY, r, &r->ex_data);
     EC_GROUP_free(r->group);
     EC_POINT_free(r->pub_key);
@@ -128,6 +131,8 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, EC_KEY *src)
     if (src->meth != dest->meth) {
         if (dest->meth->finish != NULL)
             dest->meth->finish(dest);
+        if (dest->group && dest->group->meth->keyfinish)
+            dest->group->meth->keyfinish(dest);
 #ifndef OPENSSL_NO_ENGINE
         if (ENGINE_finish(dest->engine) == 0)
             return 0;
@@ -163,8 +168,12 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, EC_KEY *src)
         }
         if (!BN_copy(dest->priv_key, src->priv_key))
             return NULL;
+        if (src->group->meth->keycopy
+            && src->group->meth->keycopy(dest, src) == 0)
+            return NULL;
     }
 
+
     /* copy the rest */
     dest->enc_flag = src->enc_flag;
     dest->conv_form = src->conv_form;
@@ -231,6 +240,9 @@ int ossl_ec_key_gen(EC_KEY *eckey)
     const BIGNUM *order = NULL;
     EC_POINT *pub_key = NULL;
 
+    if (eckey->group->meth->keygen != NULL)
+        return eckey->group->meth->keygen(eckey);
+
     if ((ctx = BN_CTX_new()) == NULL)
         goto err;
 
@@ -286,6 +298,9 @@ int EC_KEY_check_key(const EC_KEY *eckey)
         return 0;
     }
 
+    if (eckey->group->meth->keycheck)
+        return eckey->group->meth->keycheck(eckey);
+
     if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) {
         ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_POINT_AT_INFINITY);
         goto err;
@@ -442,6 +457,11 @@ const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key)
 
 int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key)
 {
+    if (key->group == NULL || key->group->meth == NULL)
+        return 0;
+    if (key->group->meth->set_private
+        && key->meth->set_private(key, priv_key) == 0)
+        return 0;
     if (key->meth->set_private != NULL
         && key->meth->set_private(key, priv_key) == 0)
         return 0;
@@ -532,7 +552,18 @@ int EC_KEY_oct2key(EC_KEY *key, const unsigned char *buf, size_t len,
         key->pub_key = EC_POINT_new(key->group);
     if (key->pub_key == NULL)
         return 0;
-    return EC_POINT_oct2point(key->group, key->pub_key, buf, len, ctx);
+    if (EC_POINT_oct2point(key->group, key->pub_key, buf, len, ctx) == 0)
+        return 0;
+    /*
+     * Save the point conversion form.
+     * For non-custom curves the first octet of the buffer (excluding
+     * the last significant bit) contains the point conversion form.
+     * EC_POINT_oct2point() has already performed sanity checking of
+     * the buffer so we know it is valid.
+     */
+    if ((key->group->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0)
+        key->conv_form = (point_conversion_form_t)(buf[0] & ~0x01);
+    return 1;
 }
 
 size_t EC_KEY_priv2oct(const EC_KEY *eckey, unsigned char *buf, size_t len)
@@ -540,6 +571,8 @@ size_t EC_KEY_priv2oct(const EC_KEY *eckey, unsigned char *buf, size_t len)
     size_t buf_len;
     if (eckey->group == NULL || eckey->group->meth == NULL)
         return 0;
+    if (eckey->group->meth->priv2oct)
+        return eckey->group->meth->priv2oct(eckey, buf, len);
 
     buf_len = (EC_GROUP_get_degree(eckey->group) + 7) / 8;
     if (eckey->priv_key == NULL)
@@ -563,6 +596,8 @@ int EC_KEY_oct2priv(EC_KEY *eckey, unsigned char *buf, size_t len)
 {
     if (eckey->group == NULL || eckey->group->meth == NULL)
         return 0;
+    if (eckey->group->meth->oct2priv)
+        return eckey->group->meth->oct2priv(eckey, buf, len);
 
     if (eckey->priv_key == NULL)
         eckey->priv_key = BN_secure_new();
@@ -596,3 +631,11 @@ size_t EC_KEY_priv2buf(const EC_KEY *eckey, unsigned char **pbuf)
     *pbuf = buf;
     return len;
 }
+
+int EC_KEY_can_sign(const EC_KEY *eckey)
+{
+    if (eckey->group == NULL || eckey->group->meth == NULL
+        || (eckey->group->meth->flags & EC_FLAGS_NO_SIGN))
+        return 0;
+    return 1;
+}
diff --git a/crypto/ec/ec_lcl.h b/crypto/ec/ec_lcl.h
index 5190b91..42cf079 100644
--- a/crypto/ec/ec_lcl.h
+++ b/crypto/ec/ec_lcl.h
@@ -83,6 +83,12 @@
 /* Use default functions for poin2oct, oct2point and compressed coordinates */
 #define EC_FLAGS_DEFAULT_OCT    0x1
 
+/* Use custom formats for EC_GROUP, EC_POINT and EC_KEY */
+#define EC_FLAGS_CUSTOM_CURVE   0x2
+
+/* Curve does not support signing operations */
+#define EC_FLAGS_NO_SIGN        0x4
+
 /*
  * Structure details are not part of the exported interface, so all this may
  * change in future versions.
@@ -109,6 +115,7 @@ struct ec_method_st {
                             BN_CTX *);
     /* used by EC_GROUP_get_degree: */
     int (*group_get_degree) (const EC_GROUP *);
+    int (*group_order_bits) (const EC_GROUP *);
     /* used by EC_GROUP_check: */
     int (*group_check_discriminant) (const EC_GROUP *, BN_CTX *);
     /*
@@ -195,6 +202,20 @@ struct ec_method_st {
     int (*field_decode) (const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                          BN_CTX *);
     int (*field_set_to_one) (const EC_GROUP *, BIGNUM *r, BN_CTX *);
+    /* private key operations */
+    size_t (*priv2oct)(const EC_KEY *eckey, unsigned char *buf, size_t len);
+    int (*oct2priv)(EC_KEY *eckey, unsigned char *buf, size_t len);
+    int (*set_private)(EC_KEY *eckey, const BIGNUM *priv_key);
+    int (*keygen)(EC_KEY *eckey);
+    int (*keycheck)(const EC_KEY *eckey);
+    int (*keygenpub)(EC_KEY *eckey);
+    int (*keycopy)(EC_KEY *dst, const EC_KEY *src);
+    void (*keyfinish)(EC_KEY *eckey);
+    /* custom ECDH operation */
+    int (*ecdh_compute_key)(void *out, size_t outlen, const EC_POINT *pub_key,
+                            const EC_KEY *ecdh,
+                            void *(*KDF) (const void *in, size_t inlen,
+                                          void *out, size_t *outlen));
 } /* EC_METHOD */ ;
 
 /*
@@ -280,6 +301,12 @@ struct ec_key_st {
     EC_GROUP *group;
     EC_POINT *pub_key;
     BIGNUM *priv_key;
+    /*
+     * Arbitrary extra data.
+     * For example in X25519 this contains the raw private key in a 32 byte
+     * buffer.
+     */
+    void *custom_data;
     unsigned int enc_flag;
     point_conversion_form_t conv_form;
     int references;
@@ -299,6 +326,11 @@ struct ec_point_st {
                                  * Z) represents (X/Z^2, Y/Z^3) if Z != 0 */
     int Z_is_one;               /* enable optimized point arithmetics for
                                  * special case */
+    /*
+     * Arbitrary extra data.
+     * For example in X25519 this contains the public key in a 32 byte buffer.
+     */
+    void *custom_data;
 } /* EC_POINT */ ;
 
 NISTP224_PRE_COMP *EC_nistp224_pre_comp_dup(NISTP224_PRE_COMP *);
@@ -621,3 +653,10 @@ int ossl_ecdsa_verify(int type, const unsigned char *dgst, int dgst_len,
                       const unsigned char *sigbuf, int sig_len, EC_KEY *eckey);
 int ossl_ecdsa_verify_sig(const unsigned char *dgst, int dgst_len,
                           const ECDSA_SIG *sig, EC_KEY *eckey);
+
+const EC_METHOD *ec_x25519_meth(void);
+
+int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
+           const uint8_t peer_public_value[32]);
+void X25519_public_from_private(uint8_t out_public_value[32],
+                                const uint8_t private_key[32]);
diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c
index a34113c..e45cbe3 100644
--- a/crypto/ec/ec_lib.c
+++ b/crypto/ec/ec_lib.c
@@ -89,12 +89,14 @@ EC_GROUP *EC_GROUP_new(const EC_METHOD *meth)
     }
 
     ret->meth = meth;
-    ret->order = BN_new();
-    if (ret->order == NULL)
-        goto err;
-    ret->cofactor = BN_new();
-    if (ret->cofactor == NULL)
-        goto err;
+    if ((ret->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0) {
+        ret->order = BN_new();
+        if (ret->order == NULL)
+            goto err;
+        ret->cofactor = BN_new();
+        if (ret->cofactor == NULL)
+            goto err;
+    }
     ret->asn1_flag = OPENSSL_EC_NAMED_CURVE;
     ret->asn1_form = POINT_CONVERSION_UNCOMPRESSED;
     if (!meth->group_init(ret))
@@ -240,10 +242,12 @@ int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src)
         dest->generator = NULL;
     }
 
-    if (!BN_copy(dest->order, src->order))
-        return 0;
-    if (!BN_copy(dest->cofactor, src->cofactor))
-        return 0;
+    if ((src->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0) {
+        if (!BN_copy(dest->order, src->order))
+            return 0;
+        if (!BN_copy(dest->cofactor, src->cofactor))
+            return 0;
+    }
 
     dest->curve_name = src->curve_name;
     dest->asn1_flag = src->asn1_flag;
@@ -369,6 +373,8 @@ const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group)
 
 int EC_GROUP_order_bits(const EC_GROUP *group)
 {
+    if (group->meth->group_order_bits)
+        return group->meth->group_order_bits(group);
     if (group->order)
         return BN_num_bits(group->order);
     return 0;
@@ -527,6 +533,8 @@ int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx)
     if (EC_GROUP_get_curve_name(a) && EC_GROUP_get_curve_name(b) &&
         EC_GROUP_get_curve_name(a) != EC_GROUP_get_curve_name(b))
         return 1;
+    if (a->meth->flags & EC_FLAGS_CUSTOM_CURVE)
+        return 0;
 
     if (ctx == NULL)
         ctx_new = ctx = BN_CTX_new();
diff --git a/crypto/ec/ecdh_ossl.c b/crypto/ec/ecdh_ossl.c
index 15a179f..fadc007 100644
--- a/crypto/ec/ecdh_ossl.c
+++ b/crypto/ec/ecdh_ossl.c
@@ -103,6 +103,10 @@ int ossl_ecdh_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
         return -1;
     }
 
+    if (ecdh->group->meth->ecdh_compute_key != 0)
+        return ecdh->group->meth->ecdh_compute_key(out, outlen, pub_key, ecdh,
+                                                   KDF);
+
     if ((ctx = BN_CTX_new()) == NULL)
         goto err;
     BN_CTX_start(ctx);
diff --git a/crypto/ec/ecdsa_ossl.c b/crypto/ec/ecdsa_ossl.c
index 3e755fb..113bcdf 100644
--- a/crypto/ec/ecdsa_ossl.c
+++ b/crypto/ec/ecdsa_ossl.c
@@ -95,6 +95,11 @@ static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in,
         return 0;
     }
 
+    if (!EC_KEY_can_sign(eckey)) {
+        ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING);
+        return 0;
+    }
+
     if (ctx_in == NULL) {
         if ((ctx = BN_CTX_new()) == NULL) {
             ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE);
@@ -254,6 +259,11 @@ ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len,
         return NULL;
     }
 
+    if (!EC_KEY_can_sign(eckey)) {
+        ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING);
+        return NULL;
+    }
+
     ret = ECDSA_SIG_new();
     if (ret == NULL) {
         ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE);
@@ -391,6 +401,11 @@ int ossl_ecdsa_verify_sig(const unsigned char *dgst, int dgst_len,
         return -1;
     }
 
+    if (!EC_KEY_can_sign(eckey)) {
+        ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING);
+        return -1;
+    }
+
     ctx = BN_CTX_new();
     if (ctx == NULL) {
         ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_MALLOC_FAILURE);
diff --git a/crypto/ec/ecp_mont.c b/crypto/ec/ecp_mont.c
index 799aade..9217c8f 100644
--- a/crypto/ec/ecp_mont.c
+++ b/crypto/ec/ecp_mont.c
@@ -76,6 +76,7 @@ const EC_METHOD *EC_GFp_mont_method(void)
         ec_GFp_mont_group_set_curve,
         ec_GFp_simple_group_get_curve,
         ec_GFp_simple_group_get_degree,
+        0, /* group_order_bits */
         ec_GFp_simple_group_check_discriminant,
         ec_GFp_simple_point_init,
         ec_GFp_simple_point_finish,
diff --git a/crypto/ec/ecp_nist.c b/crypto/ec/ecp_nist.c
index a484be4..cda9a91 100644
--- a/crypto/ec/ecp_nist.c
+++ b/crypto/ec/ecp_nist.c
@@ -78,6 +78,7 @@ const EC_METHOD *EC_GFp_nist_method(void)
         ec_GFp_nist_group_set_curve,
         ec_GFp_simple_group_get_curve,
         ec_GFp_simple_group_get_degree,
+        0, /* group_order_bits */
         ec_GFp_simple_group_check_discriminant,
         ec_GFp_simple_point_init,
         ec_GFp_simple_point_finish,
diff --git a/crypto/ec/ecp_nistp224.c b/crypto/ec/ecp_nistp224.c
index a76b60f..a533fa3 100644
--- a/crypto/ec/ecp_nistp224.c
+++ b/crypto/ec/ecp_nistp224.c
@@ -245,6 +245,7 @@ const EC_METHOD *EC_GFp_nistp224_method(void)
         ec_GFp_nistp224_group_set_curve,
         ec_GFp_simple_group_get_curve,
         ec_GFp_simple_group_get_degree,
+        0, /* group_order_bits */
         ec_GFp_simple_group_check_discriminant,
         ec_GFp_simple_point_init,
         ec_GFp_simple_point_finish,
diff --git a/crypto/ec/ecp_nistp256.c b/crypto/ec/ecp_nistp256.c
index a02af0d..db95a2d 100644
--- a/crypto/ec/ecp_nistp256.c
+++ b/crypto/ec/ecp_nistp256.c
@@ -1774,6 +1774,7 @@ const EC_METHOD *EC_GFp_nistp256_method(void)
         ec_GFp_nistp256_group_set_curve,
         ec_GFp_simple_group_get_curve,
         ec_GFp_simple_group_get_degree,
+        0, /* group_order_bits */
         ec_GFp_simple_group_check_discriminant,
         ec_GFp_simple_point_init,
         ec_GFp_simple_point_finish,
diff --git a/crypto/ec/ecp_nistp521.c b/crypto/ec/ecp_nistp521.c
index de61a8a..3edc219 100644
--- a/crypto/ec/ecp_nistp521.c
+++ b/crypto/ec/ecp_nistp521.c
@@ -1603,6 +1603,7 @@ const EC_METHOD *EC_GFp_nistp521_method(void)
         ec_GFp_nistp521_group_set_curve,
         ec_GFp_simple_group_get_curve,
         ec_GFp_simple_group_get_degree,
+        0, /* group_order_bits */
         ec_GFp_simple_group_check_discriminant,
         ec_GFp_simple_point_init,
         ec_GFp_simple_point_finish,
diff --git a/crypto/ec/ecp_nistz256.c b/crypto/ec/ecp_nistz256.c
index 4b95019..8ccf831 100644
--- a/crypto/ec/ecp_nistz256.c
+++ b/crypto/ec/ecp_nistz256.c
@@ -1441,6 +1441,7 @@ const EC_METHOD *EC_GFp_nistz256_method(void)
         ec_GFp_mont_group_set_curve,
         ec_GFp_simple_group_get_curve,
         ec_GFp_simple_group_get_degree,
+        0, /* group_order_bits */
         ec_GFp_simple_group_check_discriminant,
         ec_GFp_simple_point_init,
         ec_GFp_simple_point_finish,
diff --git a/crypto/ec/ecp_smpl.c b/crypto/ec/ecp_smpl.c
index 2a1b15d..2ba40f4 100644
--- a/crypto/ec/ecp_smpl.c
+++ b/crypto/ec/ecp_smpl.c
@@ -79,6 +79,7 @@ const EC_METHOD *EC_GFp_simple_method(void)
         ec_GFp_simple_group_set_curve,
         ec_GFp_simple_group_get_curve,
         ec_GFp_simple_group_get_degree,
+        0, /* group_order_bits */
         ec_GFp_simple_group_check_discriminant,
         ec_GFp_simple_point_init,
         ec_GFp_simple_point_finish,
diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h
index 18115ac..e5c5963 100644
--- a/crypto/objects/obj_dat.h
+++ b/crypto/objects/obj_dat.h
@@ -60,12 +60,12 @@
  * [including the GNU Public Licence.]
  */
 
-#define NUM_NID 1038
-#define NUM_SN 1031
-#define NUM_LN 1031
-#define NUM_OBJ 953
+#define NUM_NID 1036
+#define NUM_SN 1029
+#define NUM_LN 1029
+#define NUM_OBJ 951
 
-static const unsigned char lvalues[6740]={
+static const unsigned char lvalues[6722]={
 0x2A,0x86,0x48,0x86,0xF7,0x0D,               /* [  0] OBJ_rsadsi */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,          /* [  6] OBJ_pkcs */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02,     /* [ 13] OBJ_md2 */
@@ -1009,10 +1009,8 @@ static const unsigned char lvalues[6740]={
 0x2B,0x06,0x01,0x05,0x02,0x03,               /* [6683] OBJ_id_pkinit */
 0x2B,0x06,0x01,0x05,0x02,0x03,0x04,          /* [6689] OBJ_pkInitClientAuth */
 0x2B,0x06,0x01,0x05,0x02,0x03,0x05,          /* [6696] OBJ_pkInitKDC */
-0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x01,/* [6703] OBJ_Curve25519 */
-0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x02,/* [6712] OBJ_Curve448 */
-0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x03,/* [6721] OBJ_Curve25519ph */
-0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x04,/* [6730] OBJ_Curve448ph */
+0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x01,/* [6703] OBJ_X25519 */
+0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x02,/* [6712] OBJ_X448 */
 };
 
 static const ASN1_OBJECT nid_objs[NUM_NID]={
@@ -2704,10 +2702,8 @@ static const ASN1_OBJECT nid_objs[NUM_NID]={
 {"pkInitClientAuth","PKINIT Client Auth",NID_pkInitClientAuth,7,
 	&(lvalues[6689]),0},
 {"pkInitKDC","Signing KDC Response",NID_pkInitKDC,7,&(lvalues[6696]),0},
-{"Curve25519","Curve25519",NID_Curve25519,9,&(lvalues[6703]),0},
-{"Curve448","Curve448",NID_Curve448,9,&(lvalues[6712]),0},
-{"Curve25519ph","Curve25519ph",NID_Curve25519ph,9,&(lvalues[6721]),0},
-{"Curve448ph","Curve448ph",NID_Curve448ph,9,&(lvalues[6730]),0},
+{"X25519","X25519",NID_X25519,9,&(lvalues[6703]),0},
+{"X448","X448",NID_X448,9,&(lvalues[6712]),0},
 };
 
 static const unsigned int sn_objs[NUM_SN]={
@@ -2790,10 +2786,6 @@ static const unsigned int sn_objs[NUM_SN]={
 1019,	/* "ChaCha20" */
 1018,	/* "ChaCha20-Poly1305" */
 367,	/* "CrlID" */
-1034,	/* "Curve25519" */
-1036,	/* "Curve25519ph" */
-1035,	/* "Curve448" */
-1037,	/* "Curve448ph" */
 391,	/* "DC" */
 31,	/* "DES-CBC" */
 643,	/* "DES-CDMF" */
@@ -2922,6 +2914,8 @@ static const unsigned int sn_objs[NUM_SN]={
 1021,	/* "TLS1-PRF" */
 458,	/* "UID" */
  0,	/* "UNDEF" */
+1034,	/* "X25519" */
+1035,	/* "X448" */
 11,	/* "X500" */
 378,	/* "X500algorithms" */
 12,	/* "X509" */
@@ -3762,10 +3756,6 @@ static const unsigned int ln_objs[NUM_LN]={
 131,	/* "Code Signing" */
 1024,	/* "Ctrl/Provision WAP Termination" */
 1023,	/* "Ctrl/provision WAP Access" */
-1034,	/* "Curve25519" */
-1036,	/* "Curve25519ph" */
-1035,	/* "Curve448" */
-1037,	/* "Curve448ph" */
 783,	/* "Diffie-Hellman based MAC" */
 382,	/* "Directory" */
 392,	/* "Domain" */
@@ -3889,6 +3879,8 @@ static const unsigned int ln_objs[NUM_LN]={
 129,	/* "TLS Web Server Authentication" */
 133,	/* "Time Stamping" */
 375,	/* "Trust Root" */
+1034,	/* "X25519" */
+1035,	/* "X448" */
 12,	/* "X509" */
 402,	/* "X509v3 AC Targeting" */
 746,	/* "X509v3 Any Policy" */
@@ -5480,10 +5472,8 @@ static const unsigned int obj_objs[NUM_OBJ]={
 390,	/* OBJ_dcObject                     1 3 6 1 4 1 1466 344 */
 91,	/* OBJ_bf_cbc                       1 3 6 1 4 1 3029 1 2 */
 973,	/* OBJ_id_scrypt                    1 3 6 1 4 1 11591 4 11 */
-1034,	/* OBJ_Curve25519                   1 3 6 1 4 1 11591 15 1 */
-1035,	/* OBJ_Curve448                     1 3 6 1 4 1 11591 15 2 */
-1036,	/* OBJ_Curve25519ph                 1 3 6 1 4 1 11591 15 3 */
-1037,	/* OBJ_Curve448ph                   1 3 6 1 4 1 11591 15 4 */
+1034,	/* OBJ_X25519                       1 3 6 1 4 1 11591 15 1 */
+1035,	/* OBJ_X448                         1 3 6 1 4 1 11591 15 2 */
 315,	/* OBJ_id_regCtrl_regToken          1 3 6 1 5 5 7 5 1 1 */
 316,	/* OBJ_id_regCtrl_authenticator     1 3 6 1 5 5 7 5 1 2 */
 317,	/* OBJ_id_regCtrl_pkiPublicationInfo 1 3 6 1 5 5 7 5 1 3 */
diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num
index a9a9e3d..e981a05 100644
--- a/crypto/objects/obj_mac.num
+++ b/crypto/objects/obj_mac.num
@@ -1031,7 +1031,5 @@ sendProxiedOwner		1030
 id_pkinit		1031
 pkInitClientAuth		1032
 pkInitKDC		1033
-Curve25519		1034
-Curve448		1035
-Curve25519ph		1036
-Curve448ph		1037
+X25519		1034
+X448		1035
diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt
index 645591b..14e68e3 100644
--- a/crypto/objects/objects.txt
+++ b/crypto/objects/objects.txt
@@ -1451,7 +1451,5 @@ id-pkinit 5                     : pkInitKDC             : Signing KDC Response
 
 # New curves from draft-josefsson-pkix-newcurves
 
-1 3 6 1 4 1 11591 15 1      : Curve25519
-1 3 6 1 4 1 11591 15 2      : Curve448
-1 3 6 1 4 1 11591 15 3      : Curve25519ph
-1 3 6 1 4 1 11591 15 4      : Curve448ph
+1 3 6 1 4 1 11591 15 1      : X25519
+1 3 6 1 4 1 11591 15 2      : X448
diff --git a/include/openssl/ec.h b/include/openssl/ec.h
index 8530c56..b03b65d 100644
--- a/include/openssl/ec.h
+++ b/include/openssl/ec.h
@@ -901,6 +901,12 @@ int EC_KEY_generate_key(EC_KEY *key);
  */
 int EC_KEY_check_key(const EC_KEY *key);
 
+/** Indicates if an EC_KEY can be used for signing.
+ *  \param  key  the EC_KEY object
+ *  \return 1 if can can sign and 0 otherwise.
+ */
+int EC_KEY_can_sign(const EC_KEY *eckey);
+
 /** Sets a public key from affine coordindates performing
  *  necessary NIST PKV tests.
  *  \param  key  the EC_KEY object
@@ -1563,6 +1569,7 @@ void ERR_load_EC_strings(void);
 # define EC_R_BIGNUM_OUT_OF_RANGE                         144
 # define EC_R_BUFFER_TOO_SMALL                            100
 # define EC_R_COORDINATES_OUT_OF_RANGE                    146
+# define EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING              159
 # define EC_R_D2I_ECPKPARAMETERS_FAILURE                  117
 # define EC_R_DECODE_ERROR                                142
 # define EC_R_DISCRIMINANT_IS_ZERO                        118
diff --git a/include/openssl/obj_mac.h b/include/openssl/obj_mac.h
index aa640b0..b58c44d 100644
--- a/include/openssl/obj_mac.h
+++ b/include/openssl/obj_mac.h
@@ -4525,18 +4525,10 @@
 #define NID_pkInitKDC           1033
 #define OBJ_pkInitKDC           OBJ_id_pkinit,5L
 
-#define SN_Curve25519           "Curve25519"
-#define NID_Curve25519          1034
-#define OBJ_Curve25519          1L,3L,6L,1L,4L,1L,11591L,15L,1L
+#define SN_X25519               "X25519"
+#define NID_X25519              1034
+#define OBJ_X25519              1L,3L,6L,1L,4L,1L,11591L,15L,1L
 
-#define SN_Curve448             "Curve448"
-#define NID_Curve448            1035
-#define OBJ_Curve448            1L,3L,6L,1L,4L,1L,11591L,15L,2L
-
-#define SN_Curve25519ph         "Curve25519ph"
-#define NID_Curve25519ph                1036
-#define OBJ_Curve25519ph                1L,3L,6L,1L,4L,1L,11591L,15L,3L
-
-#define SN_Curve448ph           "Curve448ph"
-#define NID_Curve448ph          1037
-#define OBJ_Curve448ph          1L,3L,6L,1L,4L,1L,11591L,15L,4L
+#define SN_X448         "X448"
+#define NID_X448                1035
+#define OBJ_X448                1L,3L,6L,1L,4L,1L,11591L,15L,2L
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index f93db31..abced26 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -378,6 +378,11 @@ static int ssl_set_cert(CERT *c, X509 *x)
         return 0;
     }
 
+    if (i == SSL_PKEY_ECC && !EC_KEY_can_sign(EVP_PKEY_get0_EC_KEY(pkey))) {
+        SSLerr(SSL_F_SSL_SET_CERT, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+        return 0;
+    }
+
     if (c->pkeys[i].privatekey != NULL) {
         /*
          * The return code from EVP_PKEY_copy_parameters is deliberately
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index db5f0f6..f02317e 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -222,9 +222,11 @@ typedef struct {
     unsigned int flags;         /* Flags: currently just field type */
 } tls_curve_info;
 
-# define TLS_CURVE_TYPE          0x1
-# define TLS_CURVE_CHAR2         0x1
+/* Mask for curve type */
+# define TLS_CURVE_TYPE          0x3
 # define TLS_CURVE_PRIME         0x0
+# define TLS_CURVE_CHAR2         0x1
+# define TLS_CURVE_CUSTOM        0x2
 
 /*
  * Table of curve information.
@@ -261,6 +263,8 @@ static const tls_curve_info nid_list[] = {
     {NID_brainpoolP256r1, 128, TLS_CURVE_PRIME}, /* brainpoolP256r1 (26) */
     {NID_brainpoolP384r1, 192, TLS_CURVE_PRIME}, /* brainpoolP384r1 (27) */
     {NID_brainpoolP512r1, 256, TLS_CURVE_PRIME}, /* brainpool512r1 (28) */
+    /* X25519 (29) */
+    {NID_X25519, 128, TLS_CURVE_CUSTOM},
 };
 
 static const unsigned char ecformats_default[] = {
@@ -271,6 +275,7 @@ static const unsigned char ecformats_default[] = {
 
 /* The default curves */
 static const unsigned char eccurves_default[] = {
+    0, 29,                      /* X25519 (29) */
     /* Prefer P-256 which has the fastest and most secure implementations. */
     0, 23,                      /* secp256r1 (23) */
     /* Other >= 256-bit prime curves. */
@@ -290,6 +295,7 @@ static const unsigned char eccurves_default[] = {
 };
 
 static const unsigned char eccurves_all[] = {
+    0, 29,                      /* X25519 (29) */
     /* Prefer P-256 which has the fastest and most secure implementations. */
     0, 23,                      /* secp256r1 (23) */
     /* Other >= 256-bit prime curves. */
diff --git a/test/ecdhtest.c b/test/ecdhtest.c
index e37a020..fb4df79 100644
--- a/test/ecdhtest.c
+++ b/test/ecdhtest.c
@@ -493,6 +493,13 @@ int main(int argc, char *argv[])
     /* NAMED CURVES TESTS */
     for (n = 0; n < crv_len; n++) {
         nid = curves[n].nid;
+        /*
+         * Skipped for X25519 because affine coordinate operations are not
+         * supported for this curve.
+         * Higher level ECDH tests are performed in evptests.txt instead.
+         */
+        if (nid == NID_X25519)
+            continue;
         if (!test_ecdh_curve(nid, ctx, out)) goto err;
     }
 
diff --git a/test/ecdsatest.c b/test/ecdsatest.c
index 55ebad9..f5b753a 100644
--- a/test/ecdsatest.c
+++ b/test/ecdsatest.c
@@ -338,7 +338,7 @@ int test_builtin(BIO *out)
         unsigned char dirt, offset;
 
         nid = curves[n].nid;
-        if (nid == NID_ipsec4)
+        if (nid == NID_ipsec4 || nid == NID_X25519)
             continue;
         /* create new ecdsa key (== EC_KEY) */
         if ((eckey = EC_KEY_new()) == NULL)
diff --git a/test/ectest.c b/test/ectest.c
index b0fbcdc..bbc7ed0 100644
--- a/test/ectest.c
+++ b/test/ectest.c
@@ -1417,6 +1417,12 @@ static void internal_curve_test(void)
     for (n = 0; n < crv_len; n++) {
         EC_GROUP *group = NULL;
         int nid = curves[n].nid;
+        /*
+         * Skip for X25519 because low level operations such as EC_POINT_mul()
+         * are not supported for this curve
+         */
+        if (nid == NID_X25519)
+            continue;
         fprintf(stdout, "%s:\n", OBJ_nid2sn(nid));
         fflush(stdout);
         if ((group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
diff --git a/test/evptests.txt b/test/evptests.txt
index c325ac9..4c83163 100644
--- a/test/evptests.txt
+++ b/test/evptests.txt
@@ -3029,3 +3029,45 @@ SharedSecret=E3CC07DFBDDE76A1139811DB9FF5FAF9D17EF39944F1E77D1F6A208524BF7B1B
 Derive=P-256-Peer
 PeerKey=P-256-PUBLIC
 SharedSecret=E3CC07DFBDDE76A1139811DB9FF5FAF9D17EF39944F1E77D1F6A208524BF7B1B
+
+# X25519 test vectors from RFC7748 6.1
+PrivateKey=Alice-25519
+-----BEGIN PRIVATE KEY-----
+MEICAQAwFAYHKoZIzj0CAQYJKwYBBAHaRw8BBCcwJQIBAQQgdwdtCnMYpX08FsFy
+UbJmRd9ML4frwJkqsXf7pR25LCo=
+-----END PRIVATE KEY-----
+PublicKey=Alice-25519-PUBLIC
+-----BEGIN PUBLIC KEY-----
+MDkwFAYHKoZIzj0CAQYJKwYBBAHaRw8BAyEAhSDwCYkwp1R0i33ctD73Wg2/Og0m
+OBr066SpjqqbTmo=
+-----END PUBLIC KEY-----
+PrivateKey=Bob-25519
+-----BEGIN PRIVATE KEY-----
+MEICAQAwFAYHKoZIzj0CAQYJKwYBBAHaRw8BBCcwJQIBAQQgXasIfmJKikt54X+L
+g4AO5m87sSkmGLb9HC+LJ/+I4Os=
+-----END PRIVATE KEY-----
+PublicKey=Bob-25519-PUBLIC
+-----BEGIN PUBLIC KEY-----
+MDkwFAYHKoZIzj0CAQYJKwYBBAHaRw8BAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hb
+eGdNrfx+FG+IK08=
+-----END PUBLIC KEY-----
+
+Derive=Alice-25519
+PeerKey=Bob-25519-PUBLIC
+SharedSecret=4A5D9D5BA4CE2DE1728E3BF480350F25E07E21C947D19E3376F09B3C1E161742
+
+Derive=Bob-25519
+PeerKey=Alice-25519-PUBLIC
+SharedSecret=4A5D9D5BA4CE2DE1728E3BF480350F25E07E21C947D19E3376F09B3C1E161742
+# Try to sign/verify using X25519 keys: both return errors.
+Sign = Alice-25519
+Ctrl = digest:SHA256
+Input = "0123456789ABCDEF1234"
+Output = 30
+Result = KEYOP_ERROR
+
+Verify = Alice-25519-PUBLIC
+Ctrl = digest:SHA256
+Input = "0123456789ABCDEF1234"
+Output = 30
+Result = VERIFY_ERROR
diff --git a/util/libeay.num b/util/libeay.num
index 9323df0..06a5021 100755
--- a/util/libeay.num
+++ b/util/libeay.num
@@ -4757,3 +4757,4 @@ o2i_SCT_LIST                            5260	1_1_0	EXIST::FUNCTION:
 SCT_set_version                         5261	1_1_0	EXIST::FUNCTION:
 SCT_LIST_free                           5262	1_1_0	EXIST::FUNCTION:
 SCT_get_log_entry_type                  5263	1_1_0	EXIST::FUNCTION:
+EC_KEY_can_sign                         5264	1_1_0	EXIST::FUNCTION:EC


More information about the openssl-commits mailing list