From bcc764eca6c92210716d1d6db59bfe112522a95d Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Fri, 25 Sep 2015 17:47:35 -0400 Subject: [PATCH] Add SPAKE preauth support This is an implementation of draft-ietf-kitten-krb-spake-preauth-05. SPAKE preauth authenticates using the client principal long-term key, but protects against offline dictionary attacks. SPAKE preauth negotiates a group for use by the SPAKE2 algorithm. The edwards25519 group is implemented using code adapted from BoringSSL. The P-256, P-384, and P-521 groups are implemented against OpenSSL. edwards25519 is enabled by default on the client; no groups are enabled by default on the KDC. SPAKE preauth can also include a second factor. Second factor support isn't included in this implementation; comments have been left to indicate what should change when it is added in. Integration tests (tests/t_spake.py) are included with good coverage of the negotiation scenarios. Test vectors from the draft are checked against the group's "result" operation. The "keygen" operation is inherently random and is therefore not tested against the vectors, but is effectively exercised by the integration tests. KDC optimistic challenge is implemented. In the future we should implement client optimistic SPAKE as well; this will require changes to the generic client preauth framework. In the future we should add per-realm configuration to deny encrypted timestamp and encrypted challenge on a per-realm basis. This configuration should stick across client realm referrals. In the future we should avoid attempting encrypting timestamp or encrypted challenge if the KDC replies to a single-factor SPAKEResponse message with PREAUTH_FAILED. This will require a change to the generic client preauth framework. In the future we should make SPAKE support apply to the Windows build, either by adding support for building plugin DLLs or by moving the edwards25519 and client code to libkrb5. [npmccallum@redhat.com: split up internal headers; split out group registry contents; implemented P-384 and P-521] ticket: 8647 (new) (cherry picked from commit 7447259401569c92b1fb2e31cb02edbbffd67d35) --- NOTICE | 51 + doc/admin/conf_files/kdc_conf.rst | 22 +- doc/admin/conf_files/krb5_conf.rst | 15 + doc/admin/index.rst | 1 + doc/admin/spake.rst | 46 + doc/formats/cookie.rst | 37 + doc/notice.rst | 47 + src/Makefile.in | 2 + src/config/pre.in | 6 + src/configure.in | 20 + src/include/k5-int.h | 3 + src/include/krb5/krb5.hin | 2 + src/kdc/kdc_preauth.c | 2 + src/lib/krb5/krb/preauth2.c | 2 + src/lib/krb5/os/trace.c | 1 + src/plugins/preauth/spake/AUTHORS | 16 + src/plugins/preauth/spake/Makefile.in | 39 + src/plugins/preauth/spake/deps | 73 + src/plugins/preauth/spake/edwards25519.c | 2651 ++++++ .../preauth/spake/edwards25519_tables.h | 7881 +++++++++++++++++ src/plugins/preauth/spake/groups.c | 442 + src/plugins/preauth/spake/groups.h | 148 + src/plugins/preauth/spake/iana.c | 108 + src/plugins/preauth/spake/iana.h | 65 + src/plugins/preauth/spake/openssl.c | 315 + src/plugins/preauth/spake/spake.exports | 2 + src/plugins/preauth/spake/spake_client.c | 363 + src/plugins/preauth/spake/spake_kdc.c | 590 ++ src/plugins/preauth/spake/t_krb5.conf | 2 + src/plugins/preauth/spake/t_vectors.c | 476 + src/plugins/preauth/spake/trace.h | 74 + src/plugins/preauth/spake/util.c | 211 + src/plugins/preauth/spake/util.h | 56 + src/tests/Makefile.in | 1 + src/tests/t_spake.py | 151 + 35 files changed, 13917 insertions(+), 4 deletions(-) create mode 100644 doc/admin/spake.rst create mode 100644 src/plugins/preauth/spake/AUTHORS create mode 100644 src/plugins/preauth/spake/Makefile.in create mode 100644 src/plugins/preauth/spake/deps create mode 100644 src/plugins/preauth/spake/edwards25519.c create mode 100644 src/plugins/preauth/spake/edwards25519_tables.h create mode 100644 src/plugins/preauth/spake/groups.c create mode 100644 src/plugins/preauth/spake/groups.h create mode 100644 src/plugins/preauth/spake/iana.c create mode 100644 src/plugins/preauth/spake/iana.h create mode 100644 src/plugins/preauth/spake/openssl.c create mode 100644 src/plugins/preauth/spake/spake.exports create mode 100644 src/plugins/preauth/spake/spake_client.c create mode 100644 src/plugins/preauth/spake/spake_kdc.c create mode 100644 src/plugins/preauth/spake/t_krb5.conf create mode 100644 src/plugins/preauth/spake/t_vectors.c create mode 100644 src/plugins/preauth/spake/trace.h create mode 100644 src/plugins/preauth/spake/util.c create mode 100644 src/plugins/preauth/spake/util.h create mode 100644 src/tests/t_spake.py diff --git a/NOTICE b/NOTICE index 1db2420a7..9dc1148b1 100644 --- a/NOTICE +++ b/NOTICE @@ -1316,3 +1316,54 @@ The following notice applies to 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. + +====================================================================== + +The following notice applies to portions of +"src/plugins/preauth/spake/edwards25519.c" and +"src/plugins/preauth/spake/edwards25519_tables.h": + +The MIT License (MIT) + +Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS +file). + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +====================================================================== + +The following notice applies to portions of +"src/plugins/preauth/spake/edwards25519.c": + +Copyright (c) 2015-2016, Google Inc. + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all +copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/doc/admin/conf_files/kdc_conf.rst b/doc/admin/conf_files/kdc_conf.rst index 1ac1a37c2..f8cf1be7c 100644 --- a/doc/admin/conf_files/kdc_conf.rst +++ b/doc/admin/conf_files/kdc_conf.rst @@ -43,10 +43,10 @@ The kdc.conf file may contain the following sections: [kdcdefaults] ~~~~~~~~~~~~~ -With two exceptions, relations in the [kdcdefaults] section specify -default values for realm variables, to be used if the [realms] -subsection does not contain a relation for the tag. See the -:ref:`kdc_realms` section for the definitions of these relations. +Some relations in the [kdcdefaults] section specify default values for +realm variables, to be used if the [realms] subsection does not +contain a relation for the tag. See the :ref:`kdc_realms` section for +the definitions of these relations. * **host_based_services** * **kdc_listen** @@ -56,6 +56,8 @@ subsection does not contain a relation for the tag. See the * **no_host_referral** * **restrict_anonymous_to_tgt** +The following [kdcdefaults] variables have no per-realm equivalent: + **kdc_max_dgram_reply_size** Specifies the maximum packet size that can be sent over UDP. The default value is 4096 bytes. @@ -65,6 +67,12 @@ subsection does not contain a relation for the tag. See the daemon. The value may be limited by OS settings. The default value is 5. +**spake_preauth_kdc_challenge** + (String.) Specifies the group for a SPAKE optimistic challenge. + See the **spake_preauth_groups** variable in :ref:`libdefaults` + for possible values. The default is not to issue an optimistic + challenge. (New in release 1.17.) + .. _kdc_realms: @@ -403,6 +411,12 @@ The following tags may be specified in a [realms] subsection: without allowing anonymous authentication to services. The default value is false. New in release 1.9. +**spake_preauth_indicator** + (String.) Specifies an authentication indicator value that the + KDC asserts into tickets obtained using SPAKE pre-authentication. + The default is not to add any indicators. This option may be + specified multiple times. New in release 1.17. + **supported_enctypes** (List of *key*:*salt* strings.) Specifies the default key/salt combinations of principals for this realm. Any principals created diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst index 4ed9832c7..8cfe5f458 100644 --- a/doc/admin/conf_files/krb5_conf.rst +++ b/doc/admin/conf_files/krb5_conf.rst @@ -365,6 +365,21 @@ The libdefaults section may contain any of the following relations: with the session key type. See the **kdc_req_checksum_type** configuration option for the possible values and their meanings. +**spake_preauth_groups** + A whitespace or comma-separated list of words which specifies the + groups allowed for SPAKE preauthentication. The possible values + are: + + ============ ================================ + edwards25519 Edwards25519 curve (:rfc:`7748`) + P-256 NIST P-256 curve (:rfc:`5480`) + P-384 NIST P-384 curve (:rfc:`5480`) + P-521 NIST P-521 curve (:rfc:`5480`) + ============ ================================ + + The default value for the client is ``edwards25519``. The default + value for the KDC is empty. New in release 1.17. + **ticket_lifetime** (:ref:`duration` string.) Sets the default lifetime for initial ticket requests. The default value is 1 day. diff --git a/doc/admin/index.rst b/doc/admin/index.rst index b702f4021..292a64104 100644 --- a/doc/admin/index.rst +++ b/doc/admin/index.rst @@ -15,6 +15,7 @@ For administrators backup_host.rst pkinit.rst otp.rst + spake.rst princ_dns.rst enctypes.rst https.rst diff --git a/doc/admin/spake.rst b/doc/admin/spake.rst new file mode 100644 index 000000000..b65c694aa --- /dev/null +++ b/doc/admin/spake.rst @@ -0,0 +1,46 @@ +SPAKE Preauthentication +======================= + +SPAKE preauthentication (added in release 1.17) uses public key +cryptography techniques to protect against password dictionary +attacks. Unlike :ref:`PKINIT `, it does not require any +additional infrastructure such as certificates; it simply needs to be +turned on. Using SPAKE preauthentication may modestly increase the +CPU and network load on the KDC. + +SPAKE preauthentication can use one of four elliptic curve groups for +its password-authenticated key exchange. The recommended group is +``edwards25519``; three NIST curves (``P-256``, ``P-384``, and +``P-521``) are also supported. + +By default, SPAKE with the ``edwards25519`` group is enabled on +clients, but the KDC does not offer SPAKE by default. To turn it on, +set the **spake_preauth_groups** variable in :ref:`libdefaults` to a +list of allowed groups. This variable affects both the client and the +KDC. Simply setting it to ``edwards25519`` is recommended:: + + [libdefaults] + spake_preauth_groups = edwards25519 + +Set the **+requires_preauth** and **-allow_svr** flags on client +principal entries, as you would for any preauthentication mechanism:: + + kadmin: modprinc +requires_preauth -allow_srv PRINCNAME + +Clients which do not implement SPAKE preauthentication will fall back +to encrypted timestamp. + +By default, SPAKE preauthentication requires an extra network round +trip to the KDC during initial authentication. If most of the clients +in a realm support SPAKE, this extra round trip can be eliminated +using an optimistic challenge, by setting the +**spake_preauth_kdc_challenge** variable in :ref:`kdcdefaults` to a +single group name:: + + [kdcdefaults] + spake_preauth_kdc_challenge = edwards25519 + +Using optimistic challenge will cause the KDC to do extra work for +initial authentication requests that do not result in SPAKE +preauthentication, but will save work when SPAKE preauthentication is +used. diff --git a/doc/formats/cookie.rst b/doc/formats/cookie.rst index 640955c90..e32365daa 100644 --- a/doc/formats/cookie.rst +++ b/doc/formats/cookie.rst @@ -58,3 +58,40 @@ mechanisms which have separate request and reply types, the request type is used; this allows the KDC to determine whether a cookie is relevant to a request by comparing the request pa-data types to the cookie data types. + +SPAKE cookie format (version 1) +------------------------------- + +Inside the SecureCookie wrapper, a data value of type 151 contains +state for SPAKE pre-authentication. This data is the concatenation of +the following: + +* a two-byte big-endian version number with the value 1 +* a two-byte big-endian stage number +* a four-byte big-endian group number +* a four-byte big-endian length and data for the SPAKE value +* a four-byte big-endian length and data for the transcript hash +* zero or more second factor records, each consisting of: + - a four-byte big-endian second-factor type + - a four-byte big-endian length and data + +The stage value is 0 if the cookie was sent with a challenge message. +Otherwise it is 1 for the first encdata message sent by the KDC during +an exchange, 2 for the second, etc.. + +The group value indicates the group number used in the SPAKE challenge. + +For a stage-0 cookie, the SPAKE value is the KDC private key, +represented in the scalar marshalling form of the group. For other +cookies, the SPAKE value is the SPAKE result K, represented in the +group element marshalling form. + +For a stage-0 cookie, the transcript hash is the intermediate hash +after updating with the client support message (if one was sent) and +challenge. For other cookies it is the final hash. + +For a stage-0 cookie, there may be any number of second-factor +records, including none; a second-factor type need not create a state +field if it does not need one, and no record is created for SF-NONE. +For other cookies, there must be exactly one second-factor record +corresponding to the factor type chosen by the client. diff --git a/doc/notice.rst b/doc/notice.rst index 26011550b..cacfd659a 100644 --- a/doc/notice.rst +++ b/doc/notice.rst @@ -1237,3 +1237,50 @@ The following notice applies to 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. + +------------------- + +The following notice applies to portions of +``src/plugins/preauth/spake/edwards25519.c`` and +``src/plugins/preauth/spake/edwards25519_tables.h``: + +The MIT License (MIT) + +Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS file). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +------------------- + +The following notice applies to portions of +``src/plugins/preauth/spake/edwards25519.c``: + +Copyright (c) 2015-2016, Google Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/src/Makefile.in b/src/Makefile.in index ac9a2a060..77beff8bc 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -25,6 +25,7 @@ SUBDIRS=util include lib \ plugins/kdcpolicy/test \ plugins/preauth/otp \ plugins/preauth/pkinit \ + plugins/preauth/spake \ plugins/preauth/test \ plugins/tls/k5tls \ kdc kadmin slave clients appl tests \ @@ -523,6 +524,7 @@ pyrunenv.vals: Makefile done > $@ echo "tls_impl = '$(TLS_IMPL)'" >> $@ echo "have_sasl = '$(HAVE_SASL)'" >> $@ + echo "have_spake_openssl = '$(HAVE_SPAKE_OPENSSL)'" >> $@ echo "sizeof_time_t = $(SIZEOF_TIME_T)" >> $@ runenv.py: pyrunenv.vals diff --git a/src/config/pre.in b/src/config/pre.in index 03f5c8890..6317d3564 100644 --- a/src/config/pre.in +++ b/src/config/pre.in @@ -441,9 +441,15 @@ TLS_IMPL = @TLS_IMPL@ TLS_IMPL_CFLAGS = @TLS_IMPL_CFLAGS@ TLS_IMPL_LIBS = @TLS_IMPL_LIBS@ +# SPAKE preauth back-end libraries +SPAKE_OPENSSL_LIBS = @SPAKE_OPENSSL_LIBS@ + # Whether we have the SASL header file for the LDAP KDB module HAVE_SASL = @HAVE_SASL@ +# Whether we are building support for NIST SPAKE groups using OpenSSL +HAVE_SPAKE_OPENSSL = @HAVE_SPAKE_OPENSSL@ + # Whether we have libresolv 1.1.5 for URI discovery tests HAVE_RESOLV_WRAPPER = @HAVE_RESOLV_WRAPPER@ diff --git a/src/configure.in b/src/configure.in index 2b6d5baa7..08c63beca 100644 --- a/src/configure.in +++ b/src/configure.in @@ -321,6 +321,25 @@ AC_SUBST(TLS_IMPL) AC_SUBST(TLS_IMPL_CFLAGS) AC_SUBST(TLS_IMPL_LIBS) +# The SPAKE preauth plugin currently supports edwards25519 natively, +# and can support three NIST groups using OpenSSL. +HAVE_SPAKE_OPENSSL=no +AC_ARG_WITH([spake-openssl], +AC_HELP_STRING([--with-spake-openssl], + [use OpenSSL for SPAKE preauth @<:@auto@:>@]),,[withval=auto]) +if test "$withval" = auto -o "$withval" = yes; then + AC_CHECK_LIB([crypto],[EC_POINT_new],[have_crypto=true],[have_crypto=false]) + if test "$have_crypto" = true; then + AC_DEFINE(SPAKE_OPENSSL,1,[Define to use OpenSSL for SPAKE preauth]) + SPAKE_OPENSSL_LIBS=-lcrypto + HAVE_SPAKE_OPENSSL=yes + elif test "$withval" = yes; then + AC_MSG_ERROR([OpenSSL libcrypto not found]) + fi +fi +AC_SUBST(HAVE_SPAKE_OPENSSL) +AC_SUBST(SPAKE_OPENSSL_LIBS) + AC_ARG_ENABLE([aesni], AC_HELP_STRING([--disable-aesni],[Do not build with AES-NI support]), , enable_aesni=check) @@ -1440,6 +1459,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test plugins/kdb/test plugins/kdcpolicy/test plugins/preauth/otp + plugins/preauth/spake plugins/preauth/test plugins/authdata/greet_client plugins/authdata/greet_server diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 69b81a7f7..86b53c76b 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -286,6 +286,9 @@ typedef unsigned char u_char; #define KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT "restrict_anonymous_to_tgt" #define KRB5_CONF_SAFE_CHECKSUM_TYPE "safe_checksum_type" #define KRB5_CONF_SUPPORTED_ENCTYPES "supported_enctypes" +#define KRB5_CONF_SPAKE_PREAUTH_INDICATOR "spake_preauth_indicator" +#define KRB5_CONF_SPAKE_PREAUTH_KDC_CHALLENGE "spake_preauth_kdc_challenge" +#define KRB5_CONF_SPAKE_PREAUTH_GROUPS "spake_preauth_groups" #define KRB5_CONF_TICKET_LIFETIME "ticket_lifetime" #define KRB5_CONF_UDP_PREFERENCE_LIMIT "udp_preference_limit" #define KRB5_CONF_UNLOCKITER "unlockiter" diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index a650ecece..cea22dcac 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -1034,6 +1034,7 @@ krb5_c_keyed_checksum_types(krb5_context context, krb5_enctype enctype, #define KRB5_KEYUSAGE_ENC_CHALLENGE_KDC 55 #define KRB5_KEYUSAGE_AS_REQ 56 #define KRB5_KEYUSAGE_CAMMAC 64 +#define KRB5_KEYUSAGE_SPAKE 65 /* Key usage values 512-1023 are reserved for uses internal to a Kerberos * implementation. */ @@ -1883,6 +1884,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype, #define KRB5_PADATA_PKINIT_KX 147 /**< RFC 6112 */ #define KRB5_ENCPADATA_REQ_ENC_PA_REP 149 /**< RFC 6806 */ #define KRB5_PADATA_AS_FRESHNESS 150 /**< RFC 8070 */ +#define KRB5_PADATA_SPAKE 151 #define KRB5_SAM_USE_SAD_AS_KEY 0x80000000 #define KRB5_SAM_SEND_ENCRYPTED_SAD 0x40000000 diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 62ff9a8a7..86b9e2991 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -131,6 +131,8 @@ get_plugin_vtables(krb5_context context, "preauth"); k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "otp", "preauth"); + k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "spake", + "preauth"); k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH, "encrypted_challenge", kdcpreauth_encrypted_challenge_initvt); diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index 6b96fa135..451e0b7a8 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -132,6 +132,8 @@ k5_init_preauth_context(krb5_context context) /* Auto-register built-in modules. */ k5_plugin_register_dyn(context, PLUGIN_INTERFACE_CLPREAUTH, "pkinit", "preauth"); + k5_plugin_register_dyn(context, PLUGIN_INTERFACE_CLPREAUTH, "spake", + "preauth"); k5_plugin_register(context, PLUGIN_INTERFACE_CLPREAUTH, "encrypted_challenge", clpreauth_encrypted_challenge_initvt); diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c index 10b4f0c14..40a9e7b10 100644 --- a/src/lib/krb5/os/trace.c +++ b/src/lib/krb5/os/trace.c @@ -163,6 +163,7 @@ padata_type_string(krb5_preauthtype type) case KRB5_PADATA_PKINIT_KX: return "PA-PKINIT-KX"; case KRB5_ENCPADATA_REQ_ENC_PA_REP: return "PA-REQ-ENC-PA-REP"; case KRB5_PADATA_AS_FRESHNESS: return "PA_AS_FRESHNESS"; + case KRB5_PADATA_SPAKE: return "PA-SPAKE"; default: return NULL; } } diff --git a/src/plugins/preauth/spake/AUTHORS b/src/plugins/preauth/spake/AUTHORS new file mode 100644 index 000000000..31d71c211 --- /dev/null +++ b/src/plugins/preauth/spake/AUTHORS @@ -0,0 +1,16 @@ +# This is the official list of fiat-crypto authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as one of +# Organization's name +# Individual's name +# Individual's name +# See CONTRIBUTORS for the meaning of multiple email addresses. + +# Please keep the list sorted. + +Andres Erbsen +Google Inc. +Jade Philipoom +Massachusetts Institute of Technology diff --git a/src/plugins/preauth/spake/Makefile.in b/src/plugins/preauth/spake/Makefile.in new file mode 100644 index 000000000..dd1b90730 --- /dev/null +++ b/src/plugins/preauth/spake/Makefile.in @@ -0,0 +1,39 @@ +mydir=plugins$(S)preauth$(S)spake +BUILDTOP=$(REL)..$(S)..$(S).. +MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR) + +# Like RUN_TEST, but use t_krb5.conf from this directory. +RUN_TEST_LOCAL_CONF=$(RUN_SETUP) KRB5_CONFIG=$(srcdir)/t_krb5.conf LC_ALL=C \ + $(VALGRIND) + +LIBBASE=spake +LIBMAJOR=0 +LIBMINOR=0 +RELDIR=../plugins/preauth/spake +SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS) +SHLIB_EXPLIBS=$(KRB5_BASE_LIBS) $(SPAKE_OPENSSL_LIBS) + +STLIBOBJS=util.o iana.o groups.o openssl.o edwards25519.o \ + spake_client.o spake_kdc.o + +SRCS= \ + $(srcdir)/util.c \ + $(srcdir)/iana.c \ + $(srcdir)/groups.c \ + $(srcdir)/openssl.c \ + $(srcdir)/edwards25519.c \ + $(srcdir)/spake_client.c \ + $(srcdir)/spake_kdc.c + +t_vectors: t_vectors.o $(STLIBOBJS) $(SHLIB_EXPDEPS) + $(CC_LINK) -o $@ t_vectors.o $(STLIBOBJS) $(SHLIB_EXPLIBS) + +all-unix: all-liblinks +install-unix: install-libs +clean-unix:: clean-liblinks clean-libs clean-libobjs + +check-unix: t_vectors + $(RUN_TEST_LOCAL_CONF) ./t_vectors + +@libnover_frag@ +@libobj_frag@ diff --git a/src/plugins/preauth/spake/deps b/src/plugins/preauth/spake/deps new file mode 100644 index 000000000..ce636af66 --- /dev/null +++ b/src/plugins/preauth/spake/deps @@ -0,0 +1,73 @@ +# +# Generated makefile dependencies follow. +# +util.so util.po $(OUTPRE)util.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h groups.h iana.h \ + trace.h util.c util.h +iana.so iana.po $(OUTPRE)iana.$(OBJEXT): iana.c iana.h +groups.so groups.po $(OUTPRE)groups.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h groups.c groups.h \ + iana.h trace.h +openssl.so openssl.po $(OUTPRE)openssl.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h groups.h iana.h \ + openssl.c +edwards25519.so edwards25519.po $(OUTPRE)edwards25519.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ + $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ + $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ + $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ + $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + edwards25519.c edwards25519_tables.h groups.h iana.h +spake_client.so spake_client.po $(OUTPRE)spake_client.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ + $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ + $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ + $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-spake.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/clpreauth_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + groups.h iana.h spake_client.c trace.h util.h +spake_kdc.so spake_kdc.po $(OUTPRE)spake_kdc.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ + $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-input.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-spake.h $(top_srcdir)/include/k5-thread.h \ + $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/kdcpreauth_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h groups.h iana.h \ + spake_kdc.c trace.h util.h diff --git a/src/plugins/preauth/spake/edwards25519.c b/src/plugins/preauth/spake/edwards25519.c new file mode 100644 index 000000000..fd228d9d4 --- /dev/null +++ b/src/plugins/preauth/spake/edwards25519.c @@ -0,0 +1,2651 @@ +/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*- */ +/* This file is adapted from the SPAKE edwards25519 code in BoringSSL. */ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS file). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +/* + * Copyright (c) 2015-2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This code is adapted from the BoringSSL edwards25519 SPAKE2 implementation + * from third_party/fiat and crypto/spake25519.c, with the following + * adaptations: + * + * - The M and N points are the ones from draft-irtf-cfrg-spake2-05. The + * BoringSSL M and N points were determined similarly, but were not + * restricted to members of the generator subgroup, so they use only one hash + * iteration for both points. The intent in BoringSSL had been to multiply w + * by the cofactor so that wM and wN would be in the subgroup, but as that + * step was accidentally omitted, a hack had to be introduced after the fact + * to add multiples of the prime order to the scalar. That hack is not + * present in this code, and the SPAKE preauth spec does not multiply w by + * the cofactor as it is unnecessary if M and N are chosen from the subgroup. + * + * - The SPAKE code is modified to fit the groups.h interface and the SPAKE + * preauth spec. + * + * - The required declarations and code are all here in one file (except for + * the generator point table, which is still in a separate header), so all of + * the functions are declared static. + * + * - BORINGSSL_CURVE25519_64BIT is defined here using preprocessor conditionals + * derived from the BoringSSL headers. + * + * - The field element bounds assertion checks are disabled by default, as they + * slow the code down by roughly a factor of two. The + * OPENSSL_COMPILE_ASSERT() in fe_copy_lt() is changed to a regular assert + * and is also conditionalized. Do a build and "make check" with + * EDWARDS25519_ASSERTS defined when updating this code. + * + * - The copyright comments at the top are formatted the way we do so in other + * source files, for ease of extraction. + * + * - Declarations in for loops conflict with our compiler configuration in + * older versions of gcc, so they are moved outside of the for loop. + * + * - The preprocessor symbol OPENSSL_SMALL is changed to CONFIG_SMALL. + * + * - OPENSSL_memset and OPENSSL_memmove are changed to memset and memmove, in + * each case verifying that they are used with nonzero length arguments. + * + * - CRYPTO_memcmp is changed to k5_bcmp. + * + * - Functions used only by X25519 or Ed25519 interfaces but not SPAKE are + * removed, taking care to check for unused functions in both the 64-bit and + * 32-bit preprocessor branches. ge_p3_dbl() is unused here if CONFIG_SMALL + * is defined, so it is placed inside #ifndef CONFIG_SMALL. + */ + +// Some of this code is taken from the ref10 version of Ed25519 in SUPERCOP +// 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as +// public domain but parts have been replaced with code generated by Fiat +// (https://github.com/mit-plv/fiat-crypto), which is MIT licensed. + +#include "groups.h" +#include "iana.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wdeclaration-after-statement" +#endif + +/* + * These preprocessor conditionals are derived the BoringSSL + * include/openssl/base.h (OPENSSL_64_BIT) and crypto/internal.h + * (BORINGSSL_HAS_UINT128). + */ +#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(__aarch64__) || ((defined(__PPC64__) || defined(__powerpc64__)) && defined(_LITTLE_ENDIAN)) || defined(__mips__) && defined(__LP64__) +#if !defined(_MSC_VER) || defined(__clang__) +#define BORINGSSL_CURVE25519_64BIT +typedef __int128_t int128_t; +typedef __uint128_t uint128_t; +#endif +#endif + +#ifndef EDWARDS25519_ASSERTS +#define assert_fe(f) +#define assert_fe_loose(f) +#define assert_fe_frozen(f) +#endif + +/* From BoringSSL third-party/fiat/internal.h */ + +#if defined(BORINGSSL_CURVE25519_64BIT) +// fe means field element. Here the field is \Z/(2^255-19). An element t, +// entries t[0]...t[4], represents the integer t[0]+2^51 t[1]+2^102 t[2]+2^153 +// t[3]+2^204 t[4]. +// fe limbs are bounded by 1.125*2^51. +// Multiplication and carrying produce fe from fe_loose. +typedef struct fe { uint64_t v[5]; } fe; + +// fe_loose limbs are bounded by 3.375*2^51. +// Addition and subtraction produce fe_loose from (fe, fe). +typedef struct fe_loose { uint64_t v[5]; } fe_loose; +#else +// 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]. +// fe limbs are bounded by 1.125*2^26,1.125*2^25,1.125*2^26,1.125*2^25,etc. +// Multiplication and carrying produce fe from fe_loose. +typedef struct fe { uint32_t v[10]; } fe; + +// fe_loose limbs are bounded by 3.375*2^26,3.375*2^25,3.375*2^26,3.375*2^25,etc. +// Addition and subtraction produce fe_loose from (fe, fe). +typedef struct fe_loose { uint32_t v[10]; } fe_loose; +#endif + +// 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_loose X; + fe_loose Y; + fe_loose Z; + fe_loose T; +} ge_p1p1; + +typedef struct { + fe_loose yplusx; + fe_loose yminusx; + fe_loose xy2d; +} ge_precomp; + +typedef struct { + fe_loose YplusX; + fe_loose YminusX; + fe_loose Z; + fe_loose T2d; +} ge_cached; + +#include "edwards25519_tables.h" + +/* From BoringSSL third-party/fiat/curve25519.c */ + +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; +} + +#if defined(BORINGSSL_CURVE25519_64BIT) +static uint64_t load_8(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; + result |= ((uint64_t)in[4]) << 32; + result |= ((uint64_t)in[5]) << 40; + result |= ((uint64_t)in[6]) << 48; + result |= ((uint64_t)in[7]) << 56; + return result; +} + +static uint8_t /*bool*/ addcarryx_u51(uint8_t /*bool*/ c, uint64_t a, + uint64_t b, uint64_t *low) { + // This function extracts 51 bits of result and 1 bit of carry (52 total), so + // a 64-bit intermediate is sufficient. + uint64_t x = a + b + c; + *low = x & ((UINT64_C(1) << 51) - 1); + return (x >> 51) & 1; +} + +static uint8_t /*bool*/ subborrow_u51(uint8_t /*bool*/ c, uint64_t a, + uint64_t b, uint64_t *low) { + // This function extracts 51 bits of result and 1 bit of borrow (52 total), so + // a 64-bit intermediate is sufficient. + uint64_t x = a - b - c; + *low = x & ((UINT64_C(1) << 51) - 1); + return x >> 63; +} + +static uint64_t cmovznz64(uint64_t t, uint64_t z, uint64_t nz) { + t = -!!t; // all set if nonzero, 0 if 0 + return (t&nz) | ((~t)&z); +} + +#else + +static uint8_t /*bool*/ addcarryx_u25(uint8_t /*bool*/ c, uint32_t a, + uint32_t b, uint32_t *low) { + // This function extracts 25 bits of result and 1 bit of carry (26 total), so + // a 32-bit intermediate is sufficient. + uint32_t x = a + b + c; + *low = x & ((1 << 25) - 1); + return (x >> 25) & 1; +} + +static uint8_t /*bool*/ addcarryx_u26(uint8_t /*bool*/ c, uint32_t a, + uint32_t b, uint32_t *low) { + // This function extracts 26 bits of result and 1 bit of carry (27 total), so + // a 32-bit intermediate is sufficient. + uint32_t x = a + b + c; + *low = x & ((1 << 26) - 1); + return (x >> 26) & 1; +} + +static uint8_t /*bool*/ subborrow_u25(uint8_t /*bool*/ c, uint32_t a, + uint32_t b, uint32_t *low) { + // This function extracts 25 bits of result and 1 bit of borrow (26 total), so + // a 32-bit intermediate is sufficient. + uint32_t x = a - b - c; + *low = x & ((1 << 25) - 1); + return x >> 31; +} + +static uint8_t /*bool*/ subborrow_u26(uint8_t /*bool*/ c, uint32_t a, + uint32_t b, uint32_t *low) { + // This function extracts 26 bits of result and 1 bit of borrow (27 total), so + // a 32-bit intermediate is sufficient. + uint32_t x = a - b - c; + *low = x & ((1 << 26) - 1); + return x >> 31; +} + +static uint32_t cmovznz32(uint32_t t, uint32_t z, uint32_t nz) { + t = -!!t; // all set if nonzero, 0 if 0 + return (t&nz) | ((~t)&z); +} + +#endif + + +// Field operations. + +#if defined(BORINGSSL_CURVE25519_64BIT) + +#ifdef EDWARDS25519_ASSERTS +#define assert_fe(f) do { \ + unsigned _assert_fe_i; \ + for (_assert_fe_i = 0; _assert_fe_i< 5; _assert_fe_i++) { \ + assert(f[_assert_fe_i] < 1.125*(UINT64_C(1)<<51)); \ + } \ +} while (0) + +#define assert_fe_loose(f) do { \ + unsigned _assert_fe_i; \ + for (_assert_fe_i = 0; _assert_fe_i< 5; _assert_fe_i++) { \ + assert(f[_assert_fe_i] < 3.375*(UINT64_C(1)<<51)); \ + } \ +} while (0) + +#define assert_fe_frozen(f) do { \ + unsigned _assert_fe_i; \ + for (_assert_fe_i = 0; _assert_fe_i< 5; _assert_fe_i++) { \ + assert(f[_assert_fe_i] < (UINT64_C(1)<<51)); \ + } \ +} while (0) +#endif /* EDWARDS25519_ASSERTS */ + +static void fe_frombytes_impl(uint64_t h[5], const uint8_t *s) { + // Ignores top bit of s. + uint64_t a0 = load_8(s); + uint64_t a1 = load_8(s+8); + uint64_t a2 = load_8(s+16); + uint64_t a3 = load_8(s+24); + // Use 51 bits, 64-51 = 13 left. + h[0] = a0 & ((UINT64_C(1) << 51) - 1); + // (64-51) + 38 = 13 + 38 = 51 + h[1] = (a0 >> 51) | ((a1 & ((UINT64_C(1) << 38) - 1)) << 13); + // (64-38) + 25 = 26 + 25 = 51 + h[2] = (a1 >> 38) | ((a2 & ((UINT64_C(1) << 25) - 1)) << 26); + // (64-25) + 12 = 39 + 12 = 51 + h[3] = (a2 >> 25) | ((a3 & ((UINT64_C(1) << 12) - 1)) << 39); + // (64-12) = 52, ignore top bit + h[4] = (a3 >> 12) & ((UINT64_C(1) << 51) - 1); + assert_fe(h); +} + +static void fe_frombytes(fe *h, const uint8_t *s) { + fe_frombytes_impl(h->v, s); +} + +static void fe_freeze(uint64_t out[5], const uint64_t in1[5]) { + { const uint64_t x7 = in1[4]; + { const uint64_t x8 = in1[3]; + { const uint64_t x6 = in1[2]; + { const uint64_t x4 = in1[1]; + { const uint64_t x2 = in1[0]; + { uint64_t x10; uint8_t/*bool*/ x11 = subborrow_u51(0x0, x2, 0x7ffffffffffed, &x10); + { uint64_t x13; uint8_t/*bool*/ x14 = subborrow_u51(x11, x4, 0x7ffffffffffff, &x13); + { uint64_t x16; uint8_t/*bool*/ x17 = subborrow_u51(x14, x6, 0x7ffffffffffff, &x16); + { uint64_t x19; uint8_t/*bool*/ x20 = subborrow_u51(x17, x8, 0x7ffffffffffff, &x19); + { uint64_t x22; uint8_t/*bool*/ x23 = subborrow_u51(x20, x7, 0x7ffffffffffff, &x22); + { uint64_t x24 = cmovznz64(x23, 0x0, 0xffffffffffffffffL); + { uint64_t x25 = (x24 & 0x7ffffffffffed); + { uint64_t x27; uint8_t/*bool*/ x28 = addcarryx_u51(0x0, x10, x25, &x27); + { uint64_t x29 = (x24 & 0x7ffffffffffff); + { uint64_t x31; uint8_t/*bool*/ x32 = addcarryx_u51(x28, x13, x29, &x31); + { uint64_t x33 = (x24 & 0x7ffffffffffff); + { uint64_t x35; uint8_t/*bool*/ x36 = addcarryx_u51(x32, x16, x33, &x35); + { uint64_t x37 = (x24 & 0x7ffffffffffff); + { uint64_t x39; uint8_t/*bool*/ x40 = addcarryx_u51(x36, x19, x37, &x39); + { uint64_t x41 = (x24 & 0x7ffffffffffff); + { uint64_t x43; addcarryx_u51(x40, x22, x41, &x43); + out[0] = x27; + out[1] = x31; + out[2] = x35; + out[3] = x39; + out[4] = x43; + }}}}}}}}}}}}}}}}}}}}} +} + +static void fe_tobytes(uint8_t s[32], const fe *f) { + assert_fe(f->v); + uint64_t h[5]; + fe_freeze(h, f->v); + assert_fe_frozen(h); + + s[0] = h[0] >> 0; + s[1] = h[0] >> 8; + s[2] = h[0] >> 16; + s[3] = h[0] >> 24; + s[4] = h[0] >> 32; + s[5] = h[0] >> 40; + s[6] = (h[0] >> 48) | (h[1] << 3); + s[7] = h[1] >> 5; + s[8] = h[1] >> 13; + s[9] = h[1] >> 21; + s[10] = h[1] >> 29; + s[11] = h[1] >> 37; + s[12] = (h[1] >> 45) | (h[2] << 6); + s[13] = h[2] >> 2; + s[14] = h[2] >> 10; + s[15] = h[2] >> 18; + s[16] = h[2] >> 26; + s[17] = h[2] >> 34; + s[18] = h[2] >> 42; + s[19] = (h[2] >> 50) | (h[3] << 1); + s[20] = h[3] >> 7; + s[21] = h[3] >> 15; + s[22] = h[3] >> 23; + s[23] = h[3] >> 31; + s[24] = h[3] >> 39; + s[25] = (h[3] >> 47) | (h[4] << 4); + s[26] = h[4] >> 4; + s[27] = h[4] >> 12; + s[28] = h[4] >> 20; + s[29] = h[4] >> 28; + s[30] = h[4] >> 36; + s[31] = h[4] >> 44; +} + +// h = 0 +static void fe_0(fe *h) { + memset(h, 0, sizeof(fe)); +} + +static void fe_loose_0(fe_loose *h) { + memset(h, 0, sizeof(fe_loose)); +} + +// h = 1 +static void fe_1(fe *h) { + memset(h, 0, sizeof(fe)); + h->v[0] = 1; +} + +static void fe_loose_1(fe_loose *h) { + memset(h, 0, sizeof(fe_loose)); + h->v[0] = 1; +} + +static void fe_add_impl(uint64_t out[5], const uint64_t in1[5], const uint64_t in2[5]) { + { const uint64_t x10 = in1[4]; + { const uint64_t x11 = in1[3]; + { const uint64_t x9 = in1[2]; + { const uint64_t x7 = in1[1]; + { const uint64_t x5 = in1[0]; + { const uint64_t x18 = in2[4]; + { const uint64_t x19 = in2[3]; + { const uint64_t x17 = in2[2]; + { const uint64_t x15 = in2[1]; + { const uint64_t x13 = in2[0]; + out[0] = (x5 + x13); + out[1] = (x7 + x15); + out[2] = (x9 + x17); + out[3] = (x11 + x19); + out[4] = (x10 + x18); + }}}}}}}}}} +} + +// h = f + g +// Can overlap h with f or g. +static void fe_add(fe_loose *h, const fe *f, const fe *g) { + assert_fe(f->v); + assert_fe(g->v); + fe_add_impl(h->v, f->v, g->v); + assert_fe_loose(h->v); +} + +static void fe_sub_impl(uint64_t out[5], const uint64_t in1[5], const uint64_t in2[5]) { + { const uint64_t x10 = in1[4]; + { const uint64_t x11 = in1[3]; + { const uint64_t x9 = in1[2]; + { const uint64_t x7 = in1[1]; + { const uint64_t x5 = in1[0]; + { const uint64_t x18 = in2[4]; + { const uint64_t x19 = in2[3]; + { const uint64_t x17 = in2[2]; + { const uint64_t x15 = in2[1]; + { const uint64_t x13 = in2[0]; + out[0] = ((0xfffffffffffda + x5) - x13); + out[1] = ((0xffffffffffffe + x7) - x15); + out[2] = ((0xffffffffffffe + x9) - x17); + out[3] = ((0xffffffffffffe + x11) - x19); + out[4] = ((0xffffffffffffe + x10) - x18); + }}}}}}}}}} +} + +// h = f - g +// Can overlap h with f or g. +static void fe_sub(fe_loose *h, const fe *f, const fe *g) { + assert_fe(f->v); + assert_fe(g->v); + fe_sub_impl(h->v, f->v, g->v); + assert_fe_loose(h->v); +} + +static void fe_carry_impl(uint64_t out[5], const uint64_t in1[5]) { + { const uint64_t x7 = in1[4]; + { const uint64_t x8 = in1[3]; + { const uint64_t x6 = in1[2]; + { const uint64_t x4 = in1[1]; + { const uint64_t x2 = in1[0]; + { uint64_t x9 = (x2 >> 0x33); + { uint64_t x10 = (x2 & 0x7ffffffffffff); + { uint64_t x11 = (x9 + x4); + { uint64_t x12 = (x11 >> 0x33); + { uint64_t x13 = (x11 & 0x7ffffffffffff); + { uint64_t x14 = (x12 + x6); + { uint64_t x15 = (x14 >> 0x33); + { uint64_t x16 = (x14 & 0x7ffffffffffff); + { uint64_t x17 = (x15 + x8); + { uint64_t x18 = (x17 >> 0x33); + { uint64_t x19 = (x17 & 0x7ffffffffffff); + { uint64_t x20 = (x18 + x7); + { uint64_t x21 = (x20 >> 0x33); + { uint64_t x22 = (x20 & 0x7ffffffffffff); + { uint64_t x23 = (x10 + (0x13 * x21)); + { uint64_t x24 = (x23 >> 0x33); + { uint64_t x25 = (x23 & 0x7ffffffffffff); + { uint64_t x26 = (x24 + x13); + { uint64_t x27 = (x26 >> 0x33); + { uint64_t x28 = (x26 & 0x7ffffffffffff); + out[0] = x25; + out[1] = x28; + out[2] = (x27 + x16); + out[3] = x19; + out[4] = x22; + }}}}}}}}}}}}}}}}}}}}}}}}} +} + +static void fe_carry(fe *h, const fe_loose* f) { + assert_fe_loose(f->v); + fe_carry_impl(h->v, f->v); + assert_fe(h->v); +} + +static void fe_mul_impl(uint64_t out[5], const uint64_t in1[5], const uint64_t in2[5]) { + assert_fe_loose(in1); + assert_fe_loose(in2); + { const uint64_t x10 = in1[4]; + { const uint64_t x11 = in1[3]; + { const uint64_t x9 = in1[2]; + { const uint64_t x7 = in1[1]; + { const uint64_t x5 = in1[0]; + { const uint64_t x18 = in2[4]; + { const uint64_t x19 = in2[3]; + { const uint64_t x17 = in2[2]; + { const uint64_t x15 = in2[1]; + { const uint64_t x13 = in2[0]; + { uint128_t x20 = ((uint128_t)x5 * x13); + { uint128_t x21 = (((uint128_t)x5 * x15) + ((uint128_t)x7 * x13)); + { uint128_t x22 = ((((uint128_t)x5 * x17) + ((uint128_t)x9 * x13)) + ((uint128_t)x7 * x15)); + { uint128_t x23 = (((((uint128_t)x5 * x19) + ((uint128_t)x11 * x13)) + ((uint128_t)x7 * x17)) + ((uint128_t)x9 * x15)); + { uint128_t x24 = ((((((uint128_t)x5 * x18) + ((uint128_t)x10 * x13)) + ((uint128_t)x11 * x15)) + ((uint128_t)x7 * x19)) + ((uint128_t)x9 * x17)); + { uint64_t x25 = (x10 * 0x13); + { uint64_t x26 = (x7 * 0x13); + { uint64_t x27 = (x9 * 0x13); + { uint64_t x28 = (x11 * 0x13); + { uint128_t x29 = ((((x20 + ((uint128_t)x25 * x15)) + ((uint128_t)x26 * x18)) + ((uint128_t)x27 * x19)) + ((uint128_t)x28 * x17)); + { uint128_t x30 = (((x21 + ((uint128_t)x25 * x17)) + ((uint128_t)x27 * x18)) + ((uint128_t)x28 * x19)); + { uint128_t x31 = ((x22 + ((uint128_t)x25 * x19)) + ((uint128_t)x28 * x18)); + { uint128_t x32 = (x23 + ((uint128_t)x25 * x18)); + { uint64_t x33 = (uint64_t) (x29 >> 0x33); + { uint64_t x34 = ((uint64_t)x29 & 0x7ffffffffffff); + { uint128_t x35 = (x33 + x30); + { uint64_t x36 = (uint64_t) (x35 >> 0x33); + { uint64_t x37 = ((uint64_t)x35 & 0x7ffffffffffff); + { uint128_t x38 = (x36 + x31); + { uint64_t x39 = (uint64_t) (x38 >> 0x33); + { uint64_t x40 = ((uint64_t)x38 & 0x7ffffffffffff); + { uint128_t x41 = (x39 + x32); + { uint64_t x42 = (uint64_t) (x41 >> 0x33); + { uint64_t x43 = ((uint64_t)x41 & 0x7ffffffffffff); + { uint128_t x44 = (x42 + x24); + { uint64_t x45 = (uint64_t) (x44 >> 0x33); + { uint64_t x46 = ((uint64_t)x44 & 0x7ffffffffffff); + { uint64_t x47 = (x34 + (0x13 * x45)); + { uint64_t x48 = (x47 >> 0x33); + { uint64_t x49 = (x47 & 0x7ffffffffffff); + { uint64_t x50 = (x48 + x37); + { uint64_t x51 = (x50 >> 0x33); + { uint64_t x52 = (x50 & 0x7ffffffffffff); + out[0] = x49; + out[1] = x52; + out[2] = (x51 + x40); + out[3] = x43; + out[4] = x46; + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} + assert_fe(out); +} + +static void fe_mul_ltt(fe_loose *h, const fe *f, const fe *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_llt(fe_loose *h, const fe_loose *f, const fe *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_ttt(fe *h, const fe *f, const fe *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_tlt(fe *h, const fe_loose *f, const fe *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_ttl(fe *h, const fe *f, const fe_loose *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_tll(fe *h, const fe_loose *f, const fe_loose *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_sqr_impl(uint64_t out[5], const uint64_t in1[5]) { + assert_fe_loose(in1); + { const uint64_t x7 = in1[4]; + { const uint64_t x8 = in1[3]; + { const uint64_t x6 = in1[2]; + { const uint64_t x4 = in1[1]; + { const uint64_t x2 = in1[0]; + { uint64_t x9 = (x2 * 0x2); + { uint64_t x10 = (x4 * 0x2); + { uint64_t x11 = ((x6 * 0x2) * 0x13); + { uint64_t x12 = (x7 * 0x13); + { uint64_t x13 = (x12 * 0x2); + { uint128_t x14 = ((((uint128_t)x2 * x2) + ((uint128_t)x13 * x4)) + ((uint128_t)x11 * x8)); + { uint128_t x15 = ((((uint128_t)x9 * x4) + ((uint128_t)x13 * x6)) + ((uint128_t)x8 * (x8 * 0x13))); + { uint128_t x16 = ((((uint128_t)x9 * x6) + ((uint128_t)x4 * x4)) + ((uint128_t)x13 * x8)); + { uint128_t x17 = ((((uint128_t)x9 * x8) + ((uint128_t)x10 * x6)) + ((uint128_t)x7 * x12)); + { uint128_t x18 = ((((uint128_t)x9 * x7) + ((uint128_t)x10 * x8)) + ((uint128_t)x6 * x6)); + { uint64_t x19 = (uint64_t) (x14 >> 0x33); + { uint64_t x20 = ((uint64_t)x14 & 0x7ffffffffffff); + { uint128_t x21 = (x19 + x15); + { uint64_t x22 = (uint64_t) (x21 >> 0x33); + { uint64_t x23 = ((uint64_t)x21 & 0x7ffffffffffff); + { uint128_t x24 = (x22 + x16); + { uint64_t x25 = (uint64_t) (x24 >> 0x33); + { uint64_t x26 = ((uint64_t)x24 & 0x7ffffffffffff); + { uint128_t x27 = (x25 + x17); + { uint64_t x28 = (uint64_t) (x27 >> 0x33); + { uint64_t x29 = ((uint64_t)x27 & 0x7ffffffffffff); + { uint128_t x30 = (x28 + x18); + { uint64_t x31 = (uint64_t) (x30 >> 0x33); + { uint64_t x32 = ((uint64_t)x30 & 0x7ffffffffffff); + { uint64_t x33 = (x20 + (0x13 * x31)); + { uint64_t x34 = (x33 >> 0x33); + { uint64_t x35 = (x33 & 0x7ffffffffffff); + { uint64_t x36 = (x34 + x23); + { uint64_t x37 = (x36 >> 0x33); + { uint64_t x38 = (x36 & 0x7ffffffffffff); + out[0] = x35; + out[1] = x38; + out[2] = (x37 + x26); + out[3] = x29; + out[4] = x32; + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} + assert_fe(out); +} + +static void fe_sq_tl(fe *h, const fe_loose *f) { + fe_sqr_impl(h->v, f->v); +} + +static void fe_sq_tt(fe *h, const fe *f) { + fe_sqr_impl(h->v, f->v); +} + +// Adapted from Fiat-synthesized |fe_sub_impl| with |out| = 0. +static void fe_neg_impl(uint64_t out[5], const uint64_t in2[5]) { + { const uint64_t x10 = 0; + { const uint64_t x11 = 0; + { const uint64_t x9 = 0; + { const uint64_t x7 = 0; + { const uint64_t x5 = 0; + { const uint64_t x18 = in2[4]; + { const uint64_t x19 = in2[3]; + { const uint64_t x17 = in2[2]; + { const uint64_t x15 = in2[1]; + { const uint64_t x13 = in2[0]; + out[0] = ((0xfffffffffffda + x5) - x13); + out[1] = ((0xffffffffffffe + x7) - x15); + out[2] = ((0xffffffffffffe + x9) - x17); + out[3] = ((0xffffffffffffe + x11) - x19); + out[4] = ((0xffffffffffffe + x10) - x18); + }}}}}}}}}} +} + +// h = -f +static void fe_neg(fe_loose *h, const fe *f) { + assert_fe(f->v); + fe_neg_impl(h->v, f->v); + assert_fe_loose(h->v); +} + +// 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_loose *f, const fe_loose *g, uint64_t b) { + unsigned i; + b = 0-b; + for (i = 0; i < 5; i++) { + uint64_t x = f->v[i] ^ g->v[i]; + x &= b; + f->v[i] ^= x; + } +} + +#else + +#ifdef EDWARDS25519_ASSERTS +#define assert_fe(f) do { \ + unsigned _assert_fe_i; \ + for (_assert_fe_i = 0; _assert_fe_i< 10; _assert_fe_i++) { \ + assert(f[_assert_fe_i] < 1.125*(1<<(26-(_assert_fe_i&1)))); \ + } \ +} while (0) + +#define assert_fe_loose(f) do { \ + unsigned _assert_fe_i; \ + for (_assert_fe_i = 0; _assert_fe_i< 10; _assert_fe_i++) { \ + assert(f[_assert_fe_i] < 3.375*(1<<(26-(_assert_fe_i&1)))); \ + } \ +} while (0) + +#define assert_fe_frozen(f) do { \ + unsigned _assert_fe_i; \ + for (_assert_fe_i = 0; _assert_fe_i< 10; _assert_fe_i++) { \ + assert(f[_assert_fe_i] < (1u<<(26-(_assert_fe_i&1)))); \ + } \ +} while (0) +#endif /* EDWARDS25519_ASSERTS */ + +static void fe_frombytes_impl(uint32_t h[10], const uint8_t *s) { + // Ignores top bit of s. + uint32_t a0 = load_4(s); + uint32_t a1 = load_4(s+4); + uint32_t a2 = load_4(s+8); + uint32_t a3 = load_4(s+12); + uint32_t a4 = load_4(s+16); + uint32_t a5 = load_4(s+20); + uint32_t a6 = load_4(s+24); + uint32_t a7 = load_4(s+28); + h[0] = a0&((1<<26)-1); // 26 used, 32-26 left. 26 + h[1] = (a0>>26) | ((a1&((1<<19)-1))<< 6); // (32-26) + 19 = 6+19 = 25 + h[2] = (a1>>19) | ((a2&((1<<13)-1))<<13); // (32-19) + 13 = 13+13 = 26 + h[3] = (a2>>13) | ((a3&((1<< 6)-1))<<19); // (32-13) + 6 = 19+ 6 = 25 + h[4] = (a3>> 6); // (32- 6) = 26 + h[5] = a4&((1<<25)-1); // 25 + h[6] = (a4>>25) | ((a5&((1<<19)-1))<< 7); // (32-25) + 19 = 7+19 = 26 + h[7] = (a5>>19) | ((a6&((1<<12)-1))<<13); // (32-19) + 12 = 13+12 = 25 + h[8] = (a6>>12) | ((a7&((1<< 6)-1))<<20); // (32-12) + 6 = 20+ 6 = 26 + h[9] = (a7>> 6)&((1<<25)-1); // 25 + assert_fe(h); +} + +static void fe_frombytes(fe *h, const uint8_t *s) { + fe_frombytes_impl(h->v, s); +} + +static void fe_freeze(uint32_t out[10], const uint32_t in1[10]) { + { const uint32_t x17 = in1[9]; + { const uint32_t x18 = in1[8]; + { const uint32_t x16 = in1[7]; + { const uint32_t x14 = in1[6]; + { const uint32_t x12 = in1[5]; + { const uint32_t x10 = in1[4]; + { const uint32_t x8 = in1[3]; + { const uint32_t x6 = in1[2]; + { const uint32_t x4 = in1[1]; + { const uint32_t x2 = in1[0]; + { uint32_t x20; uint8_t/*bool*/ x21 = subborrow_u26(0x0, x2, 0x3ffffed, &x20); + { uint32_t x23; uint8_t/*bool*/ x24 = subborrow_u25(x21, x4, 0x1ffffff, &x23); + { uint32_t x26; uint8_t/*bool*/ x27 = subborrow_u26(x24, x6, 0x3ffffff, &x26); + { uint32_t x29; uint8_t/*bool*/ x30 = subborrow_u25(x27, x8, 0x1ffffff, &x29); + { uint32_t x32; uint8_t/*bool*/ x33 = subborrow_u26(x30, x10, 0x3ffffff, &x32); + { uint32_t x35; uint8_t/*bool*/ x36 = subborrow_u25(x33, x12, 0x1ffffff, &x35); + { uint32_t x38; uint8_t/*bool*/ x39 = subborrow_u26(x36, x14, 0x3ffffff, &x38); + { uint32_t x41; uint8_t/*bool*/ x42 = subborrow_u25(x39, x16, 0x1ffffff, &x41); + { uint32_t x44; uint8_t/*bool*/ x45 = subborrow_u26(x42, x18, 0x3ffffff, &x44); + { uint32_t x47; uint8_t/*bool*/ x48 = subborrow_u25(x45, x17, 0x1ffffff, &x47); + { uint32_t x49 = cmovznz32(x48, 0x0, 0xffffffff); + { uint32_t x50 = (x49 & 0x3ffffed); + { uint32_t x52; uint8_t/*bool*/ x53 = addcarryx_u26(0x0, x20, x50, &x52); + { uint32_t x54 = (x49 & 0x1ffffff); + { uint32_t x56; uint8_t/*bool*/ x57 = addcarryx_u25(x53, x23, x54, &x56); + { uint32_t x58 = (x49 & 0x3ffffff); + { uint32_t x60; uint8_t/*bool*/ x61 = addcarryx_u26(x57, x26, x58, &x60); + { uint32_t x62 = (x49 & 0x1ffffff); + { uint32_t x64; uint8_t/*bool*/ x65 = addcarryx_u25(x61, x29, x62, &x64); + { uint32_t x66 = (x49 & 0x3ffffff); + { uint32_t x68; uint8_t/*bool*/ x69 = addcarryx_u26(x65, x32, x66, &x68); + { uint32_t x70 = (x49 & 0x1ffffff); + { uint32_t x72; uint8_t/*bool*/ x73 = addcarryx_u25(x69, x35, x70, &x72); + { uint32_t x74 = (x49 & 0x3ffffff); + { uint32_t x76; uint8_t/*bool*/ x77 = addcarryx_u26(x73, x38, x74, &x76); + { uint32_t x78 = (x49 & 0x1ffffff); + { uint32_t x80; uint8_t/*bool*/ x81 = addcarryx_u25(x77, x41, x78, &x80); + { uint32_t x82 = (x49 & 0x3ffffff); + { uint32_t x84; uint8_t/*bool*/ x85 = addcarryx_u26(x81, x44, x82, &x84); + { uint32_t x86 = (x49 & 0x1ffffff); + { uint32_t x88; addcarryx_u25(x85, x47, x86, &x88); + out[0] = x52; + out[1] = x56; + out[2] = x60; + out[3] = x64; + out[4] = x68; + out[5] = x72; + out[6] = x76; + out[7] = x80; + out[8] = x84; + out[9] = x88; + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} +} + +static void fe_tobytes(uint8_t s[32], const fe *f) { + assert_fe(f->v); + uint32_t h[10]; + fe_freeze(h, f->v); + assert_fe_frozen(h); + + s[0] = h[0] >> 0; + s[1] = h[0] >> 8; + s[2] = h[0] >> 16; + s[3] = (h[0] >> 24) | (h[1] << 2); + s[4] = h[1] >> 6; + s[5] = h[1] >> 14; + s[6] = (h[1] >> 22) | (h[2] << 3); + s[7] = h[2] >> 5; + s[8] = h[2] >> 13; + s[9] = (h[2] >> 21) | (h[3] << 5); + s[10] = h[3] >> 3; + s[11] = h[3] >> 11; + s[12] = (h[3] >> 19) | (h[4] << 6); + s[13] = h[4] >> 2; + s[14] = h[4] >> 10; + s[15] = h[4] >> 18; + s[16] = h[5] >> 0; + s[17] = h[5] >> 8; + s[18] = h[5] >> 16; + s[19] = (h[5] >> 24) | (h[6] << 1); + s[20] = h[6] >> 7; + s[21] = h[6] >> 15; + s[22] = (h[6] >> 23) | (h[7] << 3); + s[23] = h[7] >> 5; + s[24] = h[7] >> 13; + s[25] = (h[7] >> 21) | (h[8] << 4); + s[26] = h[8] >> 4; + s[27] = h[8] >> 12; + s[28] = (h[8] >> 20) | (h[9] << 6); + s[29] = h[9] >> 2; + s[30] = h[9] >> 10; + s[31] = h[9] >> 18; +} + +// h = 0 +static void fe_0(fe *h) { + memset(h, 0, sizeof(fe)); +} + +static void fe_loose_0(fe_loose *h) { + memset(h, 0, sizeof(fe_loose)); +} + +// h = 1 +static void fe_1(fe *h) { + memset(h, 0, sizeof(fe)); + h->v[0] = 1; +} + +static void fe_loose_1(fe_loose *h) { + memset(h, 0, sizeof(fe_loose)); + h->v[0] = 1; +} + +static void fe_add_impl(uint32_t out[10], const uint32_t in1[10], const uint32_t in2[10]) { + { const uint32_t x20 = in1[9]; + { const uint32_t x21 = in1[8]; + { const uint32_t x19 = in1[7]; + { const uint32_t x17 = in1[6]; + { const uint32_t x15 = in1[5]; + { const uint32_t x13 = in1[4]; + { const uint32_t x11 = in1[3]; + { const uint32_t x9 = in1[2]; + { const uint32_t x7 = in1[1]; + { const uint32_t x5 = in1[0]; + { const uint32_t x38 = in2[9]; + { const uint32_t x39 = in2[8]; + { const uint32_t x37 = in2[7]; + { const uint32_t x35 = in2[6]; + { const uint32_t x33 = in2[5]; + { const uint32_t x31 = in2[4]; + { const uint32_t x29 = in2[3]; + { const uint32_t x27 = in2[2]; + { const uint32_t x25 = in2[1]; + { const uint32_t x23 = in2[0]; + out[0] = (x5 + x23); + out[1] = (x7 + x25); + out[2] = (x9 + x27); + out[3] = (x11 + x29); + out[4] = (x13 + x31); + out[5] = (x15 + x33); + out[6] = (x17 + x35); + out[7] = (x19 + x37); + out[8] = (x21 + x39); + out[9] = (x20 + x38); + }}}}}}}}}}}}}}}}}}}} +} + +// h = f + g +// Can overlap h with f or g. +static void fe_add(fe_loose *h, const fe *f, const fe *g) { + assert_fe(f->v); + assert_fe(g->v); + fe_add_impl(h->v, f->v, g->v); + assert_fe_loose(h->v); +} + +static void fe_sub_impl(uint32_t out[10], const uint32_t in1[10], const uint32_t in2[10]) { + { const uint32_t x20 = in1[9]; + { const uint32_t x21 = in1[8]; + { const uint32_t x19 = in1[7]; + { const uint32_t x17 = in1[6]; + { const uint32_t x15 = in1[5]; + { const uint32_t x13 = in1[4]; + { const uint32_t x11 = in1[3]; + { const uint32_t x9 = in1[2]; + { const uint32_t x7 = in1[1]; + { const uint32_t x5 = in1[0]; + { const uint32_t x38 = in2[9]; + { const uint32_t x39 = in2[8]; + { const uint32_t x37 = in2[7]; + { const uint32_t x35 = in2[6]; + { const uint32_t x33 = in2[5]; + { const uint32_t x31 = in2[4]; + { const uint32_t x29 = in2[3]; + { const uint32_t x27 = in2[2]; + { const uint32_t x25 = in2[1]; + { const uint32_t x23 = in2[0]; + out[0] = ((0x7ffffda + x5) - x23); + out[1] = ((0x3fffffe + x7) - x25); + out[2] = ((0x7fffffe + x9) - x27); + out[3] = ((0x3fffffe + x11) - x29); + out[4] = ((0x7fffffe + x13) - x31); + out[5] = ((0x3fffffe + x15) - x33); + out[6] = ((0x7fffffe + x17) - x35); + out[7] = ((0x3fffffe + x19) - x37); + out[8] = ((0x7fffffe + x21) - x39); + out[9] = ((0x3fffffe + x20) - x38); + }}}}}}}}}}}}}}}}}}}} +} + +// h = f - g +// Can overlap h with f or g. +static void fe_sub(fe_loose *h, const fe *f, const fe *g) { + assert_fe(f->v); + assert_fe(g->v); + fe_sub_impl(h->v, f->v, g->v); + assert_fe_loose(h->v); +} + +static void fe_carry_impl(uint32_t out[10], const uint32_t in1[10]) { + { const uint32_t x17 = in1[9]; + { const uint32_t x18 = in1[8]; + { const uint32_t x16 = in1[7]; + { const uint32_t x14 = in1[6]; + { const uint32_t x12 = in1[5]; + { const uint32_t x10 = in1[4]; + { const uint32_t x8 = in1[3]; + { const uint32_t x6 = in1[2]; + { const uint32_t x4 = in1[1]; + { const uint32_t x2 = in1[0]; + { uint32_t x19 = (x2 >> 0x1a); + { uint32_t x20 = (x2 & 0x3ffffff); + { uint32_t x21 = (x19 + x4); + { uint32_t x22 = (x21 >> 0x19); + { uint32_t x23 = (x21 & 0x1ffffff); + { uint32_t x24 = (x22 + x6); + { uint32_t x25 = (x24 >> 0x1a); + { uint32_t x26 = (x24 & 0x3ffffff); + { uint32_t x27 = (x25 + x8); + { uint32_t x28 = (x27 >> 0x19); + { uint32_t x29 = (x27 & 0x1ffffff); + { uint32_t x30 = (x28 + x10); + { uint32_t x31 = (x30 >> 0x1a); + { uint32_t x32 = (x30 & 0x3ffffff); + { uint32_t x33 = (x31 + x12); + { uint32_t x34 = (x33 >> 0x19); + { uint32_t x35 = (x33 & 0x1ffffff); + { uint32_t x36 = (x34 + x14); + { uint32_t x37 = (x36 >> 0x1a); + { uint32_t x38 = (x36 & 0x3ffffff); + { uint32_t x39 = (x37 + x16); + { uint32_t x40 = (x39 >> 0x19); + { uint32_t x41 = (x39 & 0x1ffffff); + { uint32_t x42 = (x40 + x18); + { uint32_t x43 = (x42 >> 0x1a); + { uint32_t x44 = (x42 & 0x3ffffff); + { uint32_t x45 = (x43 + x17); + { uint32_t x46 = (x45 >> 0x19); + { uint32_t x47 = (x45 & 0x1ffffff); + { uint32_t x48 = (x20 + (0x13 * x46)); + { uint32_t x49 = (x48 >> 0x1a); + { uint32_t x50 = (x48 & 0x3ffffff); + { uint32_t x51 = (x49 + x23); + { uint32_t x52 = (x51 >> 0x19); + { uint32_t x53 = (x51 & 0x1ffffff); + out[0] = x50; + out[1] = x53; + out[2] = (x52 + x26); + out[3] = x29; + out[4] = x32; + out[5] = x35; + out[6] = x38; + out[7] = x41; + out[8] = x44; + out[9] = x47; + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} +} + +static void fe_carry(fe *h, const fe_loose* f) { + assert_fe_loose(f->v); + fe_carry_impl(h->v, f->v); + assert_fe(h->v); +} + +static void fe_mul_impl(uint32_t out[10], const uint32_t in1[10], const uint32_t in2[10]) { + assert_fe_loose(in1); + assert_fe_loose(in2); + { const uint32_t x20 = in1[9]; + { const uint32_t x21 = in1[8]; + { const uint32_t x19 = in1[7]; + { const uint32_t x17 = in1[6]; + { const uint32_t x15 = in1[5]; + { const uint32_t x13 = in1[4]; + { const uint32_t x11 = in1[3]; + { const uint32_t x9 = in1[2]; + { const uint32_t x7 = in1[1]; + { const uint32_t x5 = in1[0]; + { const uint32_t x38 = in2[9]; + { const uint32_t x39 = in2[8]; + { const uint32_t x37 = in2[7]; + { const uint32_t x35 = in2[6]; + { const uint32_t x33 = in2[5]; + { const uint32_t x31 = in2[4]; + { const uint32_t x29 = in2[3]; + { const uint32_t x27 = in2[2]; + { const uint32_t x25 = in2[1]; + { const uint32_t x23 = in2[0]; + { uint64_t x40 = ((uint64_t)x23 * x5); + { uint64_t x41 = (((uint64_t)x23 * x7) + ((uint64_t)x25 * x5)); + { uint64_t x42 = ((((uint64_t)(0x2 * x25) * x7) + ((uint64_t)x23 * x9)) + ((uint64_t)x27 * x5)); + { uint64_t x43 = (((((uint64_t)x25 * x9) + ((uint64_t)x27 * x7)) + ((uint64_t)x23 * x11)) + ((uint64_t)x29 * x5)); + { uint64_t x44 = (((((uint64_t)x27 * x9) + (0x2 * (((uint64_t)x25 * x11) + ((uint64_t)x29 * x7)))) + ((uint64_t)x23 * x13)) + ((uint64_t)x31 * x5)); + { uint64_t x45 = (((((((uint64_t)x27 * x11) + ((uint64_t)x29 * x9)) + ((uint64_t)x25 * x13)) + ((uint64_t)x31 * x7)) + ((uint64_t)x23 * x15)) + ((uint64_t)x33 * x5)); + { uint64_t x46 = (((((0x2 * ((((uint64_t)x29 * x11) + ((uint64_t)x25 * x15)) + ((uint64_t)x33 * x7))) + ((uint64_t)x27 * x13)) + ((uint64_t)x31 * x9)) + ((uint64_t)x23 * x17)) + ((uint64_t)x35 * x5)); + { uint64_t x47 = (((((((((uint64_t)x29 * x13) + ((uint64_t)x31 * x11)) + ((uint64_t)x27 * x15)) + ((uint64_t)x33 * x9)) + ((uint64_t)x25 * x17)) + ((uint64_t)x35 * x7)) + ((uint64_t)x23 * x19)) + ((uint64_t)x37 * x5)); + { uint64_t x48 = (((((((uint64_t)x31 * x13) + (0x2 * (((((uint64_t)x29 * x15) + ((uint64_t)x33 * x11)) + ((uint64_t)x25 * x19)) + ((uint64_t)x37 * x7)))) + ((uint64_t)x27 * x17)) + ((uint64_t)x35 * x9)) + ((uint64_t)x23 * x21)) + ((uint64_t)x39 * x5)); + { uint64_t x49 = (((((((((((uint64_t)x31 * x15) + ((uint64_t)x33 * x13)) + ((uint64_t)x29 * x17)) + ((uint64_t)x35 * x11)) + ((uint64_t)x27 * x19)) + ((uint64_t)x37 * x9)) + ((uint64_t)x25 * x21)) + ((uint64_t)x39 * x7)) + ((uint64_t)x23 * x20)) + ((uint64_t)x38 * x5)); + { uint64_t x50 = (((((0x2 * ((((((uint64_t)x33 * x15) + ((uint64_t)x29 * x19)) + ((uint64_t)x37 * x11)) + ((uint64_t)x25 * x20)) + ((uint64_t)x38 * x7))) + ((uint64_t)x31 * x17)) + ((uint64_t)x35 * x13)) + ((uint64_t)x27 * x21)) + ((uint64_t)x39 * x9)); + { uint64_t x51 = (((((((((uint64_t)x33 * x17) + ((uint64_t)x35 * x15)) + ((uint64_t)x31 * x19)) + ((uint64_t)x37 * x13)) + ((uint64_t)x29 * x21)) + ((uint64_t)x39 * x11)) + ((uint64_t)x27 * x20)) + ((uint64_t)x38 * x9)); + { uint64_t x52 = (((((uint64_t)x35 * x17) + (0x2 * (((((uint64_t)x33 * x19) + ((uint64_t)x37 * x15)) + ((uint64_t)x29 * x20)) + ((uint64_t)x38 * x11)))) + ((uint64_t)x31 * x21)) + ((uint64_t)x39 * x13)); + { uint64_t x53 = (((((((uint64_t)x35 * x19) + ((uint64_t)x37 * x17)) + ((uint64_t)x33 * x21)) + ((uint64_t)x39 * x15)) + ((uint64_t)x31 * x20)) + ((uint64_t)x38 * x13)); + { uint64_t x54 = (((0x2 * ((((uint64_t)x37 * x19) + ((uint64_t)x33 * x20)) + ((uint64_t)x38 * x15))) + ((uint64_t)x35 * x21)) + ((uint64_t)x39 * x17)); + { uint64_t x55 = (((((uint64_t)x37 * x21) + ((uint64_t)x39 * x19)) + ((uint64_t)x35 * x20)) + ((uint64_t)x38 * x17)); + { uint64_t x56 = (((uint64_t)x39 * x21) + (0x2 * (((uint64_t)x37 * x20) + ((uint64_t)x38 * x19)))); + { uint64_t x57 = (((uint64_t)x39 * x20) + ((uint64_t)x38 * x21)); + { uint64_t x58 = ((uint64_t)(0x2 * x38) * x20); + { uint64_t x59 = (x48 + (x58 << 0x4)); + { uint64_t x60 = (x59 + (x58 << 0x1)); + { uint64_t x61 = (x60 + x58); + { uint64_t x62 = (x47 + (x57 << 0x4)); + { uint64_t x63 = (x62 + (x57 << 0x1)); + { uint64_t x64 = (x63 + x57); + { uint64_t x65 = (x46 + (x56 << 0x4)); + { uint64_t x66 = (x65 + (x56 << 0x1)); + { uint64_t x67 = (x66 + x56); + { uint64_t x68 = (x45 + (x55 << 0x4)); + { uint64_t x69 = (x68 + (x55 << 0x1)); + { uint64_t x70 = (x69 + x55); + { uint64_t x71 = (x44 + (x54 << 0x4)); + { uint64_t x72 = (x71 + (x54 << 0x1)); + { uint64_t x73 = (x72 + x54); + { uint64_t x74 = (x43 + (x53 << 0x4)); + { uint64_t x75 = (x74 + (x53 << 0x1)); + { uint64_t x76 = (x75 + x53); + { uint64_t x77 = (x42 + (x52 << 0x4)); + { uint64_t x78 = (x77 + (x52 << 0x1)); + { uint64_t x79 = (x78 + x52); + { uint64_t x80 = (x41 + (x51 << 0x4)); + { uint64_t x81 = (x80 + (x51 << 0x1)); + { uint64_t x82 = (x81 + x51); + { uint64_t x83 = (x40 + (x50 << 0x4)); + { uint64_t x84 = (x83 + (x50 << 0x1)); + { uint64_t x85 = (x84 + x50); + { uint64_t x86 = (x85 >> 0x1a); + { uint32_t x87 = ((uint32_t)x85 & 0x3ffffff); + { uint64_t x88 = (x86 + x82); + { uint64_t x89 = (x88 >> 0x19); + { uint32_t x90 = ((uint32_t)x88 & 0x1ffffff); + { uint64_t x91 = (x89 + x79); + { uint64_t x92 = (x91 >> 0x1a); + { uint32_t x93 = ((uint32_t)x91 & 0x3ffffff); + { uint64_t x94 = (x92 + x76); + { uint64_t x95 = (x94 >> 0x19); + { uint32_t x96 = ((uint32_t)x94 & 0x1ffffff); + { uint64_t x97 = (x95 + x73); + { uint64_t x98 = (x97 >> 0x1a); + { uint32_t x99 = ((uint32_t)x97 & 0x3ffffff); + { uint64_t x100 = (x98 + x70); + { uint64_t x101 = (x100 >> 0x19); + { uint32_t x102 = ((uint32_t)x100 & 0x1ffffff); + { uint64_t x103 = (x101 + x67); + { uint64_t x104 = (x103 >> 0x1a); + { uint32_t x105 = ((uint32_t)x103 & 0x3ffffff); + { uint64_t x106 = (x104 + x64); + { uint64_t x107 = (x106 >> 0x19); + { uint32_t x108 = ((uint32_t)x106 & 0x1ffffff); + { uint64_t x109 = (x107 + x61); + { uint64_t x110 = (x109 >> 0x1a); + { uint32_t x111 = ((uint32_t)x109 & 0x3ffffff); + { uint64_t x112 = (x110 + x49); + { uint64_t x113 = (x112 >> 0x19); + { uint32_t x114 = ((uint32_t)x112 & 0x1ffffff); + { uint64_t x115 = (x87 + (0x13 * x113)); + { uint32_t x116 = (uint32_t) (x115 >> 0x1a); + { uint32_t x117 = ((uint32_t)x115 & 0x3ffffff); + { uint32_t x118 = (x116 + x90); + { uint32_t x119 = (x118 >> 0x19); + { uint32_t x120 = (x118 & 0x1ffffff); + out[0] = x117; + out[1] = x120; + out[2] = (x119 + x93); + out[3] = x96; + out[4] = x99; + out[5] = x102; + out[6] = x105; + out[7] = x108; + out[8] = x111; + out[9] = x114; + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} + assert_fe(out); +} + +static void fe_mul_ltt(fe_loose *h, const fe *f, const fe *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_llt(fe_loose *h, const fe_loose *f, const fe *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_ttt(fe *h, const fe *f, const fe *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_tlt(fe *h, const fe_loose *f, const fe *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_ttl(fe *h, const fe *f, const fe_loose *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_mul_tll(fe *h, const fe_loose *f, const fe_loose *g) { + fe_mul_impl(h->v, f->v, g->v); +} + +static void fe_sqr_impl(uint32_t out[10], const uint32_t in1[10]) { + assert_fe_loose(in1); + { const uint32_t x17 = in1[9]; + { const uint32_t x18 = in1[8]; + { const uint32_t x16 = in1[7]; + { const uint32_t x14 = in1[6]; + { const uint32_t x12 = in1[5]; + { const uint32_t x10 = in1[4]; + { const uint32_t x8 = in1[3]; + { const uint32_t x6 = in1[2]; + { const uint32_t x4 = in1[1]; + { const uint32_t x2 = in1[0]; + { uint64_t x19 = ((uint64_t)x2 * x2); + { uint64_t x20 = ((uint64_t)(0x2 * x2) * x4); + { uint64_t x21 = (0x2 * (((uint64_t)x4 * x4) + ((uint64_t)x2 * x6))); + { uint64_t x22 = (0x2 * (((uint64_t)x4 * x6) + ((uint64_t)x2 * x8))); + { uint64_t x23 = ((((uint64_t)x6 * x6) + ((uint64_t)(0x4 * x4) * x8)) + ((uint64_t)(0x2 * x2) * x10)); + { uint64_t x24 = (0x2 * ((((uint64_t)x6 * x8) + ((uint64_t)x4 * x10)) + ((uint64_t)x2 * x12))); + { uint64_t x25 = (0x2 * (((((uint64_t)x8 * x8) + ((uint64_t)x6 * x10)) + ((uint64_t)x2 * x14)) + ((uint64_t)(0x2 * x4) * x12))); + { uint64_t x26 = (0x2 * (((((uint64_t)x8 * x10) + ((uint64_t)x6 * x12)) + ((uint64_t)x4 * x14)) + ((uint64_t)x2 * x16))); + { uint64_t x27 = (((uint64_t)x10 * x10) + (0x2 * ((((uint64_t)x6 * x14) + ((uint64_t)x2 * x18)) + (0x2 * (((uint64_t)x4 * x16) + ((uint64_t)x8 * x12)))))); + { uint64_t x28 = (0x2 * ((((((uint64_t)x10 * x12) + ((uint64_t)x8 * x14)) + ((uint64_t)x6 * x16)) + ((uint64_t)x4 * x18)) + ((uint64_t)x2 * x17))); + { uint64_t x29 = (0x2 * (((((uint64_t)x12 * x12) + ((uint64_t)x10 * x14)) + ((uint64_t)x6 * x18)) + (0x2 * (((uint64_t)x8 * x16) + ((uint64_t)x4 * x17))))); + { uint64_t x30 = (0x2 * (((((uint64_t)x12 * x14) + ((uint64_t)x10 * x16)) + ((uint64_t)x8 * x18)) + ((uint64_t)x6 * x17))); + { uint64_t x31 = (((uint64_t)x14 * x14) + (0x2 * (((uint64_t)x10 * x18) + (0x2 * (((uint64_t)x12 * x16) + ((uint64_t)x8 * x17)))))); + { uint64_t x32 = (0x2 * ((((uint64_t)x14 * x16) + ((uint64_t)x12 * x18)) + ((uint64_t)x10 * x17))); + { uint64_t x33 = (0x2 * ((((uint64_t)x16 * x16) + ((uint64_t)x14 * x18)) + ((uint64_t)(0x2 * x12) * x17))); + { uint64_t x34 = (0x2 * (((uint64_t)x16 * x18) + ((uint64_t)x14 * x17))); + { uint64_t x35 = (((uint64_t)x18 * x18) + ((uint64_t)(0x4 * x16) * x17)); + { uint64_t x36 = ((uint64_t)(0x2 * x18) * x17); + { uint64_t x37 = ((uint64_t)(0x2 * x17) * x17); + { uint64_t x38 = (x27 + (x37 << 0x4)); + { uint64_t x39 = (x38 + (x37 << 0x1)); + { uint64_t x40 = (x39 + x37); + { uint64_t x41 = (x26 + (x36 << 0x4)); + { uint64_t x42 = (x41 + (x36 << 0x1)); + { uint64_t x43 = (x42 + x36); + { uint64_t x44 = (x25 + (x35 << 0x4)); + { uint64_t x45 = (x44 + (x35 << 0x1)); + { uint64_t x46 = (x45 + x35); + { uint64_t x47 = (x24 + (x34 << 0x4)); + { uint64_t x48 = (x47 + (x34 << 0x1)); + { uint64_t x49 = (x48 + x34); + { uint64_t x50 = (x23 + (x33 << 0x4)); + { uint64_t x51 = (x50 + (x33 << 0x1)); + { uint64_t x52 = (x51 + x33); + { uint64_t x53 = (x22 + (x32 << 0x4)); + { uint64_t x54 = (x53 + (x32 << 0x1)); + { uint64_t x55 = (x54 + x32); + { uint64_t x56 = (x21 + (x31 << 0x4)); + { uint64_t x57 = (x56 + (x31 << 0x1)); + { uint64_t x58 = (x57 + x31); + { uint64_t x59 = (x20 + (x30 << 0x4)); + { uint64_t x60 = (x59 + (x30 << 0x1)); + { uint64_t x61 = (x60 + x30); + { uint64_t x62 = (x19 + (x29 << 0x4)); + { uint64_t x63 = (x62 + (x29 << 0x1)); + { uint64_t x64 = (x63 + x29); + { uint64_t x65 = (x64 >> 0x1a); + { uint32_t x66 = ((uint32_t)x64 & 0x3ffffff); + { uint64_t x67 = (x65 + x61); + { uint64_t x68 = (x67 >> 0x19); + { uint32_t x69 = ((uint32_t)x67 & 0x1ffffff); + { uint64_t x70 = (x68 + x58); + { uint64_t x71 = (x70 >> 0x1a); + { uint32_t x72 = ((uint32_t)x70 & 0x3ffffff); + { uint64_t x73 = (x71 + x55); + { uint64_t x74 = (x73 >> 0x19); + { uint32_t x75 = ((uint32_t)x73 & 0x1ffffff); + { uint64_t x76 = (x74 + x52); + { uint64_t x77 = (x76 >> 0x1a); + { uint32_t x78 = ((uint32_t)x76 & 0x3ffffff); + { uint64_t x79 = (x77 + x49); + { uint64_t x80 = (x79 >> 0x19); + { uint32_t x81 = ((uint32_t)x79 & 0x1ffffff); + { uint64_t x82 = (x80 + x46); + { uint64_t x83 = (x82 >> 0x1a); + { uint32_t x84 = ((uint32_t)x82 & 0x3ffffff); + { uint64_t x85 = (x83 + x43); + { uint64_t x86 = (x85 >> 0x19); + { uint32_t x87 = ((uint32_t)x85 & 0x1ffffff); + { uint64_t x88 = (x86 + x40); + { uint64_t x89 = (x88 >> 0x1a); + { uint32_t x90 = ((uint32_t)x88 & 0x3ffffff); + { uint64_t x91 = (x89 + x28); + { uint64_t x92 = (x91 >> 0x19); + { uint32_t x93 = ((uint32_t)x91 & 0x1ffffff); + { uint64_t x94 = (x66 + (0x13 * x92)); + { uint32_t x95 = (uint32_t) (x94 >> 0x1a); + { uint32_t x96 = ((uint32_t)x94 & 0x3ffffff); + { uint32_t x97 = (x95 + x69); + { uint32_t x98 = (x97 >> 0x19); + { uint32_t x99 = (x97 & 0x1ffffff); + out[0] = x96; + out[1] = x99; + out[2] = (x98 + x72); + out[3] = x75; + out[4] = x78; + out[5] = x81; + out[6] = x84; + out[7] = x87; + out[8] = x90; + out[9] = x93; + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} + assert_fe(out); +} + +static void fe_sq_tl(fe *h, const fe_loose *f) { + fe_sqr_impl(h->v, f->v); +} + +static void fe_sq_tt(fe *h, const fe *f) { + fe_sqr_impl(h->v, f->v); +} + +// Adapted from Fiat-synthesized |fe_sub_impl| with |out| = 0. +static void fe_neg_impl(uint32_t out[10], const uint32_t in2[10]) { + { const uint32_t x20 = 0; + { const uint32_t x21 = 0; + { const uint32_t x19 = 0; + { const uint32_t x17 = 0; + { const uint32_t x15 = 0; + { const uint32_t x13 = 0; + { const uint32_t x11 = 0; + { const uint32_t x9 = 0; + { const uint32_t x7 = 0; + { const uint32_t x5 = 0; + { const uint32_t x38 = in2[9]; + { const uint32_t x39 = in2[8]; + { const uint32_t x37 = in2[7]; + { const uint32_t x35 = in2[6]; + { const uint32_t x33 = in2[5]; + { const uint32_t x31 = in2[4]; + { const uint32_t x29 = in2[3]; + { const uint32_t x27 = in2[2]; + { const uint32_t x25 = in2[1]; + { const uint32_t x23 = in2[0]; + out[0] = ((0x7ffffda + x5) - x23); + out[1] = ((0x3fffffe + x7) - x25); + out[2] = ((0x7fffffe + x9) - x27); + out[3] = ((0x3fffffe + x11) - x29); + out[4] = ((0x7fffffe + x13) - x31); + out[5] = ((0x3fffffe + x15) - x33); + out[6] = ((0x7fffffe + x17) - x35); + out[7] = ((0x3fffffe + x19) - x37); + out[8] = ((0x7fffffe + x21) - x39); + out[9] = ((0x3fffffe + x20) - x38); + }}}}}}}}}}}}}}}}}}}} +} + +// h = -f +static void fe_neg(fe_loose *h, const fe *f) { + assert_fe(f->v); + fe_neg_impl(h->v, f->v); + assert_fe_loose(h->v); +} + +// 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_loose *f, const fe_loose *g, unsigned b) { + b = 0-b; + unsigned i; + for (i = 0; i < 10; i++) { + uint32_t x = f->v[i] ^ g->v[i]; + x &= b; + f->v[i] ^= x; + } +} + +#endif // BORINGSSL_CURVE25519_64BIT + +// h = f +static void fe_copy(fe *h, const fe *f) { + memmove(h, f, sizeof(fe)); +} + +static void fe_copy_lt(fe_loose *h, const fe *f) { +#ifdef EDWARDS25519_ASSERTS + assert(sizeof(fe_loose) == sizeof(fe)); +#endif + memmove(h, f, sizeof(fe)); +} +#if !defined(CONFIG_SMALL) +static void fe_copy_ll(fe_loose *h, const fe_loose *f) { + memmove(h, f, sizeof(fe_loose)); +} +#endif // !defined(CONFIG_SMALL) + +static void fe_loose_invert(fe *out, const fe_loose *z) { + fe t0; + fe t1; + fe t2; + fe t3; + int i; + + fe_sq_tl(&t0, z); + fe_sq_tt(&t1, &t0); + for (i = 1; i < 2; ++i) { + fe_sq_tt(&t1, &t1); + } + fe_mul_tlt(&t1, z, &t1); + fe_mul_ttt(&t0, &t0, &t1); + fe_sq_tt(&t2, &t0); + fe_mul_ttt(&t1, &t1, &t2); + fe_sq_tt(&t2, &t1); + for (i = 1; i < 5; ++i) { + fe_sq_tt(&t2, &t2); + } + fe_mul_ttt(&t1, &t2, &t1); + fe_sq_tt(&t2, &t1); + for (i = 1; i < 10; ++i) { + fe_sq_tt(&t2, &t2); + } + fe_mul_ttt(&t2, &t2, &t1); + fe_sq_tt(&t3, &t2); + for (i = 1; i < 20; ++i) { + fe_sq_tt(&t3, &t3); + } + fe_mul_ttt(&t2, &t3, &t2); + fe_sq_tt(&t2, &t2); + for (i = 1; i < 10; ++i) { + fe_sq_tt(&t2, &t2); + } + fe_mul_ttt(&t1, &t2, &t1); + fe_sq_tt(&t2, &t1); + for (i = 1; i < 50; ++i) { + fe_sq_tt(&t2, &t2); + } + fe_mul_ttt(&t2, &t2, &t1); + fe_sq_tt(&t3, &t2); + for (i = 1; i < 100; ++i) { + fe_sq_tt(&t3, &t3); + } + fe_mul_ttt(&t2, &t3, &t2); + fe_sq_tt(&t2, &t2); + for (i = 1; i < 50; ++i) { + fe_sq_tt(&t2, &t2); + } + fe_mul_ttt(&t1, &t2, &t1); + fe_sq_tt(&t1, &t1); + for (i = 1; i < 5; ++i) { + fe_sq_tt(&t1, &t1); + } + fe_mul_ttt(out, &t1, &t0); +} + +static void fe_invert(fe *out, const fe *z) { + fe_loose l; + fe_copy_lt(&l, z); + fe_loose_invert(out, &l); +} + +// return 0 if f == 0 +// return 1 if f != 0 +static int fe_isnonzero(const fe_loose *f) { + fe tight; + fe_carry(&tight, f); + uint8_t s[32]; + fe_tobytes(s, &tight); + + static const uint8_t zero[32] = {0}; + return k5_bcmp(s, zero, sizeof(zero)) != 0; +} + +// return 1 if f is in {1,3,5,...,q-2} +// return 0 if f is in {0,2,4,...,q-1} +static int fe_isnegative(const fe *f) { + uint8_t s[32]; + fe_tobytes(s, f); + return s[0] & 1; +} + +static void fe_sq2_tt(fe *h, const fe *f) { + // h = f^2 + fe_sq_tt(h, f); + + // h = h + h + fe_loose tmp; + fe_add(&tmp, h, h); + fe_carry(h, &tmp); +} + +static void fe_pow22523(fe *out, const fe *z) { + fe t0; + fe t1; + fe t2; + int i; + + fe_sq_tt(&t0, z); + fe_sq_tt(&t1, &t0); + for (i = 1; i < 2; ++i) { + fe_sq_tt(&t1, &t1); + } + fe_mul_ttt(&t1, z, &t1); + fe_mul_ttt(&t0, &t0, &t1); + fe_sq_tt(&t0, &t0); + fe_mul_ttt(&t0, &t1, &t0); + fe_sq_tt(&t1, &t0); + for (i = 1; i < 5; ++i) { + fe_sq_tt(&t1, &t1); + } + fe_mul_ttt(&t0, &t1, &t0); + fe_sq_tt(&t1, &t0); + for (i = 1; i < 10; ++i) { + fe_sq_tt(&t1, &t1); + } + fe_mul_ttt(&t1, &t1, &t0); + fe_sq_tt(&t2, &t1); + for (i = 1; i < 20; ++i) { + fe_sq_tt(&t2, &t2); + } + fe_mul_ttt(&t1, &t2, &t1); + fe_sq_tt(&t1, &t1); + for (i = 1; i < 10; ++i) { + fe_sq_tt(&t1, &t1); + } + fe_mul_ttt(&t0, &t1, &t0); + fe_sq_tt(&t1, &t0); + for (i = 1; i < 50; ++i) { + fe_sq_tt(&t1, &t1); + } + fe_mul_ttt(&t1, &t1, &t0); + fe_sq_tt(&t2, &t1); + for (i = 1; i < 100; ++i) { + fe_sq_tt(&t2, &t2); + } + fe_mul_ttt(&t1, &t2, &t1); + fe_sq_tt(&t1, &t1); + for (i = 1; i < 50; ++i) { + fe_sq_tt(&t1, &t1); + } + fe_mul_ttt(&t0, &t1, &t0); + fe_sq_tt(&t0, &t0); + for (i = 1; i < 2; ++i) { + fe_sq_tt(&t0, &t0); + } + fe_mul_ttt(out, &t0, z); +} + + +// Group operations. + +static void x25519_ge_tobytes(uint8_t s[32], const ge_p2 *h) { + fe recip; + fe x; + fe y; + + fe_invert(&recip, &h->Z); + fe_mul_ttt(&x, &h->X, &recip); + fe_mul_ttt(&y, &h->Y, &recip); + fe_tobytes(s, &y); + s[31] ^= fe_isnegative(&x) << 7; +} + +static int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s) { + fe u; + fe_loose v; + fe v3; + fe vxx; + fe_loose check; + + fe_frombytes(&h->Y, s); + fe_1(&h->Z); + fe_sq_tt(&v3, &h->Y); + fe_mul_ttt(&vxx, &v3, &d); + fe_sub(&v, &v3, &h->Z); // u = y^2-1 + fe_carry(&u, &v); + fe_add(&v, &vxx, &h->Z); // v = dy^2+1 + + fe_sq_tl(&v3, &v); + fe_mul_ttl(&v3, &v3, &v); // v3 = v^3 + fe_sq_tt(&h->X, &v3); + fe_mul_ttl(&h->X, &h->X, &v); + fe_mul_ttt(&h->X, &h->X, &u); // x = uv^7 + + fe_pow22523(&h->X, &h->X); // x = (uv^7)^((q-5)/8) + fe_mul_ttt(&h->X, &h->X, &v3); + fe_mul_ttt(&h->X, &h->X, &u); // x = uv^3(uv^7)^((q-5)/8) + + fe_sq_tt(&vxx, &h->X); + fe_mul_ttl(&vxx, &vxx, &v); + fe_sub(&check, &vxx, &u); + if (fe_isnonzero(&check)) { + fe_add(&check, &vxx, &u); + if (fe_isnonzero(&check)) { + return -1; + } + fe_mul_ttt(&h->X, &h->X, &sqrtm1); + } + + if (fe_isnegative(&h->X) != (s[31] >> 7)) { + fe_loose t; + fe_neg(&t, &h->X); + fe_carry(&h->X, &t); + } + + fe_mul_ttt(&h->T, &h->X, &h->Y); + return 0; +} + +static void ge_p2_0(ge_p2 *h) { + fe_0(&h->X); + fe_1(&h->Y); + fe_1(&h->Z); +} + +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_cached_0(ge_cached *h) { + fe_loose_1(&h->YplusX); + fe_loose_1(&h->YminusX); + fe_loose_1(&h->Z); + fe_loose_0(&h->T2d); +} + +static void ge_precomp_0(ge_precomp *h) { + fe_loose_1(&h->yplusx); + fe_loose_1(&h->yminusx); + fe_loose_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); +} + +// r = p +static void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p) { + fe_add(&r->YplusX, &p->Y, &p->X); + fe_sub(&r->YminusX, &p->Y, &p->X); + fe_copy_lt(&r->Z, &p->Z); + fe_mul_ltt(&r->T2d, &p->T, &d2); +} + +// r = p +static void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) { + fe_mul_tll(&r->X, &p->X, &p->T); + fe_mul_tll(&r->Y, &p->Y, &p->Z); + fe_mul_tll(&r->Z, &p->Z, &p->T); +} + +// r = p +static void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) { + fe_mul_tll(&r->X, &p->X, &p->T); + fe_mul_tll(&r->Y, &p->Y, &p->Z); + fe_mul_tll(&r->Z, &p->Z, &p->T); + fe_mul_tll(&r->T, &p->X, &p->Y); +} + +// r = p +static void ge_p1p1_to_cached(ge_cached *r, const ge_p1p1 *p) { + ge_p3 t; + x25519_ge_p1p1_to_p3(&t, p); + x25519_ge_p3_to_cached(r, &t); +} + +// r = 2 * p +static void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) { + fe trX, trZ, trT; + fe t0; + + fe_sq_tt(&trX, &p->X); + fe_sq_tt(&trZ, &p->Y); + fe_sq2_tt(&trT, &p->Z); + fe_add(&r->Y, &p->X, &p->Y); + fe_sq_tl(&t0, &r->Y); + + fe_add(&r->Y, &trZ, &trX); + fe_sub(&r->Z, &trZ, &trX); + fe_carry(&trZ, &r->Y); + fe_sub(&r->X, &t0, &trZ); + fe_carry(&trZ, &r->Z); + fe_sub(&r->T, &trT, &trZ); +} + +#ifndef CONFIG_SMALL +// 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); +} +#endif + +// r = p + q +static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { + fe trY, trZ, trT; + + fe_add(&r->X, &p->Y, &p->X); + fe_sub(&r->Y, &p->Y, &p->X); + fe_mul_tll(&trZ, &r->X, &q->yplusx); + fe_mul_tll(&trY, &r->Y, &q->yminusx); + fe_mul_tlt(&trT, &q->xy2d, &p->T); + fe_add(&r->T, &p->Z, &p->Z); + fe_sub(&r->X, &trZ, &trY); + fe_add(&r->Y, &trZ, &trY); + fe_carry(&trZ, &r->T); + fe_add(&r->Z, &trZ, &trT); + fe_sub(&r->T, &trZ, &trT); +} + +// r = p + q +static void x25519_ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { + fe trX, trY, trZ, trT; + + fe_add(&r->X, &p->Y, &p->X); + fe_sub(&r->Y, &p->Y, &p->X); + fe_mul_tll(&trZ, &r->X, &q->YplusX); + fe_mul_tll(&trY, &r->Y, &q->YminusX); + fe_mul_tlt(&trT, &q->T2d, &p->T); + fe_mul_ttl(&trX, &p->Z, &q->Z); + fe_add(&r->T, &trX, &trX); + fe_sub(&r->X, &trZ, &trY); + fe_add(&r->Y, &trZ, &trY); + fe_carry(&trZ, &r->T); + fe_add(&r->Z, &trZ, &trT); + fe_sub(&r->T, &trZ, &trT); +} + +// r = p - q +static void x25519_ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { + fe trX, trY, trZ, trT; + + fe_add(&r->X, &p->Y, &p->X); + fe_sub(&r->Y, &p->Y, &p->X); + fe_mul_tll(&trZ, &r->X, &q->YminusX); + fe_mul_tll(&trY, &r->Y, &q->YplusX); + fe_mul_tlt(&trT, &q->T2d, &p->T); + fe_mul_ttl(&trX, &p->Z, &q->Z); + fe_add(&r->T, &trX, &trX); + fe_sub(&r->X, &trZ, &trY); + fe_add(&r->Y, &trZ, &trY); + fe_carry(&trZ, &r->T); + fe_sub(&r->Z, &trZ, &trT); + fe_add(&r->T, &trZ, &trT); +} + +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, const 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); +} + +static void x25519_ge_scalarmult_small_precomp( + ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]) { + // precomp_table is first expanded into matching |ge_precomp| + // elements. + ge_precomp multiples[15]; + + unsigned i; + for (i = 0; i < 15; i++) { + const uint8_t *bytes = &precomp_table[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_ltt(&out->xy2d, &x, &y); + fe_mul_llt(&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; + x25519_ge_p3_to_cached(&cached, h); + x25519_ge_add(&r, h, &cached); + x25519_ge_p1p1_to_p3(h, &r); + + ge_madd(&r, h, &e); + x25519_ge_p1p1_to_p3(h, &r); + } +} + +#if defined(CONFIG_SMALL) + +static void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]) { + x25519_ge_scalarmult_small_precomp(h, a, k25519SmallPrecomp); +} + +#else + +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 - ((uint8_t)((-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_ll(&minust.yplusx, &t->yminusx); + fe_copy_ll(&minust.yminusx, &t->yplusx); + + // NOTE: the input table is canonical, but types don't encode it + fe tmp; + fe_carry(&tmp, &t->xy2d); + fe_neg(&minust.xy2d, &tmp); + + 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 x25519_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); + x25519_ge_p1p1_to_p3(h, &r); + } + + ge_p3_dbl(&r, h); + x25519_ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + x25519_ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + x25519_ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + x25519_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); + x25519_ge_p1p1_to_p3(h, &r); + } +} + +#endif + +static void cmov_cached(ge_cached *t, ge_cached *u, uint8_t b) { + fe_cmov(&t->YplusX, &u->YplusX, b); + fe_cmov(&t->YminusX, &u->YminusX, b); + fe_cmov(&t->Z, &u->Z, b); + fe_cmov(&t->T2d, &u->T2d, b); +} + +// r = scalar * A. +// where a = a[0]+256*a[1]+...+256^31 a[31]. +static void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar, + const ge_p3 *A) { + ge_p2 Ai_p2[8]; + ge_cached Ai[16]; + ge_p1p1 t; + + ge_cached_0(&Ai[0]); + x25519_ge_p3_to_cached(&Ai[1], A); + ge_p3_to_p2(&Ai_p2[1], A); + + unsigned i; + for (i = 2; i < 16; i += 2) { + ge_p2_dbl(&t, &Ai_p2[i / 2]); + ge_p1p1_to_cached(&Ai[i], &t); + if (i < 8) { + x25519_ge_p1p1_to_p2(&Ai_p2[i], &t); + } + x25519_ge_add(&t, A, &Ai[i]); + ge_p1p1_to_cached(&Ai[i + 1], &t); + if (i < 7) { + x25519_ge_p1p1_to_p2(&Ai_p2[i + 1], &t); + } + } + + ge_p2_0(r); + ge_p3 u; + + for (i = 0; i < 256; i += 4) { + ge_p2_dbl(&t, r); + x25519_ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + x25519_ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + x25519_ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + x25519_ge_p1p1_to_p3(&u, &t); + + uint8_t index = scalar[31 - i/8]; + index >>= 4 - (i & 4); + index &= 0xf; + + unsigned j; + ge_cached selected; + ge_cached_0(&selected); + for (j = 0; j < 16; j++) { + cmov_cached(&selected, &Ai[j], equal(j, index)); + } + + x25519_ge_add(&t, &u, &selected); + x25519_ge_p1p1_to_p2(r, &t); + } +} + +// The set of scalars is \Z/l +// where l = 2^252 + 27742317777372353535851937790883648493. + +// Input: +// s[0]+256*s[1]+...+256^63*s[63] = s +// +// Output: +// s[0]+256*s[1]+...+256^31*s[31] = s mod l +// where l = 2^252 + 27742317777372353535851937790883648493. +// Overwrites s in place. +static void x25519_sc_reduce(uint8_t s[64]) { + int64_t s0 = 2097151 & load_3(s); + int64_t s1 = 2097151 & (load_4(s + 2) >> 5); + int64_t s2 = 2097151 & (load_3(s + 5) >> 2); + int64_t s3 = 2097151 & (load_4(s + 7) >> 7); + int64_t s4 = 2097151 & (load_4(s + 10) >> 4); + int64_t s5 = 2097151 & (load_3(s + 13) >> 1); + int64_t s6 = 2097151 & (load_4(s + 15) >> 6); + int64_t s7 = 2097151 & (load_3(s + 18) >> 3); + int64_t s8 = 2097151 & load_3(s + 21); + int64_t s9 = 2097151 & (load_4(s + 23) >> 5); + int64_t s10 = 2097151 & (load_3(s + 26) >> 2); + int64_t s11 = 2097151 & (load_4(s + 28) >> 7); + int64_t s12 = 2097151 & (load_4(s + 31) >> 4); + int64_t s13 = 2097151 & (load_3(s + 34) >> 1); + int64_t s14 = 2097151 & (load_4(s + 36) >> 6); + int64_t s15 = 2097151 & (load_3(s + 39) >> 3); + int64_t s16 = 2097151 & load_3(s + 42); + int64_t s17 = 2097151 & (load_4(s + 44) >> 5); + int64_t s18 = 2097151 & (load_3(s + 47) >> 2); + int64_t s19 = 2097151 & (load_4(s + 49) >> 7); + int64_t s20 = 2097151 & (load_4(s + 52) >> 4); + int64_t s21 = 2097151 & (load_3(s + 55) >> 1); + int64_t s22 = 2097151 & (load_4(s + 57) >> 6); + int64_t s23 = (load_4(s + 60) >> 3); + 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; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s23 = 0; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s22 = 0; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s21 = 0; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s20 = 0; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s19 = 0; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + s18 = 0; + + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; + s13 += carry12; + s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; + s15 += carry14; + s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; + s17 += carry16; + s16 -= carry16 << 21; + + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; + s14 += carry13; + s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; + s16 += carry15; + s15 -= carry15 << 21; + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s17 = 0; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s16 = 0; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s15 = 0; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s14 = 0; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s13 = 0; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 << 21; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* Loosely from BoringSSL crypto/curve25519/spake25519.c */ + +/* + * Here BoringSSL uses different points, not restricted to the generator + * subgroup, while we use the draft-irtf-cfrg-spake2-05 points. The Python + * code is modified to add the subgroup restriction. + */ + +// The following precomputation tables are for the following +// points: +// +// N (found in 7 iterations): +// x: 10742253510813957597047979962966927467575235974254765187031601461055699024931 +// y: 19796686047937480651099107989427797822652529149428697746066532921705571401683 +// encoded: d3bfb518f44f3430f29d0c92af503865a1ed3281dc69b35dd868ba85f886c4ab +// +// M (found in 21 iterations): +// x: 8158688967149231307266666683326742915289288280191350817196911733632187385319 +// y: 21622333750659878624441478467798461427617029906629724657331223068277098105040 +// encoded: d048032c6ea0b6d697ddc2e86bda85a33adac920f1bf18e1b0c6d166a5cecdaf +// +// These points and their precomputation tables are generated with the +// following Python code. + +/* +import hashlib +import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py + +SEED_N = 'edwards25519 point generation seed (N)' +SEED_M = 'edwards25519 point generation seed (M)' + +def genpoint(seed): + v = hashlib.sha256(seed).digest() + it = 1 + while True: + try: + x,y = E.decodepoint(v) + if E.scalarmult((x,y), E.l) != [0, 1]: + raise Exception('point has wrong order') + except Exception, e: + print e + it += 1 + v = hashlib.sha256(v).digest() + continue + print "Found in %d iterations:" % it + print " x = %d" % x + print " y = %d" % y + print " Encoded (hex)" + print E.encodepoint((x,y)).encode('hex') + return (x,y) + +def gentable(P): + t = [] + for i in range(1,16): + k = (i >> 3 & 1) * (1 << 192) + \ + (i >> 2 & 1) * (1 << 128) + \ + (i >> 1 & 1) * (1 << 64) + \ + (i & 1) + t.append(E.scalarmult(P, k)) + return ''.join(E.encodeint(x) + E.encodeint(y) for (x,y) in t) + +def printtable(table, name): + print "static const uint8_t %s[15 * 2 * 32] = {" % name, + for i in range(15 * 2 * 32): + if i % 12 == 0: + print "\n ", + print " 0x%02x," % ord(table[i]), + print "\n};" + +if __name__ == "__main__": + print "Searching for N" + N = genpoint(SEED_N) + print "Generating precomputation table for N" + Ntable = gentable(N) + printtable(Ntable, "kSpakeNSmallPrecomp") + + print "Searching for M" + M = genpoint(SEED_M) + print "Generating precomputation table for M" + Mtable = gentable(M) + printtable(Mtable, "kSpakeMSmallPrecomp") +*/ + +static const uint8_t kSpakeNSmallPrecomp[15 * 2 * 32] = { + 0x23, 0xfc, 0x27, 0x6c, 0x55, 0xaf, 0xb3, 0x9c, 0xd8, 0x99, 0x3a, 0x0d, + 0x7f, 0x08, 0xc9, 0xeb, 0x4d, 0x6e, 0x90, 0x99, 0x2f, 0x3c, 0x15, 0x2b, + 0x89, 0x5a, 0x0f, 0xf2, 0x67, 0xe6, 0xbf, 0x17, 0xd3, 0xbf, 0xb5, 0x18, + 0xf4, 0x4f, 0x34, 0x30, 0xf2, 0x9d, 0x0c, 0x92, 0xaf, 0x50, 0x38, 0x65, + 0xa1, 0xed, 0x32, 0x81, 0xdc, 0x69, 0xb3, 0x5d, 0xd8, 0x68, 0xba, 0x85, + 0xf8, 0x86, 0xc4, 0x2b, 0x53, 0x93, 0xb1, 0x99, 0x90, 0x30, 0xca, 0xb0, + 0xbd, 0xea, 0x14, 0x4c, 0x6f, 0x2b, 0x81, 0x1e, 0x23, 0x45, 0xb2, 0x32, + 0x2e, 0x2d, 0xe6, 0xb8, 0x5d, 0xc5, 0x15, 0x91, 0x63, 0x39, 0x18, 0x5b, + 0x62, 0x63, 0x9b, 0xf4, 0x8b, 0xe0, 0x34, 0xa2, 0x95, 0x11, 0x92, 0x68, + 0x54, 0xb7, 0xf3, 0x91, 0xca, 0x22, 0xad, 0x08, 0xd8, 0x9c, 0xa2, 0xf0, + 0xdc, 0x9c, 0x2c, 0x84, 0x32, 0x26, 0xe0, 0x17, 0x89, 0x53, 0x6b, 0xfd, + 0x76, 0x97, 0x25, 0xea, 0x99, 0x94, 0xf8, 0x29, 0x7c, 0xc4, 0x53, 0xc0, + 0x98, 0x9a, 0x20, 0xdc, 0x70, 0x01, 0x50, 0xaa, 0x05, 0xa3, 0x40, 0x50, + 0x66, 0x87, 0x30, 0x19, 0x12, 0xc3, 0xb8, 0x2d, 0x28, 0x8b, 0x7b, 0x48, + 0xf7, 0x7b, 0xab, 0x45, 0x70, 0x2e, 0xbb, 0x85, 0xc1, 0x6c, 0xdd, 0x35, + 0x00, 0x83, 0x20, 0x13, 0x82, 0x08, 0xaa, 0xa3, 0x03, 0x0f, 0xca, 0x27, + 0x3e, 0x8b, 0x52, 0xc2, 0xd7, 0xb1, 0x8c, 0x22, 0xfe, 0x04, 0x4a, 0xf2, + 0xe8, 0xac, 0xee, 0x2e, 0xd7, 0x77, 0x34, 0x49, 0xf2, 0xe9, 0xeb, 0x8c, + 0xa6, 0xc8, 0xc6, 0xcd, 0x8a, 0x8f, 0x7c, 0x5d, 0x51, 0xc8, 0xfa, 0x6f, + 0xb3, 0x93, 0xdb, 0x71, 0xef, 0x3e, 0x6e, 0xa7, 0x85, 0xc7, 0xd4, 0x3e, + 0xa2, 0xe2, 0xc0, 0xaa, 0x17, 0xb3, 0xa4, 0x7c, 0xc2, 0x3f, 0x7c, 0x7a, + 0xdd, 0x26, 0xde, 0x3e, 0xf1, 0x99, 0x06, 0xf7, 0x69, 0x1b, 0xc9, 0x20, + 0x55, 0x4f, 0x86, 0x7a, 0x93, 0x89, 0x68, 0xe9, 0x2b, 0x2d, 0xbc, 0x08, + 0x15, 0x5d, 0x2d, 0x0b, 0x4f, 0x1a, 0xb3, 0xd4, 0x8e, 0x77, 0x79, 0x2a, + 0x25, 0xf9, 0xb6, 0x46, 0xfb, 0x87, 0x02, 0xa6, 0xe0, 0xd3, 0xba, 0x84, + 0xea, 0x3e, 0x58, 0xa5, 0x7f, 0x8f, 0x8c, 0x39, 0x79, 0x28, 0xb5, 0xcf, + 0xe4, 0xca, 0x63, 0xdc, 0xac, 0xed, 0x4b, 0x74, 0x1e, 0x94, 0x85, 0x8c, + 0xe5, 0xf4, 0x76, 0x6f, 0x20, 0x67, 0x8b, 0xd8, 0xd6, 0x4b, 0xe7, 0x2d, + 0xa0, 0xbd, 0xcc, 0x1f, 0xdf, 0x46, 0x9c, 0xa2, 0x49, 0x64, 0xdf, 0x24, + 0x00, 0x11, 0x11, 0x45, 0x62, 0x5c, 0xd7, 0x8a, 0x00, 0x02, 0xf5, 0x9b, + 0x4f, 0x53, 0x42, 0xc5, 0xd5, 0x55, 0x80, 0x73, 0x9a, 0x5b, 0x31, 0x5a, + 0xbd, 0x3a, 0x43, 0xe9, 0x33, 0xe5, 0xaf, 0x1d, 0x92, 0x5e, 0x59, 0x37, + 0xae, 0x57, 0xfa, 0x3b, 0xd2, 0x31, 0xae, 0xa6, 0xf9, 0xc9, 0xc1, 0x82, + 0xa6, 0xa5, 0xed, 0x24, 0x53, 0x4b, 0x38, 0x22, 0xf2, 0x85, 0x8d, 0x13, + 0xa6, 0x5e, 0xd6, 0x57, 0x17, 0xd3, 0x33, 0x38, 0x8d, 0x65, 0xd3, 0xcb, + 0x1a, 0xa2, 0x3a, 0x2b, 0xbb, 0x61, 0x53, 0xd7, 0xff, 0xcd, 0x20, 0xb6, + 0xbb, 0x8c, 0xab, 0x63, 0xef, 0xb8, 0x26, 0x7e, 0x81, 0x65, 0xaf, 0x90, + 0xfc, 0xd2, 0xb6, 0x72, 0xdb, 0xe9, 0x23, 0x78, 0x12, 0x04, 0xc0, 0x03, + 0x82, 0xa8, 0x7a, 0x0f, 0x48, 0x6f, 0x82, 0x7f, 0x81, 0xcd, 0xa7, 0x89, + 0xdd, 0x86, 0xea, 0x5e, 0xa1, 0x50, 0x14, 0x34, 0x17, 0x64, 0x82, 0x0f, + 0xc4, 0x40, 0x20, 0x1d, 0x8f, 0xfe, 0xfa, 0x99, 0xaf, 0x5b, 0xc1, 0x5d, + 0xc8, 0x47, 0x07, 0x54, 0x4a, 0x22, 0x56, 0x57, 0xf1, 0x2c, 0x3b, 0x62, + 0x7f, 0x12, 0x62, 0xaf, 0xfd, 0xf8, 0x04, 0x11, 0xa8, 0x51, 0xf0, 0x46, + 0x5d, 0x79, 0x66, 0xff, 0x8a, 0x06, 0xef, 0x54, 0x64, 0x1b, 0x84, 0x3e, + 0x41, 0xf3, 0xfe, 0x19, 0x51, 0xf7, 0x44, 0x9c, 0x16, 0xd3, 0x7a, 0x09, + 0x59, 0xf5, 0x47, 0x45, 0xd0, 0x31, 0xef, 0x96, 0x2c, 0xc5, 0xc0, 0xd0, + 0x56, 0xef, 0x3f, 0x07, 0x2b, 0xb7, 0x28, 0x49, 0xf5, 0xb1, 0x42, 0x18, + 0xcf, 0x77, 0xd8, 0x2b, 0x71, 0x74, 0x80, 0xba, 0x34, 0x52, 0xce, 0x11, + 0xfe, 0xc4, 0xb9, 0xeb, 0xf9, 0xc4, 0x5e, 0x1f, 0xd3, 0xde, 0x4b, 0x14, + 0xe3, 0x6e, 0xe7, 0xd7, 0x83, 0x59, 0x98, 0xe8, 0x3d, 0x8e, 0xd6, 0x7d, + 0xc0, 0x9a, 0x79, 0xb9, 0x83, 0xf1, 0xc1, 0x00, 0x5d, 0x16, 0x1b, 0x44, + 0xe9, 0x02, 0xce, 0x99, 0x1e, 0x77, 0xef, 0xca, 0xbc, 0xf0, 0x6a, 0xb9, + 0x65, 0x3f, 0x3c, 0xd9, 0xe1, 0x63, 0x0b, 0xbf, 0xaa, 0xa7, 0xe6, 0x6d, + 0x6d, 0x3f, 0x44, 0x29, 0xa3, 0x8b, 0x6d, 0xc4, 0x81, 0xa9, 0xc3, 0x5a, + 0x90, 0x55, 0x72, 0x61, 0x17, 0x22, 0x7f, 0x3e, 0x5f, 0xfc, 0xba, 0xb3, + 0x7a, 0x99, 0x76, 0xe9, 0x20, 0xe5, 0xc5, 0xe8, 0x55, 0x56, 0x0f, 0x7a, + 0x48, 0xe7, 0xbc, 0xe1, 0x13, 0xf4, 0x90, 0xef, 0x97, 0x6c, 0x02, 0x89, + 0x4d, 0x22, 0x48, 0xda, 0xd3, 0x52, 0x45, 0x31, 0x26, 0xcc, 0xe8, 0x9e, + 0x5d, 0xdd, 0x75, 0xe4, 0x1d, 0xbc, 0xb1, 0x08, 0x55, 0xaf, 0x54, 0x70, + 0x0d, 0x0c, 0xf3, 0x50, 0xbc, 0x40, 0x83, 0xee, 0xdc, 0x6d, 0x8b, 0x40, + 0x79, 0x62, 0x18, 0x37, 0xc4, 0x78, 0x02, 0x58, 0x7c, 0x78, 0xd3, 0x54, + 0xed, 0x31, 0xbd, 0x7d, 0x48, 0xcf, 0xb6, 0x11, 0x27, 0x37, 0x9c, 0x86, + 0xf7, 0x2e, 0x00, 0x7a, 0x48, 0x1b, 0xa6, 0x72, 0x70, 0x7b, 0x44, 0x45, + 0xeb, 0x49, 0xbf, 0xbe, 0x09, 0x78, 0x66, 0x71, 0x12, 0x7f, 0x3d, 0x78, + 0x51, 0x24, 0x82, 0xa2, 0xf0, 0x1e, 0x83, 0x81, 0x81, 0x45, 0x53, 0xfd, + 0x5e, 0xf3, 0x03, 0x74, 0xbd, 0x23, 0x35, 0xf6, 0x10, 0xdd, 0x7c, 0x73, + 0x46, 0x32, 0x09, 0x54, 0x99, 0x95, 0x91, 0x25, 0xb8, 0x32, 0x09, 0xd8, + 0x2f, 0x97, 0x50, 0xa3, 0xf5, 0xd6, 0xb1, 0xed, 0x97, 0x51, 0x06, 0x42, + 0x12, 0x0c, 0x69, 0x38, 0x09, 0xa0, 0xd8, 0x19, 0x70, 0xf7, 0x8f, 0x61, + 0x0d, 0x56, 0x43, 0x66, 0x22, 0x8b, 0x0e, 0x0e, 0xf9, 0x81, 0x9f, 0xac, + 0x6f, 0xbf, 0x7d, 0x04, 0x13, 0xf2, 0xe4, 0xeb, 0xfd, 0xbe, 0x4e, 0x56, + 0xda, 0xe0, 0x22, 0x6d, 0x1b, 0x25, 0xc8, 0xa5, 0x9c, 0x05, 0x45, 0x52, + 0x3c, 0x3a, 0xde, 0x6b, 0xac, 0x9b, 0xf8, 0x81, 0x97, 0x21, 0x46, 0xac, + 0x7e, 0x89, 0xf8, 0x49, 0x58, 0xbb, 0x45, 0xac, 0xa2, 0xc4, 0x90, 0x1f, + 0xb2, 0xb4, 0xf8, 0xe0, 0xcd, 0xa1, 0x9d, 0x1c, 0xf2, 0xf1, 0xdf, 0xfb, + 0x88, 0x4e, 0xe5, 0x41, 0xd8, 0x6e, 0xac, 0x07, 0x87, 0x95, 0x35, 0xa6, + 0x12, 0x08, 0x5d, 0x57, 0x5e, 0xaf, 0x71, 0x0f, 0x07, 0x4e, 0x81, 0x77, + 0xf1, 0xef, 0xb5, 0x35, 0x5c, 0xfa, 0xf4, 0x4e, 0x42, 0xdc, 0x19, 0xfe, + 0xe4, 0xd2, 0xb4, 0x27, 0xfb, 0x34, 0x1f, 0xb2, 0x6f, 0xf2, 0x95, 0xcc, + 0xd4, 0x47, 0x63, 0xdc, 0x7e, 0x4f, 0x97, 0x2b, 0x7a, 0xe0, 0x80, 0x31, +}; + +static const uint8_t kSpakeMSmallPrecomp[15 * 2 * 32] = { + 0xe7, 0x45, 0x7e, 0x47, 0x49, 0x69, 0xbd, 0x1b, 0x35, 0x1c, 0x2c, 0x98, + 0x03, 0xf3, 0xb3, 0x37, 0xde, 0x39, 0xa5, 0xda, 0xc0, 0x2e, 0xa4, 0xac, + 0x7d, 0x08, 0x26, 0xfc, 0x80, 0xa7, 0x09, 0x12, 0xd0, 0x48, 0x03, 0x2c, + 0x6e, 0xa0, 0xb6, 0xd6, 0x97, 0xdd, 0xc2, 0xe8, 0x6b, 0xda, 0x85, 0xa3, + 0x3a, 0xda, 0xc9, 0x20, 0xf1, 0xbf, 0x18, 0xe1, 0xb0, 0xc6, 0xd1, 0x66, + 0xa5, 0xce, 0xcd, 0x2f, 0x80, 0xa8, 0x4e, 0xc3, 0x81, 0xae, 0x68, 0x3b, + 0x0d, 0xdb, 0x56, 0x32, 0x2f, 0xa8, 0x97, 0xa0, 0x5c, 0x15, 0xc1, 0xcb, + 0x6f, 0x7a, 0x5f, 0xc5, 0x32, 0xfb, 0x49, 0x17, 0x18, 0xfa, 0x85, 0x08, + 0x85, 0xf1, 0xe3, 0x11, 0x8e, 0x3d, 0x70, 0x20, 0x38, 0x4e, 0x0c, 0x17, + 0xa1, 0xa8, 0x20, 0xd2, 0xb1, 0x1d, 0x05, 0x8d, 0x0f, 0xc9, 0x96, 0x18, + 0x9d, 0x8c, 0x89, 0x8f, 0x46, 0x6a, 0x6c, 0x6e, 0x72, 0x03, 0xb2, 0x75, + 0x87, 0xd8, 0xa9, 0x60, 0x93, 0x2b, 0x8b, 0x66, 0xee, 0xaf, 0xce, 0x98, + 0xcd, 0x6b, 0x7c, 0x6a, 0xbe, 0x19, 0xda, 0x66, 0x7c, 0xda, 0x53, 0xa0, + 0xe3, 0x9a, 0x0e, 0x53, 0x3a, 0x7c, 0x73, 0x4a, 0x37, 0xa6, 0x53, 0x23, + 0x67, 0x31, 0xce, 0x8a, 0xab, 0xee, 0x72, 0x76, 0xc2, 0xb5, 0x54, 0x42, + 0xcf, 0x4b, 0xc7, 0x53, 0x24, 0x59, 0xaf, 0x76, 0x53, 0x10, 0x7e, 0x25, + 0x94, 0x5c, 0x23, 0xa6, 0x5e, 0x05, 0xea, 0x14, 0xad, 0x2b, 0xce, 0x50, + 0x77, 0xb3, 0x7a, 0x88, 0x4c, 0xf7, 0x74, 0x04, 0x35, 0xa4, 0x0c, 0x9e, + 0xee, 0x6a, 0x4c, 0x3c, 0xc1, 0x6a, 0x35, 0x4d, 0x6d, 0x8f, 0x94, 0x95, + 0xe4, 0x10, 0xca, 0x46, 0x4e, 0xfa, 0x38, 0x40, 0xeb, 0x1a, 0x1b, 0x5a, + 0xff, 0x73, 0x4d, 0xe9, 0xf2, 0xbe, 0x89, 0xf5, 0xd1, 0x72, 0xd0, 0x1a, + 0x7b, 0x82, 0x08, 0x19, 0xda, 0x54, 0x44, 0xa5, 0x3d, 0xd8, 0x10, 0x1c, + 0xcf, 0x3b, 0xc7, 0x54, 0xd5, 0x11, 0xd7, 0x2a, 0x69, 0x3f, 0xa6, 0x58, + 0x74, 0xfd, 0x90, 0xb2, 0xf4, 0xc2, 0x0e, 0xf3, 0x19, 0x8f, 0x51, 0x7c, + 0x31, 0x12, 0x79, 0x61, 0x16, 0xb4, 0x2f, 0x2f, 0xd0, 0x88, 0x97, 0xf2, + 0xc3, 0x8c, 0xa6, 0xa3, 0x29, 0xff, 0x7e, 0x12, 0x46, 0x2a, 0x9c, 0x09, + 0x7c, 0x5f, 0x87, 0x07, 0x6b, 0xa1, 0x9a, 0x57, 0x55, 0x8e, 0xb0, 0x56, + 0x5d, 0xc9, 0x4c, 0x5b, 0xae, 0xd3, 0xd0, 0x8e, 0xb8, 0xac, 0xba, 0xe8, + 0x54, 0x45, 0x30, 0x14, 0xf6, 0x59, 0x20, 0xc4, 0x03, 0xb7, 0x7a, 0x5d, + 0x6b, 0x5a, 0xcb, 0x28, 0x60, 0xf8, 0xef, 0x61, 0x60, 0x78, 0x6b, 0xf5, + 0x21, 0x4b, 0x75, 0xc2, 0x77, 0xba, 0x0e, 0x38, 0x98, 0xe0, 0xfb, 0xb7, + 0x5f, 0x75, 0x87, 0x04, 0x0c, 0xb4, 0x5c, 0x09, 0x04, 0x00, 0x38, 0x4e, + 0x4f, 0x7b, 0x73, 0xe5, 0xdb, 0xdb, 0xf1, 0xf4, 0x5c, 0x64, 0x68, 0xfd, + 0xb1, 0x86, 0xe8, 0x89, 0xbe, 0x9c, 0xd4, 0x96, 0x1d, 0xcb, 0xdc, 0x5c, + 0xef, 0xd4, 0x33, 0x28, 0xb9, 0xb6, 0xaf, 0x3b, 0xcf, 0x8d, 0x30, 0xba, + 0xe8, 0x08, 0xcf, 0x84, 0xba, 0x61, 0x10, 0x9b, 0x62, 0xf6, 0x18, 0x79, + 0x66, 0x87, 0x82, 0x7c, 0xaa, 0x71, 0xac, 0xd0, 0xd0, 0x32, 0xb0, 0x54, + 0x03, 0xa4, 0xad, 0x3f, 0x72, 0xca, 0x22, 0xff, 0x01, 0x87, 0x08, 0x36, + 0x61, 0x22, 0xaa, 0x18, 0xab, 0x3a, 0xbc, 0xf2, 0x78, 0x05, 0xe1, 0x99, + 0xa3, 0x59, 0x98, 0xcc, 0x21, 0xc6, 0x2b, 0x51, 0x6d, 0x43, 0x0a, 0x46, + 0x50, 0xae, 0x11, 0x7e, 0xd5, 0x23, 0x56, 0xef, 0x83, 0xc8, 0xbf, 0x42, + 0xf0, 0x45, 0x52, 0x1f, 0x34, 0xbc, 0x2f, 0xb0, 0xf0, 0xce, 0xf0, 0xec, + 0xd0, 0x99, 0x59, 0x2e, 0x1f, 0xab, 0xa8, 0x1e, 0x4b, 0xce, 0x1b, 0x9a, + 0x75, 0xc6, 0xc4, 0x71, 0x86, 0xf0, 0x8d, 0xec, 0xb0, 0x30, 0xb9, 0x62, + 0xb3, 0xb7, 0xdd, 0x96, 0x29, 0xc8, 0xbf, 0xe9, 0xb0, 0x74, 0x78, 0x7b, + 0xf7, 0xea, 0xa3, 0x14, 0x12, 0x56, 0xe0, 0xf3, 0x35, 0x7a, 0x26, 0x4a, + 0x4c, 0xe6, 0xdf, 0x13, 0xb5, 0x52, 0xb0, 0x2a, 0x5f, 0x2e, 0xac, 0x34, + 0xab, 0x5f, 0x1a, 0x01, 0xe4, 0x15, 0x1a, 0xd1, 0xbf, 0xc9, 0x95, 0x0a, + 0xac, 0x1d, 0xe7, 0x53, 0x59, 0x8d, 0xc3, 0x21, 0x78, 0x5e, 0x12, 0x97, + 0x8f, 0x4e, 0x1d, 0xf9, 0xe5, 0xe2, 0xc2, 0xc4, 0xba, 0xfb, 0x50, 0x96, + 0x5b, 0x43, 0xe8, 0xf7, 0x0d, 0x1b, 0x64, 0x58, 0xbe, 0xd3, 0x95, 0x7f, + 0x8e, 0xf1, 0x85, 0x35, 0xba, 0x25, 0x55, 0x2e, 0x02, 0x46, 0x5c, 0xad, + 0x1f, 0xc5, 0x03, 0xcc, 0xd0, 0x43, 0x4c, 0xf2, 0x5e, 0x64, 0x0a, 0x89, + 0xd9, 0xfd, 0x23, 0x7d, 0x4f, 0xbe, 0x2f, 0x0f, 0x1e, 0x12, 0x4a, 0xd9, + 0xf8, 0x82, 0xde, 0x8f, 0x4f, 0x98, 0xb9, 0x90, 0xf6, 0xfa, 0xd1, 0x11, + 0xa6, 0xdc, 0x7e, 0x32, 0x48, 0x6a, 0x8a, 0x14, 0x5e, 0x73, 0xb9, 0x6c, + 0x0e, 0xc2, 0xf9, 0xcc, 0xf0, 0x32, 0xc8, 0xb5, 0x56, 0xaa, 0x5d, 0xd2, + 0x07, 0xf1, 0x6f, 0x33, 0x6f, 0x05, 0x70, 0x49, 0x60, 0x49, 0x23, 0x23, + 0x14, 0x0e, 0x4c, 0x58, 0x92, 0xad, 0xa9, 0x50, 0xb1, 0x59, 0x43, 0x96, + 0x7b, 0xc1, 0x51, 0x45, 0xef, 0x0d, 0xef, 0xd1, 0xe4, 0xd0, 0xce, 0xdf, + 0x6a, 0xbc, 0x1b, 0xbf, 0x7a, 0x87, 0x4e, 0x47, 0x17, 0x9c, 0x34, 0x38, + 0xb0, 0x3c, 0xa1, 0x04, 0xfb, 0xe2, 0x66, 0xce, 0xb6, 0x82, 0xbb, 0xad, + 0xc3, 0x8e, 0x12, 0x35, 0xbc, 0x17, 0xce, 0x01, 0x2d, 0xa3, 0xa6, 0xb9, + 0xfa, 0x84, 0xc2, 0x2f, 0x5a, 0x4a, 0x8c, 0x4c, 0x11, 0x4e, 0xa8, 0x14, + 0xcb, 0xb8, 0x99, 0xaa, 0x2e, 0x8c, 0xa0, 0xc9, 0x5f, 0x62, 0x2a, 0x84, + 0x66, 0x60, 0x0a, 0x7e, 0xdc, 0x93, 0x17, 0x45, 0x19, 0xb3, 0x93, 0x4c, + 0xdc, 0xd0, 0xd5, 0x5c, 0x25, 0xd2, 0xcd, 0x4e, 0x84, 0x4c, 0x73, 0xb3, + 0x90, 0xa4, 0x22, 0x05, 0x2c, 0x7c, 0x39, 0x2b, 0x70, 0xd9, 0x61, 0x76, + 0xb2, 0x03, 0x71, 0xe9, 0x0e, 0xf8, 0x57, 0x85, 0xad, 0xb1, 0x2f, 0x34, + 0xa5, 0x66, 0xb0, 0x0f, 0x75, 0x94, 0x6e, 0x26, 0x79, 0x99, 0xb4, 0xe2, + 0xe2, 0xa3, 0x58, 0xdd, 0xb4, 0xfb, 0x74, 0xf4, 0xa1, 0xca, 0xc3, 0x30, + 0xe7, 0x86, 0xb2, 0xa2, 0x2c, 0x11, 0xc9, 0x58, 0xe3, 0xc1, 0xa6, 0x5f, + 0x86, 0x6a, 0xe7, 0x75, 0xd5, 0xd8, 0x63, 0x95, 0x64, 0x59, 0xbc, 0xb8, + 0xb7, 0xf5, 0x12, 0xe3, 0x03, 0xc6, 0x17, 0xea, 0x4e, 0xcb, 0xee, 0x4c, + 0xae, 0x03, 0xd1, 0x33, 0xd0, 0x39, 0x36, 0x00, 0x0f, 0xf4, 0x9c, 0xbd, + 0x35, 0x96, 0xfd, 0x0d, 0x26, 0xb7, 0x9e, 0xf4, 0x4b, 0x6f, 0x4b, 0xf1, + 0xec, 0x11, 0x00, 0x16, 0x21, 0x1e, 0xd4, 0x43, 0x23, 0x8c, 0x4a, 0xfa, + 0x9e, 0xd4, 0x2b, 0x36, 0x9a, 0x43, 0x1e, 0x58, 0x31, 0xe8, 0x1f, 0x83, + 0x15, 0x20, 0x31, 0x68, 0xfe, 0x27, 0xd3, 0xd8, 0x9b, 0x43, 0x81, 0x8f, + 0x57, 0x32, 0x14, 0xe6, 0x9e, 0xbf, 0xd1, 0xfb, 0xdf, 0xad, 0x7a, 0x52, +}; + +/* left_shift_3 sets |n| to |n|*8, where |n| is represented in little-endian + * order. */ +static void left_shift_3(uint8_t n[32]) { + uint8_t carry = 0; + unsigned i; + + for (i = 0; i < 32; i++) { + const uint8_t next_carry = n[i] >> 5; + n[i] = (n[i] << 3) | carry; + carry = next_carry; + } +} + +static krb5_error_code +builtin_edwards25519_keygen(krb5_context context, groupdata *gdata, + const uint8_t *wbytes, krb5_boolean use_m, + uint8_t *priv_out, uint8_t *pub_out) +{ + uint8_t private[64]; + krb5_data data = make_data(private, 32); + krb5_error_code ret; + + /* Pick x or y uniformly from [0, p*h) divisible by h. */ + ret = krb5_c_random_make_octets(context, &data); + if (ret) + return ret; + memset(private + 32, 0, 32); + x25519_sc_reduce(private); + left_shift_3(private); + + /* Compute X=x*G or Y=y*G. */ + ge_p3 P; + x25519_ge_scalarmult_base(&P, private); + + /* Compute w mod p. */ + uint8_t wreduced[64]; + memcpy(wreduced, wbytes, 32); + memset(wreduced + 32, 0, 32); + x25519_sc_reduce(wreduced); + + /* Compute the mask, w*M or w*N. */ + ge_p3 mask; + x25519_ge_scalarmult_small_precomp(&mask, wreduced, + use_m ? kSpakeMSmallPrecomp : + kSpakeNSmallPrecomp); + + /* Compute the masked point T=w*M+X or S=w*N+Y. */ + ge_cached mask_cached; + x25519_ge_p3_to_cached(&mask_cached, &mask); + ge_p1p1 Pmasked; + x25519_ge_add(&Pmasked, &P, &mask_cached); + + /* Encode T or S into pub_out. */ + ge_p2 Pmasked_proj; + x25519_ge_p1p1_to_p2(&Pmasked_proj, &Pmasked); + x25519_ge_tobytes(pub_out, &Pmasked_proj); + + /* Remember the private key in priv_out. */ + memcpy(priv_out, private, 32); + return 0; +} + +static krb5_error_code +builtin_edwards25519_result(krb5_context context, groupdata *gdata, + const uint8_t *wbytes, const uint8_t *ourpriv, + const uint8_t *theirpub, krb5_boolean use_m, + uint8_t *elem_out) +{ + /* + * Check if the point received from peer is on the curve. This does not + * verify that it is in the generator subgroup, but since our private key is + * a multiple of the cofactor, the shared point will be in the generator + * subgroup even if a rogue peer sends a point which is not. + */ + ge_p3 Qmasked; + if (x25519_ge_frombytes_vartime(&Qmasked, theirpub) != 0) + return EINVAL; + + /* Compute w mod p. */ + uint8_t wreduced[64]; + memcpy(wreduced, wbytes, 32); + memset(wreduced + 32, 0, 32); + x25519_sc_reduce(wreduced); + + /* Compute the peer's mask, w*M or w*N. */ + ge_p3 peers_mask; + x25519_ge_scalarmult_small_precomp(&peers_mask, wreduced, + use_m ? kSpakeMSmallPrecomp : + kSpakeNSmallPrecomp); + + ge_cached peers_mask_cached; + x25519_ge_p3_to_cached(&peers_mask_cached, &peers_mask); + + /* Compute the peer's unmasked point, T-w*M or S-w*N. */ + ge_p1p1 Qcompl; + ge_p3 Qunmasked; + x25519_ge_sub(&Qcompl, &Qmasked, &peers_mask_cached); + x25519_ge_p1p1_to_p3(&Qunmasked, &Qcompl); + + /* Multiply by our private value to compute K=x*(S-w*N) or K=y*(T-w*M). */ + ge_p2 K; + x25519_ge_scalarmult(&K, ourpriv, &Qunmasked); + + /* Encode K into elem_out. */ + x25519_ge_tobytes(elem_out, &K); + return 0; +} + +static krb5_error_code +builtin_sha256(krb5_context context, groupdata *gdata, const krb5_data *dlist, + size_t ndata, uint8_t *result_out) +{ + return k5_sha256(dlist, ndata, result_out); +} + +groupdef builtin_edwards25519 = { + .reg = &spake_iana_edwards25519, + .keygen = builtin_edwards25519_keygen, + .result = builtin_edwards25519_result, + .hash = builtin_sha256 +}; diff --git a/src/plugins/preauth/spake/edwards25519_tables.h b/src/plugins/preauth/spake/edwards25519_tables.h new file mode 100644 index 000000000..c6c501373 --- /dev/null +++ b/src/plugins/preauth/spake/edwards25519_tables.h @@ -0,0 +1,7881 @@ +/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*- */ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS file). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* From BoringSSL third-party/fiat/curve25519_tables.h */ + +static const fe d = {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 929955233495203, 466365720129213, 1662059464998953, 2033849074728123, + 1442794654840575 +#else + 56195235, 13857412, 51736253, 6949390, 114729, 24766616, 60832955, 30306712, + 48412415, 21499315 +#endif +}}; + +static const fe sqrtm1 = {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, + 765476049583133 +#else + 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, + 31548777, 326685, 11406482 +#endif +}}; + +static const fe d2 = {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1859910466990425, 932731440258426, 1072319116312658, 1815898335770999, + 633789495995903 +#else + 45281625, 27714825, 36363642, 13898781, 229458, 15978800, 54557047, + 27058993, 29715967, 9444199 +#endif +}}; + +#if defined(CONFIG_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, +}; + +#else + +// k25519Precomp[i][j] = (j+1)*256^i*B +static const ge_precomp k25519Precomp[32][8] = { + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1288382639258501, 245678601348599, 269427782077623, + 1462984067271730, 137412439391563 +#else + 25967493, 19198397, 29566455, 3660896, 54414519, 4014786, + 27544626, 21800161, 61029707, 2047604 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 62697248952638, 204681361388450, 631292143396476, + 338455783676468, 1213667448819585 +#else + 54563134, 934261, 64385954, 3049989, 66381436, 9406985, + 12720692, 5043384, 19500929, 18085054 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 301289933810280, 1259582250014073, 1422107436869536, + 796239922652654, 1953934009299142 +#else + 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, + 29287918, 11864899, 42594502, 29115885 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1380971894829527, 790832306631236, 2067202295274102, + 1995808275510000, 1566530869037010 +#else + 54292951, 20578084, 45527620, 11784319, 41753206, 30803714, + 55390960, 29739860, 66750418, 23343128 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 463307831301544, 432984605774163, 1610641361907204, + 750899048855000, 1894842303421586 +#else + 45405608, 6903824, 27185491, 6451973, 37531140, 24000426, + 51492312, 11189267, 40279186, 28235350 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 748439484463711, 1033211726465151, 1396005112841647, + 1611506220286469, 1972177495910992 +#else + 26966623, 11152617, 32442495, 15396054, 14353839, 20802097, + 63980037, 24013313, 51636816, 29387734 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1601611775252272, 1720807796594148, 1132070835939856, + 1260455018889551, 2147779492816911 +#else + 15636272, 23865875, 24204772, 25642034, 616976, 16869170, + 27787599, 18782243, 28944399, 32004408 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 316559037616741, 2177824224946892, 1459442586438991, + 1461528397712656, 751590696113597 +#else + 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, + 16354576, 21778470, 7689661, 11199574 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1850748884277385, 1200145853858453, 1068094770532492, + 672251375690438, 1586055907191707 +#else + 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, + 7512774, 10017326, 49359771, 23634074 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 934282339813791, 1846903124198670, 1172395437954843, + 1007037127761661, 1830588347719256 +#else + 50071967, 13921891, 10945806, 27521001, 27105051, 17470053, + 38182653, 15006022, 3284568, 27277892 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1694390458783935, 1735906047636159, 705069562067493, + 648033061693059, 696214010414170 +#else + 23599295, 25248385, 55915199, 25867015, 13236773, 10506355, + 7464579, 9656445, 13059162, 10374397 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1121406372216585, 192876649532226, 190294192191717, + 1994165897297032, 2245000007398739 +#else + 7798537, 16710257, 3033922, 2874086, 28997861, 2835604, + 32406664, 29715387, 66467155, 33453106 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 769950342298419, 132954430919746, 844085933195555, + 974092374476333, 726076285546016 +#else + 10861363, 11473154, 27284546, 1981175, 37044515, 12577860, + 32867885, 14515107, 51670560, 10819379 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 425251763115706, 608463272472562, 442562545713235, + 837766094556764, 374555092627893 +#else + 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, + 41455196, 12483687, 54440373, 5581305 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1086255230780037, 274979815921559, 1960002765731872, + 929474102396301, 1190409889297339 +#else + 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, + 28542349, 13850243, 43430843, 17738489 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1388594989461809, 316767091099457, 394298842192982, + 1230079486801005, 1440737038838979 +#else + 51736881, 20691677, 32573249, 4720197, 40672342, 5875510, + 47920237, 18329612, 57289923, 21468654 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 7380825640100, 146210432690483, 304903576448906, + 1198869323871120, 997689833219095 +#else + 58559652, 109982, 15149363, 2178705, 22900618, 4543417, 3044240, + 17864545, 1762327, 14866737 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1181317918772081, 114573476638901, 262805072233344, + 265712217171332, 294181933805782 +#else + 48909169, 17603008, 56635573, 1707277, 49922944, 3916100, + 38872452, 3959420, 27914454, 4383652 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 665000864555967, 2065379846933859, 370231110385876, + 350988370788628, 1233371373142985 +#else + 5153727, 9909285, 1723747, 30776558, 30523604, 5516873, + 19480852, 5230134, 43156425, 18378665 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2019367628972465, 676711900706637, 110710997811333, + 1108646842542025, 517791959672113 +#else + 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, + 20654025, 16520125, 30598449, 7715701 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 965130719900578, 247011430587952, 526356006571389, + 91986625355052, 2157223321444601 +#else + 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, + 35708204, 1370707, 29794553, 32145132 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2068619540119183, 1966274918058806, 957728544705549, + 729906502578991, 159834893065166 +#else + 14499471, 30824833, 33917750, 29299779, 28494861, 14271267, + 30290735, 10876454, 33954766, 2381725 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2073601412052185, 31021124762708, 264500969797082, + 248034690651703, 1030252227928288 +#else + 59913433, 30899068, 52378708, 462250, 39384538, 3941371, + 60872247, 3696004, 34808032, 15351954 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 551790716293402, 1989538725166328, 801169423371717, + 2052451893578887, 678432056995012 +#else + 27431194, 8222322, 16448760, 29646437, 48401861, 11938354, + 34147463, 30583916, 29551812, 10109425 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1368953770187805, 790347636712921, 437508475667162, + 2142576377050580, 1932081720066286 +#else + 53451805, 20399000, 35825113, 11777097, 21447386, 6519384, + 64730580, 31926875, 10092782, 28790261 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 953638594433374, 1092333936795051, 1419774766716690, + 805677984380077, 859228993502513 +#else + 27939166, 14210322, 4677035, 16277044, 44144402, 21156292, + 34600109, 12005537, 49298737, 12803509 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1200766035879111, 20142053207432, 1465634435977050, + 1645256912097844, 295121984874596 +#else + 17228999, 17892808, 65875336, 300139, 65883994, 21839654, + 30364212, 24516238, 18016356, 4397660 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1735718747031557, 1248237894295956, 1204753118328107, + 976066523550493, 65943769534592 +#else + 56150021, 25864224, 4776340, 18600194, 27850027, 17952220, + 40489757, 14544524, 49631360, 982638 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1060098822528990, 1586825862073490, 212301317240126, + 1975302711403555, 666724059764335 +#else + 29253598, 15796703, 64244882, 23645547, 10057022, 3163536, + 7332899, 29434304, 46061167, 9934962 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1091990273418756, 1572899409348578, 80968014455247, + 306009358661350, 1520450739132526 +#else + 5793284, 16271923, 42977250, 23438027, 29188559, 1206517, + 52360934, 4559894, 36984942, 22656481 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1480517209436112, 1511153322193952, 1244343858991172, + 304788150493241, 369136856496443 +#else + 39464912, 22061425, 16282656, 22517939, 28414020, 18542168, + 24191033, 4541697, 53770555, 5500567 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2151330273626164, 762045184746182, 1688074332551515, + 823046109005759, 907602769079491 +#else + 12650548, 32057319, 9052870, 11355358, 49428827, 25154267, + 49678271, 12264342, 10874051, 13524335 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2047386910586836, 168470092900250, 1552838872594810, + 340951180073789, 360819374702533 +#else + 25556948, 30508442, 714650, 2510400, 23394682, 23139102, + 33119037, 5080568, 44580805, 5376627 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1982622644432056, 2014393600336956, 128909208804214, + 1617792623929191, 105294281913815 +#else + 41020600, 29543379, 50095164, 30016803, 60382070, 1920896, + 44787559, 24106988, 4535767, 1569007 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 980234343912898, 1712256739246056, 588935272190264, + 204298813091998, 841798321043288 +#else + 64853442, 14606629, 45416424, 25514613, 28430648, 8775819, + 36614302, 3044289, 31848280, 12543772 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 197561292938973, 454817274782871, 1963754960082318, + 2113372252160468, 971377527342673 +#else + 45080285, 2943892, 35251351, 6777305, 13784462, 29262229, + 39731668, 31491700, 7718481, 14474653 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 164699448829328, 3127451757672, 1199504971548753, + 1766155447043652, 1899238924683527 +#else + 2385296, 2454213, 44477544, 46602, 62670929, 17874016, 656964, + 26317767, 24316167, 28300865 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 732262946680281, 1674412764227063, 2182456405662809, + 1350894754474250, 558458873295247 +#else + 13741529, 10911568, 33875447, 24950694, 46931033, 32521134, + 33040650, 20129900, 46379407, 8321685 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2103305098582922, 1960809151316468, 715134605001343, + 1454892949167181, 40827143824949 +#else + 21060490, 31341688, 15712756, 29218333, 1639039, 10656336, + 23845965, 21679594, 57124405, 608371 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1239289043050212, 1744654158124578, 758702410031698, + 1796762995074688, 1603056663766 +#else + 53436132, 18466845, 56219170, 25997372, 61071954, 11305546, + 1123968, 26773855, 27229398, 23887 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2232056027107988, 987343914584615, 2115594492994461, + 1819598072792159, 1119305654014850 +#else + 43864724, 33260226, 55364135, 14712570, 37643165, 31524814, + 12797023, 27114124, 65475458, 16678953 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 320153677847348, 939613871605645, 641883205761567, + 1930009789398224, 329165806634126 +#else + 37608244, 4770661, 51054477, 14001337, 7830047, 9564805, + 65600720, 28759386, 49939598, 4904952 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 980930490474130, 1242488692177893, 1251446316964684, + 1086618677993530, 1961430968465772 +#else + 24059538, 14617003, 19037157, 18514524, 19766092, 18648003, + 5169210, 16191880, 2128236, 29227599 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 276821765317453, 1536835591188030, 1305212741412361, + 61473904210175, 2051377036983058 +#else + 50127693, 4124965, 58568254, 22900634, 30336521, 19449185, + 37302527, 916032, 60226322, 30567899 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 833449923882501, 1750270368490475, 1123347002068295, + 185477424765687, 278090826653186 +#else + 44477957, 12419371, 59974635, 26081060, 50629959, 16739174, + 285431, 2763829, 15736322, 4143876 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 794524995833413, 1849907304548286, 53348672473145, + 1272368559505217, 1147304168324779 +#else + 2379333, 11839345, 62998462, 27565766, 11274297, 794957, 212801, + 18959769, 23527083, 17096164 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1504846112759364, 1203096289004681, 562139421471418, + 274333017451844, 1284344053775441 +#else + 33431108, 22423954, 49269897, 17927531, 8909498, 8376530, + 34483524, 4087880, 51919953, 19138217 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 483048732424432, 2116063063343382, 30120189902313, + 292451576741007, 1156379271702225 +#else + 1767664, 7197987, 53903638, 31531796, 54017513, 448825, 5799055, + 4357868, 62334673, 17231393 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 928372153029038, 2147692869914564, 1455665844462196, + 1986737809425946, 185207050258089 +#else + 6721966, 13833823, 43585476, 32003117, 26354292, 21691111, + 23365146, 29604700, 7390889, 2759800 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 137732961814206, 706670923917341, 1387038086865771, + 1965643813686352, 1384777115696347 +#else + 4409022, 2052381, 23373853, 10530217, 7676779, 20668478, + 21302352, 29290375, 1244379, 20634787 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 481144981981577, 2053319313589856, 2065402289827512, + 617954271490316, 1106602634668125 +#else + 62687625, 7169618, 4982368, 30596842, 30256824, 30776892, + 14086412, 9208236, 15886429, 16489664 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 696298019648792, 893299659040895, 1148636718636009, + 26734077349617, 2203955659340681 +#else + 1996056, 10375649, 14346367, 13311202, 60234729, 17116020, + 53415665, 398368, 36502409, 32841498 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 657390353372855, 998499966885562, 991893336905797, + 810470207106761, 343139804608786 +#else + 41801399, 9795879, 64331450, 14878808, 33577029, 14780362, + 13348553, 12076947, 36272402, 5113181 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 791736669492960, 934767652997115, 824656780392914, + 1759463253018643, 361530362383518 +#else + 49338080, 11797795, 31950843, 13929123, 41220562, 12288343, + 36767763, 26218045, 13847710, 5387222 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2022541353055597, 2094700262587466, 1551008075025686, + 242785517418164, 695985404963562 +#else + 48526701, 30138214, 17824842, 31213466, 22744342, 23111821, + 8763060, 3617786, 47508202, 10370990 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1287487199965223, 2215311941380308, 1552928390931986, + 1664859529680196, 1125004975265243 +#else + 20246567, 19185054, 22358228, 33010720, 18507282, 23140436, + 14554436, 24808340, 32232923, 16763880 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 677434665154918, 989582503122485, 1817429540898386, + 1052904935475344, 1143826298169798 +#else + 9648486, 10094563, 26416693, 14745928, 36734546, 27081810, + 11094160, 15689506, 3140038, 17044340 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 367266328308408, 318431188922404, 695629353755355, + 634085657580832, 24581612564426 +#else + 50948792, 5472694, 31895588, 4744994, 8823515, 10365685, + 39884064, 9448612, 38334410, 366294 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 773360688841258, 1815381330538070, 363773437667376, + 539629987070205, 783280434248437 +#else + 19153450, 11523972, 56012374, 27051289, 42461232, 5420646, + 28344573, 8041113, 719605, 11671788 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 180820816194166, 168937968377394, 748416242794470, + 1227281252254508, 1567587861004268 +#else + 8678006, 2694440, 60300850, 2517371, 4964326, 11152271, + 51675948, 18287915, 27000812, 23358879 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 478775558583645, 2062896624554807, 699391259285399, + 358099408427873, 1277310261461761 +#else + 51950941, 7134311, 8639287, 30739555, 59873175, 10421741, + 564065, 5336097, 6750977, 19033406 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1984740906540026, 1079164179400229, 1056021349262661, + 1659958556483663, 1088529069025527 +#else + 11836410, 29574944, 26297893, 16080799, 23455045, 15735944, + 1695823, 24735310, 8169719, 16220347 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 580736401511151, 1842931091388998, 1177201471228238, + 2075460256527244, 1301133425678027 +#else + 48993007, 8653646, 17578566, 27461813, 59083086, 17541668, + 55964556, 30926767, 61118155, 19388398 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1515728832059182, 1575261009617579, 1510246567196186, + 191078022609704, 116661716289141 +#else + 43800366, 22586119, 15213227, 23473218, 36255258, 22504427, + 27884328, 2847284, 2655861, 1738395 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1295295738269652, 1714742313707026, 545583042462581, + 2034411676262552, 1513248090013606 +#else + 39571412, 19301410, 41772562, 25551651, 57738101, 8129820, + 21651608, 30315096, 48021414, 22549153 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 230710545179830, 30821514358353, 760704303452229, + 390668103790604, 573437871383156 +#else + 1533110, 3437855, 23735889, 459276, 29970501, 11335377, + 26030092, 5821408, 10478196, 8544890 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1169380107545646, 263167233745614, 2022901299054448, + 819900753251120, 2023898464874585 +#else + 32173102, 17425121, 24896206, 3921497, 22579056, 30143578, + 19270448, 12217473, 17789017, 30158437 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2102254323485823, 1570832666216754, 34696906544624, + 1993213739807337, 70638552271463 +#else + 36555903, 31326030, 51530034, 23407230, 13243888, 517024, + 15479401, 29701199, 30460519, 1052596 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 894132856735058, 548675863558441, 845349339503395, + 1942269668326667, 1615682209874691 +#else + 55493970, 13323617, 32618793, 8175907, 51878691, 12596686, + 27491595, 28942073, 3179267, 24075541 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1287670217537834, 1222355136884920, 1846481788678694, + 1150426571265110, 1613523400722047 +#else + 31947050, 19187781, 62468280, 18214510, 51982886, 27514722, + 52352086, 17142691, 19072639, 24043372 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 793388516527298, 1315457083650035, 1972286999342417, + 1901825953052455, 338269477222410 +#else + 11685058, 11822410, 3158003, 19601838, 33402193, 29389366, + 5977895, 28339415, 473098, 5040608 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 550201530671806, 778605267108140, 2063911101902983, + 115500557286349, 2041641272971022 +#else + 46817982, 8198641, 39698732, 11602122, 1290375, 30754672, + 28326861, 1721092, 47550222, 30422825 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 717255318455100, 519313764361315, 2080406977303708, + 541981206705521, 774328150311600 +#else + 7881532, 10687937, 7578723, 7738378, 48157852, 31000479, + 21820785, 8076149, 39240368, 11538388 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 261715221532238, 1795354330069993, 1496878026850283, + 499739720521052, 389031152673770 +#else + 47173198, 3899860, 18283497, 26752864, 51380203, 22305220, + 8754524, 7446702, 61432810, 5797015 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1997217696294013, 1717306351628065, 1684313917746180, + 1644426076011410, 1857378133465451 +#else + 55813245, 29760862, 51326753, 25589858, 12708868, 25098233, + 2014098, 24503858, 64739691, 27677090 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1475434724792648, 76931896285979, 1116729029771667, + 2002544139318042, 725547833803938 +#else + 44636488, 21985690, 39426843, 1146374, 18956691, 16640559, + 1192730, 29840233, 15123618, 10811505 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2022306639183567, 726296063571875, 315345054448644, + 1058733329149221, 1448201136060677 +#else + 14352079, 30134717, 48166819, 10822654, 32750596, 4699007, + 67038501, 15776355, 38222085, 21579878 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1710065158525665, 1895094923036397, 123988286168546, + 1145519900776355, 1607510767693874 +#else + 38867681, 25481956, 62129901, 28239114, 29416930, 1847569, + 46454691, 17069576, 4714546, 23953777 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 561605375422540, 1071733543815037, 131496498800990, + 1946868434569999, 828138133964203 +#else + 15200332, 8368572, 19679101, 15970074, 35236190, 1959450, + 24611599, 29010600, 55362987, 12340219 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1548495173745801, 442310529226540, 998072547000384, + 553054358385281, 644824326376171 +#else + 12876937, 23074376, 33134380, 6590940, 60801088, 14872439, + 9613953, 8241152, 15370987, 9608631 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1445526537029440, 2225519789662536, 914628859347385, + 1064754194555068, 1660295614401091 +#else + 62965568, 21540023, 8446280, 33162829, 4407737, 13629032, + 59383996, 15866073, 38898243, 24740332 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1199690223111956, 24028135822341, 66638289244341, + 57626156285975, 565093967979607 +#else + 26660628, 17876777, 8393733, 358047, 59707573, 992987, 43204631, + 858696, 20571223, 8420556 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 876926774220824, 554618976488214, 1012056309841565, + 839961821554611, 1414499340307677 +#else + 14620696, 13067227, 51661590, 8264466, 14106269, 15080814, + 33531827, 12516406, 45534429, 21077682 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 703047626104145, 1266841406201770, 165556500219173, + 486991595001879, 1011325891650656 +#else + 236881, 10476226, 57258, 18877408, 6472997, 2466984, 17258519, + 7256740, 8791136, 15069930 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1622861044480487, 1156394801573634, 1869132565415504, + 327103985777730, 2095342781472284 +#else + 1276391, 24182514, 22949634, 17231625, 43615824, 27852245, + 14711874, 4874229, 36445724, 31223040 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 334886927423922, 489511099221528, 129160865966726, + 1720809113143481, 619700195649254 +#else + 5855666, 4990204, 53397016, 7294283, 59304582, 1924646, + 65685689, 25642053, 34039526, 9234252 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1646545795166119, 1758370782583567, 714746174550637, + 1472693650165135, 898994790308209 +#else + 20590503, 24535444, 31529743, 26201766, 64402029, 10650547, + 31559055, 21944845, 18979185, 13396066 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 333403773039279, 295772542452938, 1693106465353610, + 912330357530760, 471235657950362 +#else + 24474287, 4968103, 22267082, 4407354, 24063882, 25229252, + 48291976, 13594781, 33514650, 7021958 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1811196219982022, 1068969825533602, 289602974833439, + 1988956043611592, 863562343398367 +#else + 55541958, 26988926, 45743778, 15928891, 40950559, 4315420, + 41160136, 29637754, 45628383, 12868081 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 906282429780072, 2108672665779781, 432396390473936, + 150625823801893, 1708930497638539 +#else + 38473832, 13504660, 19988037, 31421671, 21078224, 6443208, + 45662757, 2244499, 54653067, 25465048 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 925664675702328, 21416848568684, 1831436641861340, + 601157008940113, 371818055044496 +#else + 36513336, 13793478, 61256044, 319135, 41385692, 27290532, + 33086545, 8957937, 51875216, 5540520 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1479786007267725, 1738881859066675, 68646196476567, + 2146507056100328, 1247662817535471 +#else + 55478669, 22050529, 58989363, 25911358, 2620055, 1022908, + 43398120, 31985447, 50980335, 18591624 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 52035296774456, 939969390708103, 312023458773250, + 59873523517659, 1231345905848899 +#else + 23152952, 775386, 27395463, 14006635, 57407746, 4649511, + 1689819, 892185, 55595587, 18348483 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 643355106415761, 290186807495774, 2013561737429023, + 319648069511546, 393736678496162 +#else + 9770129, 9586738, 26496094, 4324120, 1556511, 30004408, + 27453818, 4763127, 47929250, 5867133 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 129358342392716, 1932811617704777, 1176749390799681, + 398040349861790, 1170779668090425 +#else + 34343820, 1927589, 31726409, 28801137, 23962433, 17534932, + 27846558, 5931263, 37359161, 17445976 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2051980782668029, 121859921510665, 2048329875753063, + 1235229850149665, 519062146124755 +#else + 27461885, 30576896, 22380809, 1815854, 44075111, 30522493, + 7283489, 18406359, 47582163, 7734628 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1608170971973096, 415809060360428, 1350468408164766, + 2038620059057678, 1026904485989112 +#else + 59098600, 23963614, 55988460, 6196037, 29344158, 20123547, + 7585294, 30377806, 18549496, 15302069 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1837656083115103, 1510134048812070, 906263674192061, + 1821064197805734, 565375124676301 +#else + 34450527, 27383209, 59436070, 22502750, 6258877, 13504381, + 10458790, 27135971, 58236621, 8424745 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 578027192365650, 2034800251375322, 2128954087207123, + 478816193810521, 2196171989962750 +#else + 24687186, 8613276, 36441818, 30320886, 1863891, 31723888, + 19206233, 7134917, 55824382, 32725512 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1633188840273139, 852787172373708, 1548762607215796, + 1266275218902681, 1107218203325133 +#else + 11334899, 24336410, 8025292, 12707519, 17523892, 23078361, + 10243737, 18868971, 62042829, 16498836 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 462189358480054, 1784816734159228, 1611334301651368, + 1303938263943540, 707589560319424 +#else + 8911542, 6887158, 57524604, 26595841, 11145640, 24010752, + 17303924, 19430194, 6536640, 10543906 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1038829280972848, 38176604650029, 753193246598573, + 1136076426528122, 595709990562434 +#else + 38162480, 15479762, 49642029, 568875, 65611181, 11223453, + 64439674, 16928857, 39873154, 8876770 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1408451820859834, 2194984964010833, 2198361797561729, + 1061962440055713, 1645147963442934 +#else + 41365946, 20987567, 51458897, 32707824, 34082177, 32758143, + 33627041, 15824473, 66504438, 24514614 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 4701053362120, 1647641066302348, 1047553002242085, + 1923635013395977, 206970314902065 +#else + 10330056, 70051, 7957388, 24551765, 9764901, 15609756, 27698697, + 28664395, 1657393, 3084098 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1750479161778571, 1362553355169293, 1891721260220598, + 966109370862782, 1024913988299801 +#else + 10477963, 26084172, 12119565, 20303627, 29016246, 28188843, + 31280318, 14396151, 36875289, 15272408 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 212699049131723, 1117950018299775, 1873945661751056, + 1403802921984058, 130896082652698 +#else + 54820555, 3169462, 28813183, 16658753, 25116432, 27923966, + 41934906, 20918293, 42094106, 1950503 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 636808533673210, 1262201711667560, 390951380330599, + 1663420692697294, 561951321757406 +#else + 40928506, 9489186, 11053416, 18808271, 36055143, 5825629, + 58724558, 24786899, 15341278, 8373727 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 520731594438141, 1446301499955692, 273753264629267, + 1565101517999256, 1019411827004672 +#else + 28685821, 7759505, 52730348, 21551571, 35137043, 4079241, + 298136, 23321830, 64230656, 15190419 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 926527492029409, 1191853477411379, 734233225181171, + 184038887541270, 1790426146325343 +#else + 34175969, 13806335, 52771379, 17760000, 43104243, 10940927, + 8669718, 2742393, 41075551, 26679428 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1464651961852572, 1483737295721717, 1519450561335517, + 1161429831763785, 405914998179977 +#else + 65528476, 21825014, 41129205, 22109408, 49696989, 22641577, + 9291593, 17306653, 54954121, 6048604 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 996126634382301, 796204125879525, 127517800546509, + 344155944689303, 615279846169038 +#else + 36803549, 14843443, 1539301, 11864366, 20201677, 1900163, + 13934231, 5128323, 11213262, 9168384 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 738724080975276, 2188666632415296, 1961313708559162, + 1506545807547587, 1151301638969740 +#else + 40828332, 11007846, 19408960, 32613674, 48515898, 29225851, + 62020803, 22449281, 20470156, 17155731 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 622917337413835, 1218989177089035, 1284857712846592, + 970502061709359, 351025208117090 +#else + 43972811, 9282191, 14855179, 18164354, 59746048, 19145871, + 44324911, 14461607, 14042978, 5230683 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2067814584765580, 1677855129927492, 2086109782475197, + 235286517313238, 1416314046739645 +#else + 29969548, 30812838, 50396996, 25001989, 9175485, 31085458, + 21556950, 3506042, 61174973, 21104723 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 586844262630358, 307444381952195, 458399356043426, + 602068024507062, 1028548203415243 +#else + 63964118, 8744660, 19704003, 4581278, 46678178, 6830682, + 45824694, 8971512, 38569675, 15326562 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 678489922928203, 2016657584724032, 90977383049628, + 1026831907234582, 615271492942522 +#else + 47644235, 10110287, 49846336, 30050539, 43608476, 1355668, + 51585814, 15300987, 46594746, 9168259 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 301225714012278, 1094837270268560, 1202288391010439, + 644352775178361, 1647055902137983 +#else + 61755510, 4488612, 43305616, 16314346, 7780487, 17915493, + 38160505, 9601604, 33087103, 24543045 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1210746697896478, 1416608304244708, 686487477217856, + 1245131191434135, 1051238336855737 +#else + 47665694, 18041531, 46311396, 21109108, 37284416, 10229460, + 39664535, 18553900, 61111993, 15664671 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1135604073198207, 1683322080485474, 769147804376683, + 2086688130589414, 900445683120379 +#else + 23294591, 16921819, 44458082, 25083453, 27844203, 11461195, + 13099750, 31094076, 18151675, 13417686 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1971518477615628, 401909519527336, 448627091057375, + 1409486868273821, 1214789035034363 +#else + 42385932, 29377914, 35958184, 5988918, 40250079, 6685064, + 1661597, 21002991, 15271675, 18101767 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1364039144731711, 1897497433586190, 2203097701135459, + 145461396811251, 1349844460790699 +#else + 11433023, 20325767, 8239630, 28274915, 65123427, 32828713, + 48410099, 2167543, 60187563, 20114249 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1045230323257973, 818206601145807, 630513189076103, + 1672046528998132, 807204017562437 +#else + 35672693, 15575145, 30436815, 12192228, 44645511, 9395378, + 57191156, 24915434, 12215109, 12028277 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 439961968385997, 386362664488986, 1382706320807688, + 309894000125359, 2207801346498567 +#else + 14098381, 6555944, 23007258, 5757252, 51681032, 20603929, + 30123439, 4617780, 50208775, 32898803 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1229004686397588, 920643968530863, 123975893911178, + 681423993215777, 1400559197080973 +#else + 63082644, 18313596, 11893167, 13718664, 52299402, 1847384, + 51288865, 10154008, 23973261, 20869958 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2003766096898049, 170074059235165, 1141124258967971, + 1485419893480973, 1573762821028725 +#else + 40577025, 29858441, 65199965, 2534300, 35238307, 17004076, + 18341389, 22134481, 32013173, 23450893 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 729905708611432, 1270323270673202, 123353058984288, + 426460209632942, 2195574535456672 +#else + 41629544, 10876442, 55337778, 18929291, 54739296, 1838103, + 21911214, 6354752, 4425632, 32716610 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1271140255321235, 2044363183174497, 52125387634689, + 1445120246694705, 942541986339084 +#else + 56675475, 18941465, 22229857, 30463385, 53917697, 776728, + 49693489, 21533969, 4725004, 14044970 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1761608437466135, 583360847526804, 1586706389685493, + 2157056599579261, 1170692369685772 +#else + 19268631, 26250011, 1555348, 8692754, 45634805, 23643767, + 6347389, 32142648, 47586572, 17444675 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 871476219910823, 1878769545097794, 2241832391238412, + 548957640601001, 690047440233174 +#else + 42244775, 12986007, 56209986, 27995847, 55796492, 33405905, + 19541417, 8180106, 9282262, 10282508 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 297194732135507, 1366347803776820, 1301185512245601, + 561849853336294, 1533554921345731 +#else + 40903763, 4428546, 58447668, 20360168, 4098401, 19389175, + 15522534, 8372215, 5542595, 22851749 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 999628998628371, 1132836708493400, 2084741674517453, + 469343353015612, 678782988708035 +#else + 56546323, 14895632, 26814552, 16880582, 49628109, 31065071, + 64326972, 6993760, 49014979, 10114654 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2189427607417022, 699801937082607, 412764402319267, + 1478091893643349, 2244675696854460 +#else + 47001790, 32625013, 31422703, 10427861, 59998115, 6150668, + 38017109, 22025285, 25953724, 33448274 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1712292055966563, 204413590624874, 1405738637332841, + 408981300829763, 861082219276721 +#else + 62874467, 25515139, 57989738, 3045999, 2101609, 20947138, + 19390019, 6094296, 63793585, 12831124 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 508561155940631, 966928475686665, 2236717801150132, + 424543858577297, 2089272956986143 +#else + 51110167, 7578151, 5310217, 14408357, 33560244, 33329692, + 31575953, 6326196, 7381791, 31132593 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 221245220129925, 1156020201681217, 491145634799213, + 542422431960839, 828100817819207 +#else + 46206085, 3296810, 24736065, 17226043, 18374253, 7318640, + 6295303, 8082724, 51746375, 12339663 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 153756971240384, 1299874139923977, 393099165260502, + 1058234455773022, 996989038681183 +#else + 27724736, 2291157, 6088201, 19369634, 1792726, 5857634, + 13848414, 15768922, 25091167, 14856294 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 559086812798481, 573177704212711, 1629737083816402, + 1399819713462595, 1646954378266038 +#else + 48242193, 8331042, 24373479, 8541013, 66406866, 24284974, + 12927299, 20858939, 44926390, 24541532 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1887963056288059, 228507035730124, 1468368348640282, + 930557653420194, 613513962454686 +#else + 55685435, 28132841, 11632844, 3405020, 30536730, 21880393, + 39848098, 13866389, 30146206, 9142070 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1224529808187553, 1577022856702685, 2206946542980843, + 625883007765001, 279930793512158 +#else + 3924129, 18246916, 53291741, 23499471, 12291819, 32886066, + 39406089, 9326383, 58871006, 4171293 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1076287717051609, 1114455570543035, 187297059715481, + 250446884292121, 1885187512550540 +#else + 51186905, 16037936, 6713787, 16606682, 45496729, 2790943, + 26396185, 3731949, 345228, 28091483 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 902497362940219, 76749815795675, 1657927525633846, + 1420238379745202, 1340321636548352 +#else + 45781307, 13448258, 25284571, 1143661, 20614966, 24705045, + 2031538, 21163201, 50855680, 19972348 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1129576631190784, 1281994010027327, 996844254743018, + 257876363489249, 1150850742055018 +#else + 31016192, 16832003, 26371391, 19103199, 62081514, 14854136, + 17477601, 3842657, 28012650, 17149012 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 628740660038789, 1943038498527841, 467786347793886, + 1093341428303375, 235413859513003 +#else + 62033029, 9368965, 58546785, 28953529, 51858910, 6970559, + 57918991, 16292056, 58241707, 3507939 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 237425418909360, 469614029179605, 1512389769174935, + 1241726368345357, 441602891065214 +#else + 29439664, 3537914, 23333589, 6997794, 49553303, 22536363, + 51899661, 18503164, 57943934, 6580395 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1736417953058555, 726531315520508, 1833335034432527, + 1629442561574747, 624418919286085 +#else + 54923003, 25874643, 16438268, 10826160, 58412047, 27318820, + 17860443, 24280586, 65013061, 9304566 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1960754663920689, 497040957888962, 1909832851283095, + 1271432136996826, 2219780368020940 +#else + 20714545, 29217521, 29088194, 7406487, 11426967, 28458727, + 14792666, 18945815, 5289420, 33077305 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1537037379417136, 1358865369268262, 2130838645654099, + 828733687040705, 1999987652890901 +#else + 50443312, 22903641, 60948518, 20248671, 9192019, 31751970, + 17271489, 12349094, 26939669, 29802138 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 629042105241814, 1098854999137608, 887281544569320, + 1423102019874777, 7911258951561 +#else + 54218966, 9373457, 31595848, 16374215, 21471720, 13221525, + 39825369, 21205872, 63410057, 117886 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1811562332665373, 1501882019007673, 2213763501088999, + 359573079719636, 36370565049116 +#else + 22263325, 26994382, 3984569, 22379786, 51994855, 32987646, + 28311252, 5358056, 43789084, 541963 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 218907117361280, 1209298913016966, 1944312619096112, + 1130690631451061, 1342327389191701 +#else + 16259200, 3261970, 2309254, 18019958, 50223152, 28972515, + 24134069, 16848603, 53771797, 20002236 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1369976867854704, 1396479602419169, 1765656654398856, + 2203659200586299, 998327836117241 +#else + 9378160, 20414246, 44262881, 20809167, 28198280, 26310334, + 64709179, 32837080, 690425, 14876244 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2230701885562825, 1348173180338974, 2172856128624598, + 1426538746123771, 444193481326151 +#else + 24977353, 33240048, 58884894, 20089345, 28432342, 32378079, + 54040059, 21257083, 44727879, 6618998 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 784210426627951, 918204562375674, 1284546780452985, + 1324534636134684, 1872449409642708 +#else + 65570671, 11685645, 12944378, 13682314, 42719353, 19141238, + 8044828, 19737104, 32239828, 27901670 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 319638829540294, 596282656808406, 2037902696412608, + 1557219121643918, 341938082688094 +#else + 48505798, 4762989, 66182614, 8885303, 38696384, 30367116, + 9781646, 23204373, 32779358, 5095274 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1901860206695915, 2004489122065736, 1625847061568236, + 973529743399879, 2075287685312905 +#else + 34100715, 28339925, 34843976, 29869215, 9460460, 24227009, + 42507207, 14506723, 21639561, 30924196 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1371853944110545, 1042332820512553, 1949855697918254, + 1791195775521505, 37487364849293 +#else + 50707921, 20442216, 25239337, 15531969, 3987758, 29055114, + 65819361, 26690896, 17874573, 558605 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 687200189577855, 1082536651125675, 644224940871546, + 340923196057951, 343581346747396 +#else + 53508735, 10240080, 9171883, 16131053, 46239610, 9599699, + 33499487, 5080151, 2085892, 5119761 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2082717129583892, 27829425539422, 145655066671970, + 1690527209845512, 1865260509673478 +#else + 44903700, 31034903, 50727262, 414690, 42089314, 2170429, + 30634760, 25190818, 35108870, 27794547 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1059729620568824, 2163709103470266, 1440302280256872, + 1769143160546397, 869830310425069 +#else + 60263160, 15791201, 8550074, 32241778, 29928808, 21462176, + 27534429, 26362287, 44757485, 12961481 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1609516219779025, 777277757338817, 2101121130363987, + 550762194946473, 1905542338659364 +#else + 42616785, 23983660, 10368193, 11582341, 43711571, 31309144, + 16533929, 8206996, 36914212, 28394793 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2024821921041576, 426948675450149, 595133284085473, + 471860860885970, 600321679413000 +#else + 55987368, 30172197, 2307365, 6362031, 66973409, 8868176, + 50273234, 7031274, 7589640, 8945490 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 598474602406721, 1468128276358244, 1191923149557635, + 1501376424093216, 1281662691293476 +#else + 34956097, 8917966, 6661220, 21876816, 65916803, 17761038, + 7251488, 22372252, 24099108, 19098262 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1721138489890707, 1264336102277790, 433064545421287, + 1359988423149466, 1561871293409447 +#else + 5019539, 25646962, 4244126, 18840076, 40175591, 6453164, + 47990682, 20265406, 60876967, 23273695 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 719520245587143, 393380711632345, 132350400863381, + 1543271270810729, 1819543295798660 +#else + 10853575, 10721687, 26480089, 5861829, 44113045, 1972174, + 65242217, 22996533, 63745412, 27113307 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 396397949784152, 1811354474471839, 1362679985304303, + 2117033964846756, 498041172552279 +#else + 50106456, 5906789, 221599, 26991285, 7828207, 20305514, + 24362660, 31546264, 53242455, 7421391 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1812471844975748, 1856491995543149, 126579494584102, + 1036244859282620, 1975108050082550 +#else + 8139908, 27007935, 32257645, 27663886, 30375718, 1886181, + 45933756, 15441251, 28826358, 29431403 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 650623932407995, 1137551288410575, 2125223403615539, + 1725658013221271, 2134892965117796 +#else + 6267067, 9695052, 7709135, 16950835, 34239795, 31668296, + 14795159, 25714308, 13746020, 31812384 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 522584000310195, 1241762481390450, 1743702789495384, + 2227404127826575, 1686746002148897 +#else + 28584883, 7787108, 60375922, 18503702, 22846040, 25983196, + 63926927, 33190907, 4771361, 25134474 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 427904865186312, 1703211129693455, 1585368107547509, + 1436984488744336, 761188534613978 +#else + 24949256, 6376279, 39642383, 25379823, 48462709, 23623825, + 33543568, 21412737, 3569626, 11342593 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 318101947455002, 248138407995851, 1481904195303927, + 309278454311197, 1258516760217879 +#else + 26514970, 4740088, 27912651, 3697550, 19331575, 22082093, + 6809885, 4608608, 7325975, 18753361 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1275068538599310, 513726919533379, 349926553492294, + 688428871968420, 1702400196000666 +#else + 55490446, 19000001, 42787651, 7655127, 65739590, 5214311, + 39708324, 10258389, 49462170, 25367739 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1061864036265233, 961611260325381, 321859632700838, + 1045600629959517, 1985130202504038 +#else + 11431185, 15823007, 26570245, 14329124, 18029990, 4796082, + 35662685, 15580663, 9280358, 29580745 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1558816436882417, 1962896332636523, 1337709822062152, + 1501413830776938, 294436165831932 +#else + 66948081, 23228174, 44253547, 29249434, 46247496, 19933429, + 34297962, 22372809, 51563772, 4387440 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 818359826554971, 1862173000996177, 626821592884859, + 573655738872376, 1749691246745455 +#else + 46309467, 12194511, 3937617, 27748540, 39954043, 9340369, + 42594872, 8548136, 20617071, 26072431 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1988022651432119, 1082111498586040, 1834020786104821, + 1454826876423687, 692929915223122 +#else + 66170039, 29623845, 58394552, 16124717, 24603125, 27329039, + 53333511, 21678609, 24345682, 10325460 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2146513703733331, 584788900394667, 464965657279958, + 2183973639356127, 238371159456790 +#else + 47253587, 31985546, 44906155, 8714033, 14007766, 6928528, + 16318175, 32543743, 4766742, 3552007 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1129007025494441, 2197883144413266, 265142755578169, + 971864464758890, 1983715884903702 +#else + 45357481, 16823515, 1351762, 32751011, 63099193, 3950934, + 3217514, 14481909, 10988822, 29559670 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1291366624493075, 381456718189114, 1711482489312444, + 1815233647702022, 892279782992467 +#else + 15564307, 19242862, 3101242, 5684148, 30446780, 25503076, + 12677126, 27049089, 58813011, 13296004 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 444548969917454, 1452286453853356, 2113731441506810, + 645188273895859, 810317625309512 +#else + 57666574, 6624295, 36809900, 21640754, 62437882, 31497052, + 31521203, 9614054, 37108040, 12074673 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2242724082797924, 1373354730327868, 1006520110883049, + 2147330369940688, 1151816104883620 +#else + 4771172, 33419193, 14290748, 20464580, 27992297, 14998318, + 65694928, 31997715, 29832612, 17163397 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1745720200383796, 1911723143175317, 2056329390702074, + 355227174309849, 879232794371100 +#else + 7064884, 26013258, 47946901, 28486894, 48217594, 30641695, + 25825241, 5293297, 39986204, 13101589 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 163723479936298, 115424889803150, 1156016391581227, + 1894942220753364, 1970549419986329 +#else + 64810282, 2439669, 59642254, 1719964, 39841323, 17225986, + 32512468, 28236839, 36752793, 29363474 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 681981452362484, 267208874112496, 1374683991933094, + 638600984916117, 646178654558546 +#else + 37102324, 10162315, 33928688, 3981722, 50626726, 20484387, + 14413973, 9515896, 19568978, 9628812 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 13378654854251, 106237307029567, 1944412051589651, + 1841976767925457, 230702819835573 +#else + 33053803, 199357, 15894591, 1583059, 27380243, 28973997, + 49269969, 27447592, 60817077, 3437739 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 260683893467075, 854060306077237, 913639551980112, + 4704576840123, 280254810808712 +#else + 48129987, 3884492, 19469877, 12726490, 15913552, 13614290, + 44147131, 70103, 7463304, 4176122 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 715374893080287, 1173334812210491, 1806524662079626, + 1894596008000979, 398905715033393 +#else + 39984863, 10659916, 11482427, 17484051, 12771466, 26919315, + 34389459, 28231680, 24216881, 5944158 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 500026409727661, 1596431288195371, 1420380351989370, + 985211561521489, 392444930785633 +#else + 8894125, 7450974, 64444715, 23788679, 39028346, 21165316, + 19345745, 14680796, 11632993, 5847885 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2096421546958141, 1922523000950363, 789831022876840, + 427295144688779, 320923973161730 +#else + 26942781, 31239115, 9129563, 28647825, 26024104, 11769399, + 55590027, 6367193, 57381634, 4782139 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1927770723575450, 1485792977512719, 1850996108474547, + 551696031508956, 2126047405475647 +#else + 19916442, 28726022, 44198159, 22140040, 25606323, 27581991, + 33253852, 8220911, 6358847, 31680575 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2112099158080148, 742570803909715, 6484558077432, + 1951119898618916, 93090382703416 +#else + 801428, 31472730, 16569427, 11065167, 29875704, 96627, 7908388, + 29073952, 53570360, 1387154 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 383905201636970, 859946997631870, 855623867637644, + 1017125780577795, 794250831877809 +#else + 19646058, 5720633, 55692158, 12814208, 11607948, 12749789, + 14147075, 15156355, 45242033, 11835259 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 77571826285752, 999304298101753, 487841111777762, + 1038031143212339, 339066367948762 +#else + 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, + 26121523, 15467869, 40548314, 5052482 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 674994775520533, 266035846330789, 826951213393478, + 1405007746162285, 1781791018620876 +#else + 64091413, 10058205, 1980837, 3964243, 22160966, 12322533, + 60677741, 20936246, 12228556, 26550755 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1001412661522686, 348196197067298, 1666614366723946, + 888424995032760, 580747687801357 +#else + 32944382, 14922211, 44263970, 5188527, 21913450, 24834489, + 4001464, 13238564, 60994061, 8653814 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1939560076207777, 1409892634407635, 552574736069277, + 383854338280405, 190706709864139 +#else + 22865569, 28901697, 27603667, 21009037, 14348957, 8234005, + 24808405, 5719875, 28483275, 2841751 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2177087163428741, 1439255351721944, 1208070840382793, + 2230616362004769, 1396886392021913 +#else + 50687877, 32441126, 66781144, 21446575, 21886281, 18001658, + 65220897, 33238773, 19932057, 20815229 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 676962063230039, 1880275537148808, 2046721011602706, + 888463247083003, 1318301552024067 +#else + 55452759, 10087520, 58243976, 28018288, 47830290, 30498519, + 3999227, 13239134, 62331395, 19644223 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1466980508178206, 617045217998949, 652303580573628, + 757303753529064, 207583137376902 +#else + 1382174, 21859713, 17266789, 9194690, 53784508, 9720080, + 20403944, 11284705, 53095046, 3093229 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1511056752906902, 105403126891277, 493434892772846, + 1091943425335976, 1802717338077427 +#else + 16650902, 22516500, 66044685, 1570628, 58779118, 7352752, + 66806440, 16271224, 43059443, 26862581 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1853982405405128, 1878664056251147, 1528011020803992, + 1019626468153565, 1128438412189035 +#else + 45197768, 27626490, 62497547, 27994275, 35364760, 22769138, + 24123613, 15193618, 45456747, 16815042 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1963939888391106, 293456433791664, 697897559513649, + 985882796904380, 796244541237972 +#else + 57172930, 29264984, 41829040, 4372841, 2087473, 10399484, + 31870908, 14690798, 17361620, 11864968 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 416770998629779, 389655552427054, 1314476859406756, + 1749382513022778, 1161905598739491 +#else + 55801235, 6210371, 13206574, 5806320, 38091172, 19587231, + 54777658, 26067830, 41530403, 17313742 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1428358296490651, 1027115282420478, 304840698058337, + 441410174026628, 1819358356278573 +#else + 14668443, 21284197, 26039038, 15305210, 25515617, 4542480, + 10453892, 6577524, 9145645, 27110552 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 204943430200135, 1554861433819175, 216426658514651, + 264149070665950, 2047097371738319 +#else + 5974855, 3053895, 57675815, 23169240, 35243739, 3225008, + 59136222, 3936127, 61456591, 30504127 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1934415182909034, 1393285083565062, 516409331772960, + 1157690734993892, 121039666594268 +#else + 30625386, 28825032, 41552902, 20761565, 46624288, 7695098, + 17097188, 17250936, 39109084, 1803631 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 662035583584445, 286736105093098, 1131773000510616, + 818494214211439, 472943792054479 +#else + 63555773, 9865098, 61880298, 4272700, 61435032, 16864731, + 14911343, 12196514, 45703375, 7047411 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 665784778135882, 1893179629898606, 808313193813106, + 276797254706413, 1563426179676396 +#else + 20093258, 9920966, 55970670, 28210574, 13161586, 12044805, + 34252013, 4124600, 34765036, 23296865 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 945205108984232, 526277562959295, 1324180513733566, + 1666970227868664, 153547609289173 +#else + 46320040, 14084653, 53577151, 7842146, 19119038, 19731827, + 4752376, 24839792, 45429205, 2288037 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2031433403516252, 203996615228162, 170487168837083, + 981513604791390, 843573964916831 +#else + 40289628, 30270716, 29965058, 3039786, 52635099, 2540456, + 29457502, 14625692, 42289247, 12570231 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1476570093962618, 838514669399805, 1857930577281364, + 2017007352225784, 317085545220047 +#else + 66045306, 22002608, 16920317, 12494842, 1278292, 27685323, + 45948920, 30055751, 55134159, 4724942 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1461557121912842, 1600674043318359, 2157134900399597, + 1670641601940616, 127765583803283 +#else + 17960970, 21778898, 62967895, 23851901, 58232301, 32143814, + 54201480, 24894499, 37532563, 1903855 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1293543509393474, 2143624609202546, 1058361566797508, + 214097127393994, 946888515472729 +#else + 23134274, 19275300, 56426866, 31942495, 20684484, 15770816, + 54119114, 3190295, 26955097, 14109738 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 357067959932916, 1290876214345711, 521245575443703, + 1494975468601005, 800942377643885 +#else + 15308788, 5320727, 36995055, 19235554, 22902007, 7767164, + 29425325, 22276870, 31960941, 11934971 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 566116659100033, 820247422481740, 994464017954148, + 327157611686365, 92591318111744 +#else + 39713153, 8435795, 4109644, 12222639, 42480996, 14818668, + 20638173, 4875028, 10491392, 1379718 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 617256647603209, 1652107761099439, 1857213046645471, + 1085597175214970, 817432759830522 +#else + 53949449, 9197840, 3875503, 24618324, 65725151, 27674630, + 33518458, 16176658, 21432314, 12180697 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 771808161440705, 1323510426395069, 680497615846440, + 851580615547985, 1320806384849017 +#else + 55321537, 11500837, 13787581, 19721842, 44678184, 10140204, + 1465425, 12689540, 56807545, 19681548 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1219260086131915, 647169006596815, 79601124759706, + 2161724213426748, 404861897060198 +#else + 5414091, 18168391, 46101199, 9643569, 12834970, 1186149, + 64485948, 32212200, 26128230, 6032912 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1327968293887866, 1335500852943256, 1401587164534264, + 558137311952440, 1551360549268902 +#else + 40771450, 19788269, 32496024, 19900513, 17847800, 20885276, + 3604024, 8316894, 41233830, 23117073 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 417621685193956, 1429953819744454, 396157358457099, + 1940470778873255, 214000046234152 +#else + 3296484, 6223048, 24680646, 21307972, 44056843, 5903204, + 58246567, 28915267, 12376616, 3188849 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1268047918491973, 2172375426948536, 1533916099229249, + 1761293575457130, 1590622667026765 +#else + 29190469, 18895386, 27549112, 32370916, 3520065, 22857131, + 32049514, 26245319, 50999629, 23702124 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1627072914981959, 2211603081280073, 1912369601616504, + 1191770436221309, 2187309757525860 +#else + 52364359, 24245275, 735817, 32955454, 46701176, 28496527, + 25246077, 17758763, 18640740, 32593455 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1149147819689533, 378692712667677, 828475842424202, + 2218619146419342, 70688125792186 +#else + 60180029, 17123636, 10361373, 5642961, 4910474, 12345252, + 35470478, 33060001, 10530746, 1053335 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1299739417079761, 1438616663452759, 1536729078504412, + 2053896748919838, 1008421032591246 +#else + 37842897, 19367626, 53570647, 21437058, 47651804, 22899047, + 35646494, 30605446, 24018830, 15026644 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2040723824657366, 399555637875075, 632543375452995, + 872649937008051, 1235394727030233 +#else + 44516310, 30409154, 64819587, 5953842, 53668675, 9425630, + 25310643, 13003497, 64794073, 18408815 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2211311599327900, 2139787259888175, 938706616835350, + 12609661139114, 2081897930719789 +#else + 39688860, 32951110, 59064879, 31885314, 41016598, 13987818, + 39811242, 187898, 43942445, 31022696 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1324994503390450, 336982330582631, 1183998925654177, + 1091654665913274, 48727673971319 +#else + 45364466, 19743956, 1844839, 5021428, 56674465, 17642958, + 9716666, 16266922, 62038647, 726098 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1845522914617879, 1222198248335542, 150841072760134, + 1927029069940982, 1189913404498011 +#else + 29370903, 27500434, 7334070, 18212173, 9385286, 2247707, + 53446902, 28714970, 30007387, 17731091 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1079559557592645, 2215338383666441, 1903569501302605, + 49033973033940, 305703433934152 +#else + 66172485, 16086690, 23751945, 33011114, 65941325, 28365395, + 9137108, 730663, 9835848, 4555336 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 94653405416909, 1386121349852999, 1062130477891762, + 36553947479274, 833669648948846 +#else + 43732429, 1410445, 44855111, 20654817, 30867634, 15826977, + 17693930, 544696, 55123566, 12422645 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1432015813136298, 440364795295369, 1395647062821501, + 1976874522764578, 934452372723352 +#else + 31117226, 21338698, 53606025, 6561946, 57231997, 20796761, + 61990178, 29457725, 29120152, 13924425 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1296625309219774, 2068273464883862, 1858621048097805, + 1492281814208508, 2235868981918946 +#else + 49707966, 19321222, 19675798, 30819676, 56101901, 27695611, + 57724924, 22236731, 7240930, 33317044 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1490330266465570, 1858795661361448, 1436241134969763, + 294573218899647, 1208140011028933 +#else + 35747106, 22207651, 52101416, 27698213, 44655523, 21401660, + 1222335, 4389483, 3293637, 18002689 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1282462923712748, 741885683986255, 2027754642827561, + 518989529541027, 1826610009555945 +#else + 50424044, 19110186, 11038543, 11054958, 53307689, 30215898, + 42789283, 7733546, 12796905, 27218610 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1525827120027511, 723686461809551, 1597702369236987, + 244802101764964, 1502833890372311 +#else + 58349431, 22736595, 41689999, 10783768, 36493307, 23807620, + 38855524, 3647835, 3222231, 22393970 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 113622036244513, 1233740067745854, 674109952278496, + 2114345180342965, 166764512856263 +#else + 18606113, 1693100, 41660478, 18384159, 4112352, 10045021, + 23603893, 31506198, 59558087, 2484984 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2041668749310338, 2184405322203901, 1633400637611036, + 2110682505536899, 2048144390084644 +#else + 9255298, 30423235, 54952701, 32550175, 13098012, 24339566, + 16377219, 31451620, 47306788, 30519729 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 503058759232932, 760293024620937, 2027152777219493, + 666858468148475, 1539184379870952 +#else + 44379556, 7496159, 61366665, 11329248, 19991973, 30206930, + 35390715, 9936965, 37011176, 22935634 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1916168475367211, 915626432541343, 883217071712575, + 363427871374304, 1976029821251593 +#else + 21878571, 28553135, 4338335, 13643897, 64071999, 13160959, + 19708896, 5415497, 59748361, 29445138 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 678039535434506, 570587290189340, 1605302676614120, + 2147762562875701, 1706063797091704 +#else + 27736842, 10103576, 12500508, 8502413, 63695848, 23920873, + 10436917, 32004156, 43449720, 25422331 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1439489648586438, 2194580753290951, 832380563557396, + 561521973970522, 584497280718389 +#else + 19492550, 21450067, 37426887, 32701801, 63900692, 12403436, + 30066266, 8367329, 13243957, 8709688 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 187989455492609, 681223515948275, 1933493571072456, + 1872921007304880, 488162364135671 +#else + 12015105, 2801261, 28198131, 10151021, 24818120, 28811299, + 55914672, 27908697, 5150967, 7274186 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1413466089534451, 410844090765630, 1397263346404072, + 408227143123410, 1594561803147811 +#else + 2831347, 21062286, 1478974, 6122054, 23825128, 20820846, + 31097298, 6083058, 31021603, 23760822 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2102170800973153, 719462588665004, 1479649438510153, + 1097529543970028, 1302363283777685 +#else + 64578913, 31324785, 445612, 10720828, 53259337, 22048494, + 43601132, 16354464, 15067285, 19406725 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 942065717847195, 1069313679352961, 2007341951411051, + 70973416446291, 1419433790163706 +#else + 7840923, 14037873, 33744001, 15934015, 66380651, 29911725, + 21403987, 1057586, 47729402, 21151211 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1146565545556377, 1661971299445212, 406681704748893, + 564452436406089, 1109109865829139 +#else + 915865, 17085158, 15608284, 24765302, 42751837, 6060029, + 49737545, 8410996, 59888403, 16527024 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2214421081775077, 1165671861210569, 1890453018796184, + 3556249878661, 442116172656317 +#else + 32922597, 32997445, 20336073, 17369864, 10903704, 28169945, + 16957573, 52992, 23834301, 6588044 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 753830546620811, 1666955059895019, 1530775289309243, + 1119987029104146, 2164156153857580 +#else + 32752011, 11232950, 3381995, 24839566, 22652987, 22810329, + 17159698, 16689107, 46794284, 32248439 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 615171919212796, 1523849404854568, 854560460547503, + 2067097370290715, 1765325848586042 +#else + 62419196, 9166775, 41398568, 22707125, 11576751, 12733943, + 7924251, 30802151, 1976122, 26305405 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1094538949313667, 1796592198908825, 870221004284388, + 2025558921863561, 1699010892802384 +#else + 21251203, 16309901, 64125849, 26771309, 30810596, 12967303, + 156041, 30183180, 12331344, 25317235 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1951351290725195, 1916457206844795, 198025184438026, + 1909076887557595, 1938542290318919 +#else + 8651595, 29077400, 51023227, 28557437, 13002506, 2950805, + 29054427, 28447462, 10008135, 28886531 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1014323197538413, 869150639940606, 1756009942696599, + 1334952557375672, 1544945379082874 +#else + 31486061, 15114593, 52847614, 12951353, 14369431, 26166587, + 16347320, 19892343, 8684154, 23021480 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 764055910920305, 1603590757375439, 146805246592357, + 1843313433854297, 954279890114939 +#else + 19443825, 11385320, 24468943, 23895364, 43189605, 2187568, + 40845657, 27467510, 31316347, 14219878 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 80113526615750, 764536758732259, 1055139345100233, + 469252651759390, 617897512431515 +#else + 38514374, 1193784, 32245219, 11392485, 31092169, 15722801, + 27146014, 6992409, 29126555, 9207390 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 74497112547268, 740094153192149, 1745254631717581, + 727713886503130, 1283034364416928 +#else + 32382916, 1110093, 18477781, 11028262, 39697101, 26006320, + 62128346, 10843781, 59151264, 19118701 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 525892105991110, 1723776830270342, 1476444848991936, + 573789489857760, 133864092632978 +#else + 2814918, 7836403, 27519878, 25686276, 46214848, 22000742, + 45614304, 8550129, 28346258, 1994730 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 542611720192581, 1986812262899321, 1162535242465837, + 481498966143464, 544600533583622 +#else + 47530565, 8085544, 53108345, 29605809, 2785837, 17323125, + 47591912, 7174893, 22628102, 8115180 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 64123227344372, 1239927720647794, 1360722983445904, + 222610813654661, 62429487187991 +#else + 36703732, 955510, 55975026, 18476362, 34661776, 20276352, + 41457285, 3317159, 57165847, 930271 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1793193323953132, 91096687857833, 70945970938921, + 2158587638946380, 1537042406482111 +#else + 51805164, 26720662, 28856489, 1357446, 23421993, 1057177, + 24091212, 32165462, 44343487, 22903716 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1895854577604609, 1394895708949416, 1728548428495944, + 1140864900240149, 563645333603061 +#else + 44357633, 28250434, 54201256, 20785565, 51297352, 25757378, + 52269845, 17000211, 65241845, 8398969 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 141358280486863, 91435889572504, 1087208572552643, + 1829599652522921, 1193307020643647 +#else + 35139535, 2106402, 62372504, 1362500, 12813763, 16200670, + 22981545, 27263159, 18009407, 17781660 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1611230858525381, 950720175540785, 499589887488610, + 2001656988495019, 88977313255908 +#else + 49887941, 24009210, 39324209, 14166834, 29815394, 7444469, + 29551787, 29827013, 19288548, 1325865 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1189080501479658, 2184348804772597, 1040818725742319, + 2018318290311834, 1712060030915354 +#else + 15100138, 17718680, 43184885, 32549333, 40658671, 15509407, + 12376730, 30075286, 33166106, 25511682 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 873966876953756, 1090638350350440, 1708559325189137, + 672344594801910, 1320437969700239 +#else + 20909212, 13023121, 57899112, 16251777, 61330449, 25459517, + 12412150, 10018715, 2213263, 19676059 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1508590048271766, 1131769479776094, 101550868699323, + 428297785557897, 561791648661744 +#else + 32529814, 22479743, 30361438, 16864679, 57972923, 1513225, + 22922121, 6382134, 61341936, 8371347 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 756417570499462, 237882279232602, 2136263418594016, + 1701968045454886, 703713185137472 +#else + 9923462, 11271500, 12616794, 3544722, 37110496, 31832805, + 12891686, 25361300, 40665920, 10486143 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1781187809325462, 1697624151492346, 1381393690939988, + 175194132284669, 1483054666415238 +#else + 44511638, 26541766, 8587002, 25296571, 4084308, 20584370, + 361725, 2610596, 43187334, 22099236 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2175517777364616, 708781536456029, 955668231122942, + 1967557500069555, 2021208005604118 +#else + 5408392, 32417741, 62139741, 10561667, 24145918, 14240566, + 31319731, 29318891, 19985174, 30118346 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1115135966606887, 224217372950782, 915967306279222, + 593866251291540, 561747094208006 +#else + 53114407, 16616820, 14549246, 3341099, 32155958, 13648976, + 49531796, 8849296, 65030, 8370684 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1443163092879439, 391875531646162, 2180847134654632, + 464538543018753, 1594098196837178 +#else + 58787919, 21504805, 31204562, 5839400, 46481576, 32497154, + 47665921, 6922163, 12743482, 23753914 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 850858855888869, 319436476624586, 327807784938441, + 740785849558761, 17128415486016 +#else + 64747493, 12678784, 28815050, 4759974, 43215817, 4884716, + 23783145, 11038569, 18800704, 255233 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2132756334090067, 536247820155645, 48907151276867, + 608473197600695, 1261689545022784 +#else + 61839187, 31780545, 13957885, 7990715, 23132995, 728773, + 13393847, 9066957, 19258688, 18800639 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1525176236978354, 974205476721062, 293436255662638, + 148269621098039, 137961998433963 +#else + 64172210, 22726896, 56676774, 14516792, 63468078, 4372540, + 35173943, 2209389, 65584811, 2055793 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1121075518299410, 2071745529082111, 1265567917414828, + 1648196578317805, 496232102750820 +#else + 580882, 16705327, 5468415, 30871414, 36182444, 18858431, + 59905517, 24560042, 37087844, 7394434 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 122321229299801, 1022922077493685, 2001275453369484, + 2017441881607947, 993205880778002 +#else + 23838809, 1822728, 51370421, 15242726, 8318092, 29821328, + 45436683, 30062226, 62287122, 14799920 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 654925550560074, 1168810995576858, 575655959430926, + 905758704861388, 496774564663534 +#else + 13345610, 9759151, 3371034, 17416641, 16353038, 8577942, + 31129804, 13496856, 58052846, 7402517 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1954109525779738, 2117022646152485, 338102630417180, + 1194140505732026, 107881734943492 +#else + 2286874, 29118501, 47066405, 31546095, 53412636, 5038121, + 11006906, 17794080, 8205060, 1607563 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1714785840001267, 2036500018681589, 1876380234251966, + 2056717182974196, 1645855254384642 +#else + 14414067, 25552300, 3331829, 30346215, 22249150, 27960244, + 18364660, 30647474, 30019586, 24525154 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 106431476499341, 62482972120563, 1513446655109411, + 807258751769522, 538491469114 +#else + 39420813, 1585952, 56333811, 931068, 37988643, 22552112, + 52698034, 12029092, 9944378, 8024 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2002850762893643, 1243624520538135, 1486040410574605, + 2184752338181213, 378495998083531 +#else + 4368715, 29844802, 29874199, 18531449, 46878477, 22143727, + 50994269, 32555346, 58966475, 5640029 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 922510868424903, 1089502620807680, 402544072617374, + 1131446598479839, 1290278588136533 +#else + 10299591, 13746483, 11661824, 16234854, 7630238, 5998374, + 9809887, 16859868, 15219797, 19226649 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1867998812076769, 715425053580701, 39968586461416, + 2173068014586163, 653822651801304 +#else + 27425505, 27835351, 3055005, 10660664, 23458024, 595578, + 51710259, 32381236, 48766680, 9742716 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 162892278589453, 182585796682149, 75093073137630, + 497037941226502, 133871727117371 +#else + 6744077, 2427284, 26042789, 2720740, 66260958, 1118973, + 32324614, 7406442, 12420155, 1994844 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1914596576579670, 1608999621851578, 1987629837704609, + 1519655314857977, 1819193753409464 +#else + 14012502, 28529712, 48724410, 23975962, 40623521, 29617992, + 54075385, 22644628, 24319928, 27108099 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1949315551096831, 1069003344994464, 1939165033499916, + 1548227205730856, 1933767655861407 +#else + 16412671, 29047065, 10772640, 15929391, 50040076, 28895810, + 10555944, 23070383, 37006495, 28815383 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1730519386931635, 1393284965610134, 1597143735726030, + 416032382447158, 1429665248828629 +#else + 22397363, 25786748, 57815702, 20761563, 17166286, 23799296, + 39775798, 6199365, 21880021, 21303672 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 360275475604565, 547835731063078, 215360904187529, + 596646739879007, 332709650425085 +#else + 62825557, 5368522, 35991846, 8163388, 36785801, 3209127, + 16557151, 8890729, 8840445, 4957760 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 47602113726801, 1522314509708010, 437706261372925, + 814035330438027, 335930650933545 +#else + 51661137, 709326, 60189418, 22684253, 37330941, 6522331, + 45388683, 12130071, 52312361, 5005756 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1291597595523886, 1058020588994081, 402837842324045, + 1363323695882781, 2105763393033193 +#else + 64994094, 19246303, 23019041, 15765735, 41839181, 6002751, + 10183197, 20315106, 50713577, 31378319 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 109521982566564, 1715257748585139, 1112231216891516, + 2046641005101484, 134249157157013 +#else + 48083108, 1632004, 13466291, 25559332, 43468412, 16573536, + 35094956, 30497327, 22208661, 2000468 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2156991030936798, 2227544497153325, 1869050094431622, + 754875860479115, 1754242344267058 +#else + 3065054, 32141671, 41510189, 33192999, 49425798, 27851016, + 58944651, 11248526, 63417650, 26140247 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1846089562873800, 98894784984326, 1412430299204844, + 171351226625762, 1100604760929008 +#else + 10379208, 27508878, 8877318, 1473647, 37817580, 21046851, + 16690914, 2553332, 63976176, 16400288 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 84172382130492, 499710970700046, 425749630620778, + 1762872794206857, 612842602127960 +#else + 15716668, 1254266, 48636174, 7446273, 58659946, 6344163, + 45011593, 26268851, 26894936, 9132066 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 868309334532756, 1703010512741873, 1952690008738057, + 4325269926064, 2071083554962116 +#else + 24158868, 12938817, 11085297, 25376834, 39045385, 29097348, + 36532400, 64451, 60291780, 30861549 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 523094549451158, 401938899487815, 1407690589076010, + 2022387426254453, 158660516411257 +#else + 13488534, 7794716, 22236231, 5989356, 25426474, 20976224, + 2350709, 30135921, 62420857, 2364225 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 612867287630009, 448212612103814, 571629077419196, + 1466796750919376, 1728478129663858 +#else + 16335033, 9132434, 25640582, 6678888, 1725628, 8517937, + 55301840, 21856974, 15445874, 25756331 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1723848973783452, 2208822520534681, 1718748322776940, + 1974268454121942, 1194212502258141 +#else + 29004188, 25687351, 28661401, 32914020, 54314860, 25611345, + 31863254, 29418892, 66830813, 17795152 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1254114807944608, 977770684047110, 2010756238954993, + 1783628927194099, 1525962994408256 +#else + 60986784, 18687766, 38493958, 14569918, 56250865, 29962602, + 10343411, 26578142, 37280576, 22738620 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 232464058235826, 1948628555342434, 1835348780427694, + 1031609499437291, 64472106918373 +#else + 27081650, 3463984, 14099042, 29036828, 1616302, 27348828, + 29542635, 15372179, 17293797, 960709 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 767338676040683, 754089548318405, 1523192045639075, + 435746025122062, 512692508440385 +#else + 20263915, 11434237, 61343429, 11236809, 13505955, 22697330, + 50997518, 6493121, 47724353, 7639713 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1255955808701983, 1700487367990941, 1166401238800299, + 1175121994891534, 1190934801395380 +#else + 64278047, 18715199, 25403037, 25339236, 58791851, 17380732, + 18006286, 17510682, 29994676, 17746311 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 349144008168292, 1337012557669162, 1475912332999108, + 1321618454900458, 47611291904320 +#else + 9769828, 5202651, 42951466, 19923039, 39057860, 21992807, + 42495722, 19693649, 35924288, 709463 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 877519947135419, 2172838026132651, 272304391224129, + 1655143327559984, 886229406429814 +#else + 12286395, 13076066, 45333675, 32377809, 42105665, 4057651, + 35090736, 24663557, 16102006, 13205847 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 375806028254706, 214463229793940, 572906353144089, + 572168269875638, 697556386112979 +#else + 13733362, 5599946, 10557076, 3195751, 61550873, 8536969, + 41568694, 8525971, 10151379, 10394400 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1168827102357844, 823864273033637, 2071538752104697, + 788062026895924, 599578340743362 +#else + 4024660, 17416881, 22436261, 12276534, 58009849, 30868332, + 19698228, 11743039, 33806530, 8934413 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1948116082078088, 2054898304487796, 2204939184983900, + 210526805152138, 786593586607626 +#else + 51229064, 29029191, 58528116, 30620370, 14634844, 32856154, + 57659786, 3137093, 55571978, 11721157 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1915320147894736, 156481169009469, 655050471180417, + 592917090415421, 2165897438660879 +#else + 17555920, 28540494, 8268605, 2331751, 44370049, 9761012, + 9319229, 8835153, 57903375, 32274386 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1726336468579724, 1119932070398949, 1929199510967666, + 33918788322959, 1836837863503150 +#else + 66647436, 25724417, 20614117, 16688288, 59594098, 28747312, + 22300303, 505429, 6108462, 27371017 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 829996854845988, 217061778005138, 1686565909803640, + 1346948817219846, 1723823550730181 +#else + 62038564, 12367916, 36445330, 3234472, 32617080, 25131790, + 29880582, 20071101, 40210373, 25686972 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 384301494966394, 687038900403062, 2211195391021739, + 254684538421383, 1245698430589680 +#else + 35133562, 5726538, 26934134, 10237677, 63935147, 32949378, + 24199303, 3795095, 7592688, 18562353 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1247567493562688, 1978182094455847, 183871474792955, + 806570235643435, 288461518067916 +#else + 21594432, 18590204, 17466407, 29477210, 32537083, 2739898, + 6407723, 12018833, 38852812, 4298411 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1449077384734201, 38285445457996, 2136537659177832, + 2146493000841573, 725161151123125 +#else + 46458361, 21592935, 39872588, 570497, 3767144, 31836892, + 13891941, 31985238, 13717173, 10805743 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1201928866368855, 800415690605445, 1703146756828343, + 997278587541744, 1858284414104014 +#else + 52432215, 17910135, 15287173, 11927123, 24177847, 25378864, + 66312432, 14860608, 40169934, 27690595 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 356468809648877, 782373916933152, 1718002439402870, + 1392222252219254, 663171266061951 +#else + 12962541, 5311799, 57048096, 11658279, 18855286, 25600231, + 13286262, 20745728, 62727807, 9882021 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 759628738230460, 1012693474275852, 353780233086498, + 246080061387552, 2030378857679162 +#else + 18512060, 11319350, 46985740, 15090308, 18818594, 5271736, + 44380960, 3666878, 43141434, 30255002 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2040672435071076, 888593182036908, 1298443657189359, + 1804780278521327, 354070726137060 +#else + 60319844, 30408388, 16192428, 13241070, 15898607, 19348318, + 57023983, 26893321, 64705764, 5276064 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1894938527423184, 1463213041477277, 474410505497651, + 247294963033299, 877975941029128 +#else + 30169808, 28236784, 26306205, 21803573, 27814963, 7069267, + 7152851, 3684982, 1449224, 13082861 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 207937160991127, 12966911039119, 820997788283092, + 1010440472205286, 1701372890140810 +#else + 10342807, 3098505, 2119311, 193222, 25702612, 12233820, + 23697382, 15056736, 46092426, 25352431 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 218882774543183, 533427444716285, 1233243976733245, + 435054256891319, 1509568989549904 +#else + 33958735, 3261607, 22745853, 7948688, 19370557, 18376767, + 40936887, 6482813, 56808784, 22494330 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1888838535711826, 1052177758340622, 1213553803324135, + 169182009127332, 463374268115872 +#else + 32869458, 28145887, 25609742, 15678670, 56421095, 18083360, + 26112420, 2521008, 44444576, 6904814 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 299137589460312, 1594371588983567, 868058494039073, + 257771590636681, 1805012993142921 +#else + 29506904, 4457497, 3377935, 23757988, 36598817, 12935079, + 1561737, 3841096, 38105225, 26896789 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1806842755664364, 2098896946025095, 1356630998422878, + 1458279806348064, 347755825962072 +#else + 10340844, 26924055, 48452231, 31276001, 12621150, 20215377, + 30878496, 21730062, 41524312, 5181965 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1402334161391744, 1560083671046299, 1008585416617747, + 1147797150908892, 1420416683642459 +#else + 25940096, 20896407, 17324187, 23247058, 58437395, 15029093, + 24396252, 17103510, 64786011, 21165857 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 665506704253369, 273770475169863, 799236974202630, + 848328990077558, 1811448782807931 +#else + 45343161, 9916822, 65808455, 4079497, 66080518, 11909558, + 1782390, 12641087, 20603771, 26992690 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1468412523962641, 771866649897997, 1931766110147832, + 799561180078482, 524837559150077 +#else + 48226577, 21881051, 24849421, 11501709, 13161720, 28785558, + 1925522, 11914390, 4662781, 7820689 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2223212657821850, 630416247363666, 2144451165500328, + 816911130947791, 1024351058410032 +#else + 12241050, 33128450, 8132690, 9393934, 32846760, 31954812, + 29749455, 12172924, 16136752, 15264020 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1266603897524861, 156378408858100, 1275649024228779, + 447738405888420, 253186462063095 +#else + 56758909, 18873868, 58896884, 2330219, 49446315, 19008651, + 10658212, 6671822, 19012087, 3772772 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2022215964509735, 136144366993649, 1800716593296582, + 1193970603800203, 871675847064218 +#else + 3753511, 30133366, 10617073, 2028709, 14841030, 26832768, + 28718731, 17791548, 20527770, 12988982 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1862751661970328, 851596246739884, 1519315554814041, + 1542798466547449, 1417975335901520 +#else + 52286360, 27757162, 63400876, 12689772, 66209881, 22639565, + 42925817, 22989488, 3299664, 21129479 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1228168094547481, 334133883362894, 587567568420081, + 433612590281181, 603390400373205 +#else + 50331161, 18301130, 57466446, 4978982, 3308785, 8755439, + 6943197, 6461331, 41525717, 8991217 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 121893973206505, 1843345804916664, 1703118377384911, + 497810164760654, 101150811654673 +#else + 49882601, 1816361, 65435576, 27467992, 31783887, 25378441, + 34160718, 7417949, 36866577, 1507264 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 458346255946468, 290909935619344, 1452768413850679, + 550922875254215, 1537286854336538 +#else + 29692644, 6829891, 56610064, 4334895, 20945975, 21647936, + 38221255, 8209390, 14606362, 22907359 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 584322311184395, 380661238802118, 114839394528060, + 655082270500073, 2111856026034852 +#else + 63627275, 8707080, 32188102, 5672294, 22096700, 1711240, + 34088169, 9761486, 4170404, 31469107 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 996965581008991, 2148998626477022, 1012273164934654, + 1073876063914522, 1688031788934939 +#else + 55521375, 14855944, 62981086, 32022574, 40459774, 15084045, + 22186522, 16002000, 52832027, 25153633 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 923487018849600, 2085106799623355, 528082801620136, + 1606206360876188, 735907091712524 +#else + 62297408, 13761028, 35404987, 31070512, 63796392, 7869046, + 59995292, 23934339, 13240844, 10965870 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1697697887804317, 1335343703828273, 831288615207040, + 949416685250051, 288760277392022 +#else + 59366301, 25297669, 52340529, 19898171, 43876480, 12387165, + 4498947, 14147411, 29514390, 4302863 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1419122478109648, 1325574567803701, 602393874111094, + 2107893372601700, 1314159682671307 +#else + 53695440, 21146572, 20757301, 19752600, 14785142, 8976368, + 62047588, 31410058, 17846987, 19582505 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2201150872731804, 2180241023425241, 97663456423163, + 1633405770247824, 848945042443986 +#else + 64864412, 32799703, 62511833, 32488122, 60861691, 1455298, + 45461136, 24339642, 61886162, 12650266 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1173339555550611, 818605084277583, 47521504364289, + 924108720564965, 735423405754506 +#else + 57202067, 17484121, 21134159, 12198166, 40044289, 708125, + 387813, 13770293, 47974538, 10958662 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 830104860549448, 1886653193241086, 1600929509383773, + 1475051275443631, 286679780900937 +#else + 22470984, 12369526, 23446014, 28113323, 45588061, 23855708, + 55336367, 21979976, 42025033, 4271861 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1577111294832995, 1030899169768747, 144900916293530, + 1964672592979567, 568390100955250 +#else + 41939299, 23500789, 47199531, 15361594, 61124506, 2159191, + 75375, 29275903, 34582642, 8469672 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 278388655910247, 487143369099838, 927762205508727, + 181017540174210, 1616886700741287 +#else + 15854951, 4148314, 58214974, 7259001, 11666551, 13824734, + 36577666, 2697371, 24154791, 24093489 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1191033906638969, 940823957346562, 1606870843663445, + 861684761499847, 658674867251089 +#else + 15446137, 17747788, 29759746, 14019369, 30811221, 23944241, + 35526855, 12840103, 24913809, 9815020 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1875032594195546, 1427106132796197, 724736390962158, + 901860512044740, 635268497268760 +#else + 62399578, 27940162, 35267365, 21265538, 52665326, 10799413, + 58005188, 13438768, 18735128, 9466238 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 622869792298357, 1903919278950367, 1922588621661629, + 1520574711600434, 1087100760174640 +#else + 11933045, 9281483, 5081055, 28370608, 64480701, 28648802, + 59381042, 22658328, 44380208, 16199063 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 25465949416618, 1693639527318811, 1526153382657203, + 125943137857169, 145276964043999 +#else + 14576810, 379472, 40322331, 25237195, 37682355, 22741457, + 67006097, 1876698, 30801119, 2164795 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 214739857969358, 920212862967915, 1939901550972269, + 1211862791775221, 85097515720120 +#else + 15995086, 3199873, 13672555, 13712240, 47730029, 28906785, + 54027253, 18058162, 53616056, 1268051 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2006245852772938, 734762734836159, 254642929763427, + 1406213292755966, 239303749517686 +#else + 56818250, 29895392, 63822271, 10948817, 23037027, 3794475, + 63638526, 20954210, 50053494, 3565903 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1619678837192149, 1919424032779215, 1357391272956794, + 1525634040073113, 1310226789796241 +#else + 29210069, 24135095, 61189071, 28601646, 10834810, 20226706, + 50596761, 22733718, 39946641, 19523900 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1040763709762123, 1704449869235352, 605263070456329, + 1998838089036355, 1312142911487502 +#else + 53946955, 15508587, 16663704, 25398282, 38758921, 9019122, + 37925443, 29785008, 2244110, 19552453 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1996723311435669, 1844342766567060, 985455700466044, + 1165924681400960, 311508689870129 +#else + 61955989, 29753495, 57802388, 27482848, 16243068, 14684434, + 41435776, 17373631, 13491505, 4641841 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 43173156290518, 2202883069785309, 1137787467085917, + 1733636061944606, 1394992037553852 +#else + 10813398, 643330, 47920349, 32825515, 30292061, 16954354, + 27548446, 25833190, 14476988, 20787001 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 670078326344559, 555655025059356, 471959386282438, + 2141455487356409, 849015953823125 +#else + 10292079, 9984945, 6481436, 8279905, 59857350, 7032742, + 27282937, 31910173, 39196053, 12651323 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2197214573372804, 794254097241315, 1030190060513737, + 267632515541902, 2040478049202624 +#else + 35923332, 32741048, 22271203, 11835308, 10201545, 15351028, + 17099662, 3988035, 21721536, 30405492 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1812516004670529, 1609256702920783, 1706897079364493, + 258549904773295, 996051247540686 +#else + 10202177, 27008593, 35735631, 23979793, 34958221, 25434748, + 54202543, 3852693, 13216206, 14842320 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1540374301420584, 1764656898914615, 1810104162020396, + 923808779163088, 664390074196579 +#else + 51293224, 22953365, 60569911, 26295436, 60124204, 26972653, + 35608016, 13765823, 39674467, 9900183 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1323460699404750, 1262690757880991, 871777133477900, + 1060078894988977, 1712236889662886 +#else + 14465486, 19721101, 34974879, 18815558, 39665676, 12990491, + 33046193, 15796406, 60056998, 25514317 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1696163952057966, 1391710137550823, 608793846867416, + 1034391509472039, 1780770894075012 +#else + 30924398, 25274812, 6359015, 20738097, 16508376, 9071735, + 41620263, 15413634, 9524356, 26535554 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1367603834210841, 2131988646583224, 890353773628144, + 1908908219165595, 270836895252891 +#else + 12274201, 20378885, 32627640, 31769106, 6736624, 13267305, + 5237659, 28444949, 15663515, 4035784 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 597536315471731, 40375058742586, 1942256403956049, + 1185484645495932, 312666282024145 +#else + 64157555, 8903984, 17349946, 601635, 50676049, 28941875, + 53376124, 17665097, 44850385, 4659090 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1919411405316294, 1234508526402192, 1066863051997083, + 1008444703737597, 1348810787701552 +#else + 50192582, 28601458, 36715152, 18395610, 20774811, 15897498, + 5736189, 15026997, 64930608, 20098846 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2102881477513865, 1570274565945361, 1573617900503708, + 18662635732583, 2232324307922098 +#else + 58249865, 31335375, 28571665, 23398914, 66634396, 23448733, + 63307367, 278094, 23440562, 33264224 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1853931367696942, 8107973870707, 350214504129299, + 775206934582587, 1752317649166792 +#else + 10226222, 27625730, 15139955, 120818, 52241171, 5218602, + 32937275, 11551483, 50536904, 26111567 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1417148368003523, 721357181628282, 505725498207811, + 373232277872983, 261634707184480 +#else + 17932739, 21117156, 43069306, 10749059, 11316803, 7535897, + 22503767, 5561594, 63462240, 3898660 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2186733281493267, 2250694917008620, 1014829812957440, + 479998161452389, 83566193876474 +#else + 7749907, 32584865, 50769132, 33537967, 42090752, 15122142, + 65535333, 7152529, 21831162, 1245233 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1268116367301224, 560157088142809, 802626839600444, + 2210189936605713, 1129993785579988 +#else + 26958440, 18896406, 4314585, 8346991, 61431100, 11960071, + 34519569, 32934396, 36706772, 16838219 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 615183387352312, 917611676109240, 878893615973325, + 978940963313282, 938686890583575 +#else + 54942968, 9166946, 33491384, 13673479, 29787085, 13096535, + 6280834, 14587357, 44770839, 13987524 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 522024729211672, 1045059315315808, 1892245413707790, + 1907891107684253, 2059998109500714 +#else + 42758936, 7778774, 21116000, 15572597, 62275598, 28196653, + 62807965, 28429792, 59639082, 30696363 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1799679152208884, 912132775900387, 25967768040979, + 432130448590461, 274568990261996 +#else + 9681908, 26817309, 35157219, 13591837, 60225043, 386949, + 31622781, 6439245, 52527852, 4091396 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 98698809797682, 2144627600856209, 1907959298569602, + 811491302610148, 1262481774981493 +#else + 58682418, 1470726, 38999185, 31957441, 3978626, 28430809, + 47486180, 12092162, 29077877, 18812444 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1791451399743152, 1713538728337276, 118349997257490, + 1882306388849954, 158235232210248 +#else + 5269168, 26694706, 53878652, 25533716, 25932562, 1763552, + 61502754, 28048550, 47091016, 2357888 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1217809823321928, 2173947284933160, 1986927836272325, + 1388114931125539, 12686131160169 +#else + 32264008, 18146780, 61721128, 32394338, 65017541, 29607531, + 23104803, 20684524, 5727337, 189038 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1650875518872272, 1136263858253897, 1732115601395988, + 734312880662190, 1252904681142109 +#else + 14609104, 24599962, 61108297, 16931650, 52531476, 25810533, + 40363694, 10942114, 41219933, 18669734 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 372986456113865, 525430915458171, 2116279931702135, + 501422713587815, 1907002872974925 +#else + 20513481, 5557931, 51504251, 7829530, 26413943, 31535028, + 45729895, 7471780, 13913677, 28416557 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 803147181835288, 868941437997146, 316299302989663, + 943495589630550, 571224287904572 +#else + 41534488, 11967825, 29233242, 12948236, 60354399, 4713226, + 58167894, 14059179, 12878652, 8511905 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 227742695588364, 1776969298667369, 628602552821802, + 457210915378118, 2041906378111140 +#else + 41452044, 3393630, 64153449, 26478905, 64858154, 9366907, + 36885446, 6812973, 5568676, 30426776 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 815000523470260, 913085688728307, 1052060118271173, + 1345536665214223, 541623413135555 +#else + 11630004, 12144454, 2116339, 13606037, 27378885, 15676917, + 49700111, 20050058, 52713667, 8070817 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1580216071604333, 1877997504342444, 857147161260913, + 703522726778478, 2182763974211603 +#else + 27117677, 23547054, 35826092, 27984343, 1127281, 12772488, + 37262958, 10483305, 55556115, 32525717 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1870080310923419, 71988220958492, 1783225432016732, + 615915287105016, 1035570475990230 +#else + 10637467, 27866368, 5674780, 1072708, 40765276, 26572129, + 65424888, 9177852, 39615702, 15431202 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 730987750830150, 857613889540280, 1083813157271766, + 1002817255970169, 1719228484436074 +#else + 20525126, 10892566, 54366392, 12779442, 37615830, 16150074, + 38868345, 14943141, 52052074, 25618500 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 377616581647602, 1581980403078513, 804044118130621, + 2034382823044191, 643844048472185 +#else + 37084402, 5626925, 66557297, 23573344, 753597, 11981191, + 25244767, 30314666, 63752313, 9594023 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 176957326463017, 1573744060478586, 528642225008045, + 1816109618372371, 1515140189765006 +#else + 43356201, 2636869, 61944954, 23450613, 585133, 7877383, + 11345683, 27062142, 13352334, 22577348 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1888911448245718, 1387110895611080, 1924503794066429, + 1731539523700949, 2230378382645454 +#else + 65177046, 28146973, 3304648, 20669563, 17015805, 28677341, + 37325013, 25801949, 53893326, 33235227 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 443392177002051, 233793396845137, 2199506622312416, + 1011858706515937, 974676837063129 +#else + 20239939, 6607058, 6203985, 3483793, 48721888, 32775202, + 46385121, 15077869, 44358105, 14523816 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1846351103143623, 1949984838808427, 671247021915253, + 1946756846184401, 1929296930380217 +#else + 27406023, 27512775, 27423595, 29057038, 4996213, 10002360, + 38266833, 29008937, 36936121, 28748764 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 849646212452002, 1410198775302919, 73767886183695, + 1641663456615812, 762256272452411 +#else + 11374242, 12660715, 17861383, 21013599, 10935567, 1099227, + 53222788, 24462691, 39381819, 11358503 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 692017667358279, 723305578826727, 1638042139863265, + 748219305990306, 334589200523901 +#else + 54378055, 10311866, 1510375, 10778093, 64989409, 24408729, + 32676002, 11149336, 40985213, 4985767 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 22893968530686, 2235758574399251, 1661465835630252, + 925707319443452, 1203475116966621 +#else + 48012542, 341146, 60911379, 33315398, 15756972, 24757770, + 66125820, 13794113, 47694557, 17933176 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 801299035785166, 1733292596726131, 1664508947088596, + 467749120991922, 1647498584535623 +#else + 6490062, 11940286, 25495923, 25828072, 8668372, 24803116, + 3367602, 6970005, 65417799, 24549641 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 903105258014366, 427141894933047, 561187017169777, + 1884330244401954, 1914145708422219 +#else + 1656478, 13457317, 15370807, 6364910, 13605745, 8362338, + 47934242, 28078708, 50312267, 28522993 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1344191060517578, 1960935031767890, 1518838929955259, + 1781502350597190, 1564784025565682 +#else + 44835530, 20030007, 67044178, 29220208, 48503227, 22632463, + 46537798, 26546453, 67009010, 23317098 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 673723351748086, 1979969272514923, 1175287312495508, + 1187589090978666, 1881897672213940 +#else + 17747446, 10039260, 19368299, 29503841, 46478228, 17513145, + 31992682, 17696456, 37848500, 28042460 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1917185587363432, 1098342571752737, 5935801044414, + 2000527662351839, 1538640296181569 +#else + 31932008, 28568291, 47496481, 16366579, 22023614, 88450, + 11371999, 29810185, 4882241, 22927527 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2495540013192, 678856913479236, 224998292422872, + 219635787698590, 1972465269000940 +#else + 29796488, 37186, 19818052, 10115756, 55279832, 3352735, + 18551198, 3272828, 61917932, 29392022 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 271413961212179, 1353052061471651, 344711291283483, + 2014925838520662, 2006221033113941 +#else + 12501267, 4044383, 58495907, 20162046, 34678811, 5136598, + 47878486, 30024734, 330069, 29895023 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 194583029968109, 514316781467765, 829677956235672, + 1676415686873082, 810104584395840 +#else + 6384877, 2899513, 17807477, 7663917, 64749976, 12363164, + 25366522, 24980540, 66837568, 12071498 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1980510813313589, 1948645276483975, 152063780665900, + 129968026417582, 256984195613935 +#else + 58743349, 29511910, 25133447, 29037077, 60897836, 2265926, + 34339246, 1936674, 61949167, 3829362 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1860190562533102, 1936576191345085, 461100292705964, + 1811043097042830, 957486749306835 +#else + 28425966, 27718999, 66531773, 28857233, 52891308, 6870929, + 7921550, 26986645, 26333139, 14267664 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 796664815624365, 1543160838872951, 1500897791837765, + 1667315977988401, 599303877030711 +#else + 56041645, 11871230, 27385719, 22994888, 62522949, 22365119, + 10004785, 24844944, 45347639, 8930323 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1151480509533204, 2136010406720455, 738796060240027, + 319298003765044, 1150614464349587 +#else + 45911060, 17158396, 25654215, 31829035, 12282011, 11008919, + 1541940, 4757911, 40617363, 17145491 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1731069268103150, 735642447616087, 1364750481334268, + 417232839982871, 927108269127661 +#else + 13537262, 25794942, 46504023, 10961926, 61186044, 20336366, + 53952279, 6217253, 51165165, 13814989 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1017222050227968, 1987716148359, 2234319589635701, + 621282683093392, 2132553131763026 +#else + 49686272, 15157789, 18705543, 29619, 24409717, 33293956, + 27361680, 9257833, 65152338, 31777517 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1567828528453324, 1017807205202360, 565295260895298, + 829541698429100, 307243822276582 +#else + 42063564, 23362465, 15366584, 15166509, 54003778, 8423555, + 37937324, 12361134, 48422886, 4578289 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 249079270936248, 1501514259790706, 947909724204848, + 944551802437487, 552658763982480 +#else + 24579768, 3711570, 1342322, 22374306, 40103728, 14124955, + 44564335, 14074918, 21964432, 8235257 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2089966982947227, 1854140343916181, 2151980759220007, + 2139781292261749, 158070445864917 +#else + 60580251, 31142934, 9442965, 27628844, 12025639, 32067012, + 64127349, 31885225, 13006805, 2355433 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1338766321464554, 1906702607371284, 1519569445519894, + 115384726262267, 1393058953390992 +#else + 50803946, 19949172, 60476436, 28412082, 16974358, 22643349, + 27202043, 1719366, 1141648, 20758196 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1364621558265400, 1512388234908357, 1926731583198686, + 2041482526432505, 920401122333774 +#else + 54244920, 20334445, 58790597, 22536340, 60298718, 28710537, + 13475065, 30420460, 32674894, 13715045 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1884844597333588, 601480070269079, 620203503079537, + 1079527400117915, 1202076693132015 +#else + 11423316, 28086373, 32344215, 8962751, 24989809, 9241752, + 53843611, 16086211, 38367983, 17912338 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 840922919763324, 727955812569642, 1303406629750194, + 522898432152867, 294161410441865 +#else + 65699196, 12530727, 60740138, 10847386, 19531186, 19422272, + 55399715, 7791793, 39862921, 4383346 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 353760790835310, 1598361541848743, 1122905698202299, + 1922533590158905, 419107700666580 +#else + 38137966, 5271446, 65842855, 23817442, 54653627, 16732598, + 62246457, 28647982, 27193556, 6245191 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 359856369838236, 180914355488683, 861726472646627, + 218807937262986, 575626773232501 +#else + 51914908, 5362277, 65324971, 2695833, 4960227, 12840725, + 23061898, 3260492, 22510453, 8577507 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 755467689082474, 909202735047934, 730078068932500, + 936309075711518, 2007798262842972 +#else + 54476394, 11257345, 34415870, 13548176, 66387860, 10879010, + 31168030, 13952092, 37537372, 29918525 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1609384177904073, 362745185608627, 1335318541768201, + 800965770436248, 547877979267412 +#else + 3877321, 23981693, 32416691, 5405324, 56104457, 19897796, + 3759768, 11935320, 5611860, 8164018 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 984339177776787, 815727786505884, 1645154585713747, + 1659074964378553, 1686601651984156 +#else + 50833043, 14667796, 15906460, 12155291, 44997715, 24514713, + 32003001, 24722143, 5773084, 25132323 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1697863093781930, 599794399429786, 1104556219769607, + 830560774794755, 12812858601017 +#else + 43320746, 25300131, 1950874, 8937633, 18686727, 16459170, + 66203139, 12376319, 31632953, 190926 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1168737550514982, 897832437380552, 463140296333799, + 302564600022547, 2008360505135501 +#else + 42515238, 17415546, 58684872, 13378745, 14162407, 6901328, + 58820115, 4508563, 41767309, 29926903 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1856930662813910, 678090852002597, 1920179140755167, + 1259527833759868, 55540971895511 +#else + 8884438, 27670423, 6023973, 10104341, 60227295, 28612898, + 18722940, 18768427, 65436375, 827624 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1158643631044921, 476554103621892, 178447851439725, + 1305025542653569, 103433927680625 +#else + 34388281, 17265135, 34605316, 7101209, 13354605, 2659080, + 65308289, 19446395, 42230385, 1541285 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2176793111709008, 1576725716350391, 2009350167273523, + 2012390194631546, 2125297410909580 +#else + 2901328, 32436745, 3880375, 23495044, 49487923, 29941650, + 45306746, 29986950, 20456844, 31669399 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 825403285195098, 2144208587560784, 1925552004644643, + 1915177840006985, 1015952128947864 +#else + 27019610, 12299467, 53450576, 31951197, 54247203, 28692960, + 47568713, 28538373, 29439640, 15138866 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1807108316634472, 1534392066433717, 347342975407218, + 1153820745616376, 7375003497471 +#else + 21536104, 26928012, 34661045, 22864223, 44700786, 5175813, + 61688824, 17193268, 7779327, 109896 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 983061001799725, 431211889901241, 2201903782961093, + 817393911064341, 2214616493042167 +#else + 30279725, 14648750, 59063993, 6425557, 13639621, 32810923, + 28698389, 12180118, 23177719, 33000357 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 228567918409756, 865093958780220, 358083886450556, + 159617889659320, 1360637926292598 +#else + 26572828, 3405927, 35407164, 12890904, 47843196, 5335865, + 60615096, 2378491, 4439158, 20275085 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 234147501399755, 2229469128637390, 2175289352258889, + 1397401514549353, 1885288963089922 +#else + 44392139, 3489069, 57883598, 33221678, 18875721, 32414337, + 14819433, 20822905, 49391106, 28092994 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1111762412951562, 252849572507389, 1048714233823341, + 146111095601446, 1237505378776770 +#else + 62052362, 16566550, 15953661, 3767752, 56672365, 15627059, + 66287910, 2177224, 8550082, 18440267 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1113790697840279, 1051167139966244, 1045930658550944, + 2011366241542643, 1686166824620755 +#else + 48635543, 16596774, 66727204, 15663610, 22860960, 15585581, + 39264755, 29971692, 43848403, 25125843 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1054097349305049, 1872495070333352, 182121071220717, + 1064378906787311, 100273572924182 +#else + 34628313, 15707274, 58902952, 27902350, 29464557, 2713815, + 44383727, 15860481, 45206294, 1494192 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1306410853171605, 1627717417672447, 50983221088417, + 1109249951172250, 870201789081392 +#else + 47546773, 19467038, 41524991, 24254879, 13127841, 759709, + 21923482, 16529112, 8742704, 12967017 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 104233794644221, 1548919791188248, 2224541913267306, + 2054909377116478, 1043803389015153 +#else + 38643965, 1553204, 32536856, 23080703, 42417258, 33148257, + 58194238, 30620535, 37205105, 15553882 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 216762189468802, 707284285441622, 190678557969733, + 973969342604308, 1403009538434867 +#else + 21877890, 3230008, 9881174, 10539357, 62311749, 2841331, + 11543572, 14513274, 19375923, 20906471 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1279024291038477, 344776835218310, 273722096017199, + 1834200436811442, 634517197663804 +#else + 8832269, 19058947, 13253510, 5137575, 5037871, 4078777, + 24880818, 27331716, 2862652, 9455043 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 343805853118335, 1302216857414201, 566872543223541, + 2051138939539004, 321428858384280 +#else + 29306751, 5123106, 20245049, 19404543, 9592565, 8447059, + 65031740, 30564351, 15511448, 4789663 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 470067171324852, 1618629234173951, 2000092177515639, + 7307679772789, 1117521120249968 +#else + 46429108, 7004546, 8824831, 24119455, 63063159, 29803695, + 61354101, 108892, 23513200, 16652362 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 278151578291475, 1810282338562947, 1771599529530998, + 1383659409671631, 685373414471841 +#else + 33852691, 4144781, 62632835, 26975308, 10770038, 26398890, + 60458447, 20618131, 48789665, 10212859 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 577009397403102, 1791440261786291, 2177643735971638, + 174546149911960, 1412505077782326 +#else + 2756062, 8598110, 7383731, 26694540, 22312758, 32449420, + 21179800, 2600940, 57120566, 21047965 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 893719721537457, 1201282458018197, 1522349501711173, + 58011597740583, 1130406465887139 +#else + 42463153, 13317461, 36659605, 17900503, 21365573, 22684775, + 11344423, 864440, 64609187, 16844368 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 412607348255453, 1280455764199780, 2233277987330768, + 14180080401665, 331584698417165 +#else + 40676061, 6148328, 49924452, 19080277, 18782928, 33278435, + 44547329, 211299, 2719757, 4940997 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 262483770854550, 990511055108216, 526885552771698, + 571664396646158, 354086190278723 +#else + 65784982, 3911312, 60160120, 14759764, 37081714, 7851206, + 21690126, 8518463, 26699843, 5276295 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1820352417585487, 24495617171480, 1547899057533253, + 10041836186225, 480457105094042 +#else + 53958991, 27125364, 9396248, 365013, 24703301, 23065493, + 1321585, 149635, 51656090, 7159368 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2023310314989233, 637905337525881, 2106474638900687, + 557820711084072, 1687858215057826 +#else + 9987761, 30149673, 17507961, 9505530, 9731535, 31388918, + 22356008, 8312176, 22477218, 25151047 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1144168702609745, 604444390410187, 1544541121756138, + 1925315550126027, 626401428894002 +#else + 18155857, 17049442, 19744715, 9006923, 15154154, 23015456, + 24256459, 28689437, 44560690, 9334108 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1922168257351784, 2018674099908659, 1776454117494445, + 956539191509034, 36031129147635 +#else + 2986088, 28642539, 10776627, 30080588, 10620589, 26471229, + 45695018, 14253544, 44521715, 536905 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 544644538748041, 1039872944430374, 876750409130610, + 710657711326551, 1216952687484972 +#else + 4377737, 8115836, 24567078, 15495314, 11625074, 13064599, + 7390551, 10589625, 10838060, 18134008 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 58242421545916, 2035812695641843, 2118491866122923, + 1191684463816273, 46921517454099 +#else + 47766460, 867879, 9277171, 30335973, 52677291, 31567988, + 19295825, 17757482, 6378259, 699185 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 272268252444639, 1374166457774292, 2230115177009552, + 1053149803909880, 1354288411641016 +#else + 7895007, 4057113, 60027092, 20476675, 49222032, 33231305, + 66392824, 15693154, 62063800, 20180469 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1857910905368338, 1754729879288912, 885945464109877, + 1516096106802166, 1602902393369811 +#else + 59371282, 27685029, 52542544, 26147512, 11385653, 13201616, + 31730678, 22591592, 63190227, 23885106 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1193437069800958, 901107149704790, 999672920611411, + 477584824802207, 364239578697845 +#else + 10188286, 17783598, 59772502, 13427542, 22223443, 14896287, + 30743455, 7116568, 45322357, 5427592 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 886299989548838, 1538292895758047, 1590564179491896, + 1944527126709657, 837344427345298 +#else + 696102, 13206899, 27047647, 22922350, 15285304, 23701253, + 10798489, 28975712, 19236242, 12477404 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 754558365378305, 1712186480903618, 1703656826337531, + 750310918489786, 518996040250900 +#else + 55879425, 11243795, 50054594, 25513566, 66320635, 25386464, + 63211194, 11180503, 43939348, 7733643 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1309847803895382, 1462151862813074, 211370866671570, + 1544595152703681, 1027691798954090 +#else + 17800790, 19518253, 40108434, 21787760, 23887826, 3149671, + 23466177, 23016261, 10322026, 15313801 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 803217563745370, 1884799722343599, 1357706345069218, + 2244955901722095, 730869460037413 +#else + 26246234, 11968874, 32263343, 28085704, 6830754, 20231401, + 51314159, 33452449, 42659621, 10890803 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 689299471295966, 1831210565161071, 1375187341585438, + 1106284977546171, 1893781834054269 +#else + 35743198, 10271362, 54448239, 27287163, 16690206, 20491888, + 52126651, 16484930, 25180797, 28219548 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 696351368613042, 1494385251239250, 738037133616932, + 636385507851544, 927483222611406 +#else + 66522290, 10376443, 34522450, 22268075, 19801892, 10997610, + 2276632, 9482883, 316878, 13820577 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1949114198209333, 1104419699537997, 783495707664463, + 1747473107602770, 2002634765788641 +#else + 57226037, 29044064, 64993357, 16457135, 56008783, 11674995, + 30756178, 26039378, 30696929, 29841583 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1607325776830197, 530883941415333, 1451089452727895, + 1581691157083423, 496100432831154 +#else + 32988917, 23951020, 12499365, 7910787, 56491607, 21622917, + 59766047, 23569034, 34759346, 7392472 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1068900648804224, 2006891997072550, 1134049269345549, + 1638760646180091, 2055396084625778 +#else + 58253184, 15927860, 9866406, 29905021, 64711949, 16898650, + 36699387, 24419436, 25112946, 30627788 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2222475519314561, 1870703901472013, 1884051508440561, + 1344072275216753, 1318025677799069 +#else + 64604801, 33117465, 25621773, 27875660, 15085041, 28074555, + 42223985, 20028237, 5537437, 19640113 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 155711679280656, 681100400509288, 389811735211209, + 2135723811340709, 408733211204125 +#else + 55883280, 2320284, 57524584, 10149186, 33664201, 5808647, + 52232613, 31824764, 31234589, 6090599 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 7813206966729, 194444201427550, 2071405409526507, + 1065605076176312, 1645486789731291 +#else + 57475529, 116425, 26083934, 2897444, 60744427, 30866345, 609720, + 15878753, 60138459, 24519663 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 16625790644959, 1647648827778410, 1579910185572704, + 436452271048548, 121070048451050 +#else + 39351007, 247743, 51914090, 24551880, 23288160, 23542496, + 43239268, 6503645, 20650474, 1804084 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1037263028552531, 568385780377829, 297953104144430, + 1558584511931211, 2238221839292471 +#else + 39519059, 15456423, 8972517, 8469608, 15640622, 4439847, + 3121995, 23224719, 27842615, 33352104 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 190565267697443, 672855706028058, 338796554369226, + 337687268493904, 853246848691734 +#else + 51801891, 2839643, 22530074, 10026331, 4602058, 5048462, + 28248656, 5031932, 55733782, 12714368 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1763863028400139, 766498079432444, 1321118624818005, + 69494294452268, 858786744165651 +#else + 20807691, 26283607, 29286140, 11421711, 39232341, 19686201, + 45881388, 1035545, 47375635, 12796919 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1292056768563024, 1456632109855638, 1100631247050184, + 1386133165675321, 1232898350193752 +#else + 12076880, 19253146, 58323862, 21705509, 42096072, 16400683, + 49517369, 20654993, 3480664, 18371617 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 366253102478259, 525676242508811, 1449610995265438, + 1183300845322183, 185960306491545 +#else + 34747315, 5457596, 28548107, 7833186, 7303070, 21600887, + 42745799, 17632556, 33734809, 2771024 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 28315355815982, 460422265558930, 1799675876678724, + 1969256312504498, 1051823843138725 +#else + 45719598, 421931, 26597266, 6860826, 22486084, 26817260, + 49971378, 29344205, 42556581, 15673396 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 156914999361983, 1606148405719949, 1665208410108430, + 317643278692271, 1383783705665320 +#else + 46924223, 2338215, 19788685, 23933476, 63107598, 24813538, + 46837679, 4733253, 3727144, 20619984 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 54684536365732, 2210010038536222, 1194984798155308, + 535239027773705, 1516355079301361 +#else + 6120100, 814863, 55314462, 32931715, 6812204, 17806661, 2019593, + 7975683, 31123697, 22595451 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1484387703771650, 198537510937949, 2186282186359116, + 617687444857508, 647477376402122 +#else + 30069250, 22119100, 30434653, 2958439, 18399564, 32578143, + 12296868, 9204260, 50676426, 9648164 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2147715541830533, 500032538445817, 646380016884826, + 352227855331122, 1488268620408052 +#else + 32705413, 32003455, 30705657, 7451065, 55303258, 9631812, + 3305266, 5248604, 41100532, 22176930 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 159386186465542, 1877626593362941, 618737197060512, + 1026674284330807, 1158121760792685 +#else + 17219846, 2375039, 35537917, 27978816, 47649184, 9219902, + 294711, 15298639, 2662509, 17257359 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1744544377739822, 1964054180355661, 1685781755873170, + 2169740670377448, 1286112621104591 +#else + 65935918, 25995736, 62742093, 29266687, 45762450, 25120105, + 32087528, 32331655, 32247247, 19164571 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 81977249784993, 1667943117713086, 1668983819634866, + 1605016835177615, 1353960708075544 +#else + 14312609, 1221556, 17395390, 24854289, 62163122, 24869796, + 38911119, 23916614, 51081240, 20175586 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1602253788689063, 439542044889886, 2220348297664483, + 657877410752869, 157451572512238 +#else + 65680039, 23875441, 57873182, 6549686, 59725795, 33085767, + 23046501, 9803137, 17597934, 2346211 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1029287186166717, 65860128430192, 525298368814832, + 1491902500801986, 1461064796385400 +#else + 18510781, 15337574, 26171504, 981392, 44867312, 7827555, + 43617730, 22231079, 3059832, 21771562 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 408216988729246, 2121095722306989, 913562102267595, + 1879708920318308, 241061448436731 +#else + 10141598, 6082907, 17829293, 31606789, 9830091, 13613136, + 41552228, 28009845, 33606651, 3592095 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1185483484383269, 1356339572588553, 584932367316448, + 102132779946470, 1792922621116791 +#else + 33114149, 17665080, 40583177, 20211034, 33076704, 8716171, + 1151462, 1521897, 66126199, 26716628 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1966196870701923, 2230044620318636, 1425982460745905, + 261167817826569, 46517743394330 +#else + 34169699, 29298616, 23947180, 33230254, 34035889, 21248794, + 50471177, 3891703, 26353178, 693168 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 107077591595359, 884959942172345, 27306869797400, + 2224911448949390, 964352058245223 +#else + 30374239, 1595580, 50224825, 13186930, 4600344, 406904, 9585294, + 33153764, 31375463, 14369965 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1730194207717538, 431790042319772, 1831515233279467, + 1372080552768581, 1074513929381760 +#else + 52738210, 25781902, 1510300, 6434173, 48324075, 27291703, + 32732229, 20445593, 17901440, 16011505 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1450880638731607, 1019861580989005, 1229729455116861, + 1174945729836143, 826083146840706 +#else + 18171223, 21619806, 54608461, 15197121, 56070717, 18324396, + 47936623, 17508055, 8764034, 12309598 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1899935429242705, 1602068751520477, 940583196550370, + 82431069053859, 1540863155745696 +#else + 5975889, 28311244, 47649501, 23872684, 55567586, 14015781, + 43443107, 1228318, 17544096, 22960650 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2136688454840028, 2099509000964294, 1690800495246475, + 1217643678575476, 828720645084218 +#else + 5811932, 31839139, 3442886, 31285122, 48741515, 25194890, + 49064820, 18144304, 61543482, 12348899 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 765548025667841, 462473984016099, 998061409979798, + 546353034089527, 2212508972466858 +#else + 35709185, 11407554, 25755363, 6891399, 63851926, 14872273, + 42259511, 8141294, 56476330, 32968952 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 46575283771160, 892570971573071, 1281983193144090, + 1491520128287375, 75847005908304 +#else + 54433560, 694025, 62032719, 13300343, 14015258, 19103038, + 57410191, 22225381, 30944592, 1130208 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1801436127943107, 1734436817907890, 1268728090345068, + 167003097070711, 2233597765834956 +#else + 8247747, 26843490, 40546482, 25845122, 52706924, 18905521, + 4652151, 2488540, 23550156, 33283200 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1997562060465113, 1048700225534011, 7615603985628, + 1855310849546841, 2242557647635213 +#else + 17294297, 29765994, 7026747, 15626851, 22990044, 113481, + 2267737, 27646286, 66700045, 33416712 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1161017320376250, 492624580169043, 2169815802355237, + 976496781732542, 1770879511019629 +#else + 16091066, 17300506, 18599251, 7340678, 2137637, 32332775, + 63744702, 14550935, 3260525, 26388161 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1357044908364776, 729130645262438, 1762469072918979, + 1365633616878458, 181282906404941 +#else + 62198760, 20221544, 18550886, 10864893, 50649539, 26262835, + 44079994, 20349526, 54360141, 2701325 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1080413443139865, 1155205815510486, 1848782073549786, + 622566975152580, 124965574467971 +#else + 58534169, 16099414, 4629974, 17213908, 46322650, 27548999, + 57090500, 9276970, 11329923, 1862132 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1184526762066993, 247622751762817, 692129017206356, + 820018689412496, 2188697339828085 +#else + 14763057, 17650824, 36190593, 3689866, 3511892, 10313526, + 45157776, 12219230, 58070901, 32614131 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2020536369003019, 202261491735136, 1053169669150884, + 2056531979272544, 778165514694311 +#else + 8894987, 30108338, 6150752, 3013931, 301220, 15693451, 35127648, + 30644714, 51670695, 11595569 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 237404399610207, 1308324858405118, 1229680749538400, + 720131409105291, 1958958863624906 +#else + 15214943, 3537601, 40870142, 19495559, 4418656, 18323671, + 13947275, 10730794, 53619402, 29190761 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 515583508038846, 17656978857189, 1717918437373989, + 1568052070792483, 46975803123923 +#else + 64570558, 7682792, 32759013, 263109, 37124133, 25598979, + 44776739, 23365796, 977107, 699994 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 281527309158085, 36970532401524, 866906920877543, + 2222282602952734, 1289598729589882 +#else + 54642373, 4195083, 57897332, 550903, 51543527, 12917919, + 19118110, 33114591, 36574330, 19216518 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1278207464902042, 494742455008756, 1262082121427081, + 1577236621659884, 1888786707293291 +#else + 31788442, 19046775, 4799988, 7372237, 8808585, 18806489, + 9408236, 23502657, 12493931, 28145115 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 353042527954210, 1830056151907359, 1111731275799225, + 174960955838824, 404312815582675 +#else + 41428258, 5260743, 47873055, 27269961, 63412921, 16566086, + 27218280, 2607121, 29375955, 6024730 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2064251142068628, 1666421603389706, 1419271365315441, + 468767774902855, 191535130366583 +#else + 842132, 30759739, 62345482, 24831616, 26332017, 21148791, + 11831879, 6985184, 57168503, 2854095 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1716987058588002, 1859366439773457, 1767194234188234, + 64476199777924, 1117233614485261 +#else + 62261602, 25585100, 2516241, 27706719, 9695690, 26333246, + 16512644, 960770, 12121869, 16648078 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 984292135520292, 135138246951259, 2220652137473167, + 1722843421165029, 190482558012909 +#else + 51890212, 14667095, 53772635, 2013716, 30598287, 33090295, + 35603941, 25672367, 20237805, 2838411 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 298845952651262, 1166086588952562, 1179896526238434, + 1347812759398693, 1412945390096208 +#else + 47820798, 4453151, 15298546, 17376044, 22115042, 17581828, + 12544293, 20083975, 1068880, 21054527 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1143239552672925, 906436640714209, 2177000572812152, + 2075299936108548, 325186347798433 +#else + 57549981, 17035596, 33238497, 13506958, 30505848, 32439836, + 58621956, 30924378, 12521377, 4845654 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 721024854374772, 684487861263316, 1373438744094159, + 2193186935276995, 1387043709851261 +#else + 38910324, 10744107, 64150484, 10199663, 7759311, 20465832, + 3409347, 32681032, 60626557, 20668561 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 418098668140962, 715065997721283, 1471916138376055, + 2168570337288357, 937812682637044 +#else + 43547042, 6230155, 46726851, 10655313, 43068279, 21933259, + 10477733, 32314216, 63995636, 13974497 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1043584187226485, 2143395746619356, 2209558562919611, + 482427979307092, 847556718384018 +#else + 12966261, 15550616, 35069916, 31939085, 21025979, 32924988, + 5642324, 7188737, 18895762, 12629579 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1248731221520759, 1465200936117687, 540803492710140, + 52978634680892, 261434490176109 +#else + 14741879, 18607545, 22177207, 21833195, 1279740, 8058600, + 11758140, 789443, 32195181, 3895677 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1057329623869501, 620334067429122, 461700859268034, + 2012481616501857, 297268569108938 +#else + 10758205, 15755439, 62598914, 9243697, 62229442, 6879878, + 64904289, 29988312, 58126794, 4429646 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1055352180870759, 1553151421852298, 1510903185371259, + 1470458349428097, 1226259419062731 +#else + 64654951, 15725972, 46672522, 23143759, 61304955, 22514211, + 59972993, 21911536, 18047435, 18272689 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1492988790301668, 790326625573331, 1190107028409745, + 1389394752159193, 1620408196604194 +#else + 41935844, 22247266, 29759955, 11776784, 44846481, 17733976, + 10993113, 20703595, 49488162, 24145963 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 47000654413729, 1004754424173864, 1868044813557703, + 173236934059409, 588771199737015 +#else + 21987233, 700364, 42603816, 14972007, 59334599, 27836036, + 32155025, 2581431, 37149879, 8773374 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 30498470091663, 1082245510489825, 576771653181956, + 806509986132686, 1317634017056939 +#else + 41540495, 454462, 53896929, 16126714, 25240068, 8594567, + 20656846, 12017935, 59234475, 19634276 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 420308055751555, 1493354863316002, 165206721528088, + 1884845694919786, 2065456951573059 +#else + 6028163, 6263078, 36097058, 22252721, 66289944, 2461771, + 35267690, 28086389, 65387075, 30777706 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1115636332012334, 1854340990964155, 83792697369514, + 1972177451994021, 457455116057587 +#else + 54829870, 16624276, 987579, 27631834, 32908202, 1248608, + 7719845, 29387734, 28408819, 6816612 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1698968457310898, 1435137169051090, 1083661677032510, + 938363267483709, 340103887207182 +#else + 56750770, 25316602, 19549650, 21385210, 22082622, 16147817, + 20613181, 13982702, 56769294, 5067942 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1995325341336574, 911500251774648, 164010755403692, + 855378419194762, 1573601397528842 +#else + 36602878, 29732664, 12074680, 13582412, 47230892, 2443950, + 47389578, 12746131, 5331210, 23448488 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 241719380661528, 310028521317150, 1215881323380194, + 1408214976493624, 2141142156467363 +#else + 30528792, 3601899, 65151774, 4619784, 39747042, 18118043, + 24180792, 20984038, 27679907, 31905504 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1315157046163473, 727368447885818, 1363466668108618, + 1668921439990361, 1398483384337907 +#else + 9402385, 19597367, 32834042, 10838634, 40528714, 20317236, + 26653273, 24868867, 22611443, 20839026 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 75029678299646, 1015388206460473, 1849729037055212, + 1939814616452984, 444404230394954 +#else + 22190590, 1118029, 22736441, 15130463, 36648172, 27563110, + 19189624, 28905490, 4854858, 6622139 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2053597130993710, 2024431685856332, 2233550957004860, + 2012407275509545, 872546993104440 +#else + 58798126, 30600981, 58846284, 30166382, 56707132, 33282502, + 13424425, 29987205, 26404408, 13001963 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1217269667678610, 599909351968693, 1390077048548598, + 1471879360694802, 739586172317596 +#else + 35867026, 18138731, 64114613, 8939345, 11562230, 20713762, + 41044498, 21932711, 51703708, 11020692 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1718318639380794, 1560510726633958, 904462881159922, + 1418028351780052, 94404349451937 +#else + 1866042, 25604943, 59210214, 23253421, 12483314, 13477547, + 3175636, 21130269, 28761761, 1406734 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2132502667405250, 214379346175414, 1502748313768060, + 1960071701057800, 1353971822643138 +#else + 66660290, 31776765, 13018550, 3194501, 57528444, 22392694, + 24760584, 29207344, 25577410, 20175752 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 319394212043702, 2127459436033571, 717646691535162, + 663366796076914, 318459064945314 +#else + 42818486, 4759344, 66418211, 31701615, 2066746, 10693769, + 37513074, 9884935, 57739938, 4745409 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 405989424923593, 1960452633787083, 667349034401665, + 1492674260767112, 1451061489880787 +#else + 57967561, 6049713, 47577803, 29213020, 35848065, 9944275, + 51646856, 22242579, 10931923, 21622501 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 947085906234007, 323284730494107, 1485778563977200, + 728576821512394, 901584347702286 +#else + 50547351, 14112679, 59096219, 4817317, 59068400, 22139825, + 44255434, 10856640, 46638094, 13434653 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1575783124125742, 2126210792434375, 1569430791264065, + 1402582372904727, 1891780248341114 +#else + 22759470, 23480998, 50342599, 31683009, 13637441, 23386341, + 1765143, 20900106, 28445306, 28189722 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 838432205560695, 1997703511451664, 1018791879907867, + 1662001808174331, 78328132957753 +#else + 29875063, 12493613, 2795536, 29768102, 1710619, 15181182, + 56913147, 24765756, 9074233, 1167180 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 739152638255629, 2074935399403557, 505483666745895, + 1611883356514088, 628654635394878 +#else + 40903181, 11014232, 57266213, 30918946, 40200743, 7532293, + 48391976, 24018933, 3843902, 9367684 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1822054032121349, 643057948186973, 7306757352712, + 577249257962099, 284735863382083 +#else + 56139269, 27150720, 9591133, 9582310, 11349256, 108879, + 16235123, 8601684, 66969667, 4242894 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1366558556363930, 1448606567552086, 1478881020944768, + 165803179355898, 1115718458123498 +#else + 22092954, 20363309, 65066070, 21585919, 32186752, 22037044, + 60534522, 2470659, 39691498, 16625500 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 204146226972102, 1630511199034723, 2215235214174763, + 174665910283542, 956127674017216 +#else + 56051142, 3042015, 13770083, 24296510, 584235, 33009577, + 59338006, 2602724, 39757248, 14247412 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1562934578796716, 1070893489712745, 11324610642270, + 958989751581897, 2172552325473805 +#else + 6314156, 23289540, 34336361, 15957556, 56951134, 168749, + 58490057, 14290060, 27108877, 32373552 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1770564423056027, 735523631664565, 1326060113795289, + 1509650369341127, 65892421582684 +#else + 58522267, 26383465, 13241781, 10960156, 34117849, 19759835, + 33547975, 22495543, 39960412, 981873 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 623682558650637, 1337866509471512, 990313350206649, + 1314236615762469, 1164772974270275 +#else + 22833421, 9293594, 34459416, 19935764, 57971897, 14756818, + 44180005, 19583651, 56629059, 17356469 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 223256821462517, 723690150104139, 1000261663630601, + 933280913953265, 254872671543046 +#else + 59340277, 3326785, 38997067, 10783823, 19178761, 14905060, + 22680049, 13906969, 51175174, 3797898 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1969087237026041, 624795725447124, 1335555107635969, + 2069986355593023, 1712100149341902 +#else + 21721337, 29341686, 54902740, 9310181, 63226625, 19901321, + 23740223, 30845200, 20491982, 25512280 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1236103475266979, 1837885883267218, 1026072585230455, + 1025865513954973, 1801964901432134 +#else + 9209251, 18419377, 53852306, 27386633, 66377847, 15289672, + 25947805, 15286587, 30997318, 26851369 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1115241013365517, 1712251818829143, 2148864332502771, + 2096001471438138, 2235017246626125 +#else + 7392013, 16618386, 23946583, 25514540, 53843699, 32020573, + 52911418, 31232855, 17649997, 33304352 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1299268198601632, 2047148477845621, 2165648650132450, + 1612539282026145, 514197911628890 +#else + 57807776, 19360604, 30609525, 30504889, 41933794, 32270679, + 51867297, 24028707, 64875610, 7662145 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 118352772338543, 1067608711804704, 1434796676193498, + 1683240170548391, 230866769907437 +#else + 49550191, 1763593, 33994528, 15908609, 37067994, 21380136, + 7335079, 25082233, 63934189, 3440182 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1850689576796636, 1601590730430274, 1139674615958142, + 1954384401440257, 76039205311 +#else + 47219164, 27577423, 42997570, 23865561, 10799742, 16982475, + 40449, 29122597, 4862399, 1133 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1723387471374172, 997301467038410, 533927635123657, + 20928644693965, 1756575222802513 +#else + 34252636, 25680474, 61686474, 14860949, 50789833, 7956141, + 7258061, 311861, 36513873, 26175010 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2146711623855116, 503278928021499, 625853062251406, + 1109121378393107, 1033853809911861 +#else + 63335436, 31988495, 28985339, 7499440, 24445838, 9325937, + 29727763, 16527196, 18278453, 15405622 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 571005965509422, 2005213373292546, 1016697270349626, + 56607856974274, 914438579435146 +#else + 62726958, 8508651, 47210498, 29880007, 61124410, 15149969, + 53795266, 843522, 45233802, 13626196 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1346698876211176, 2076651707527589, 1084761571110205, + 265334478828406, 1068954492309671 +#else + 2281448, 20067377, 56193445, 30944521, 1879357, 16164207, + 56324982, 3953791, 13340839, 15928663 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1769967932677654, 1695893319756416, 1151863389675920, + 1781042784397689, 400287774418285 +#else + 31727126, 26374577, 48671360, 25270779, 2875792, 17164102, + 41838969, 26539605, 43656557, 5964752 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1851867764003121, 403841933237558, 820549523771987, + 761292590207581, 1743735048551143 +#else + 4100401, 27594980, 49929526, 6017713, 48403027, 12227140, + 40424029, 11344143, 2538215, 25983677 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 410915148140008, 2107072311871739, 1004367461876503, + 99684895396761, 1180818713503224 +#else + 57675240, 6123112, 11159803, 31397824, 30016279, 14966241, + 46633881, 1485420, 66479608, 17595569 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 285945406881439, 648174397347453, 1098403762631981, + 1366547441102991, 1505876883139217 +#else + 40304287, 4260918, 11851389, 9658551, 35091757, 16367491, + 46903439, 20363143, 11659921, 22439314 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 672095903120153, 1675918957959872, 636236529315028, + 1569297300327696, 2164144194785875 +#else + 26180377, 10015009, 36264640, 24973138, 5418196, 9480663, + 2231568, 23384352, 33100371, 32248261 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1902708175321798, 1035343530915438, 1178560808893263, + 301095684058146, 1280977479761118 +#else + 15121094, 28352561, 56718958, 15427820, 39598927, 17561924, + 21670946, 4486675, 61177054, 19088051 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1615357281742403, 404257611616381, 2160201349780978, + 1160947379188955, 1578038619549541 +#else + 16166467, 24070699, 56004733, 6023907, 35182066, 32189508, + 2340059, 17299464, 56373093, 23514607 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2013087639791217, 822734930507457, 1785668418619014, + 1668650702946164, 389450875221715 +#else + 28042865, 29997343, 54982337, 12259705, 63391366, 26608532, + 6766452, 24864833, 18036435, 5803270 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 453918449698368, 106406819929001, 2072540975937135, + 308588860670238, 1304394580755385 +#else + 66291264, 6763911, 11803561, 1585585, 10958447, 30883267, + 23855390, 4598332, 60949433, 19436993 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1295082798350326, 2091844511495996, 1851348972587817, + 3375039684596, 789440738712837 +#else + 36077558, 19298237, 17332028, 31170912, 31312681, 27587249, + 696308, 50292, 47013125, 11763583 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2083069137186154, 848523102004566, 993982213589257, + 1405313299916317, 1532824818698468 +#else + 66514282, 31040148, 34874710, 12643979, 12650761, 14811489, + 665117, 20940800, 47335652, 22840869 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1495961298852430, 1397203457344779, 1774950217066942, + 139302743555696, 66603584342787 +#else + 30464590, 22291560, 62981387, 20819953, 19835326, 26448819, + 42712688, 2075772, 50088707, 992470 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1782411379088302, 1096724939964781, 27593390721418, + 542241850291353, 1540337798439873 +#else + 18357166, 26559999, 7766381, 16342475, 37783946, 411173, + 14578841, 8080033, 55534529, 22952821 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 693543956581437, 171507720360750, 1557908942697227, + 1074697073443438, 1104093109037196 +#else + 19598397, 10334610, 12555054, 2555664, 18821899, 23214652, + 21873262, 16014234, 26224780, 16452269 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 345288228393419, 1099643569747172, 134881908403743, + 1740551994106740, 248212179299770 +#else + 36884939, 5145195, 5944548, 16385966, 3976735, 2009897, + 55731060, 25936245, 46575034, 3698649 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 231429562203065, 1526290236421172, 2021375064026423, + 1520954495658041, 806337791525116 +#else + 14187449, 3448569, 56472628, 22743496, 44444983, 30120835, + 7268409, 22663988, 27394300, 12015369 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1079623667189886, 872403650198613, 766894200588288, + 2163700860774109, 2023464507911816 +#else + 19695742, 16087646, 28032085, 12999827, 6817792, 11427614, + 20244189, 32241655, 53849736, 30151970 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 854645372543796, 1936406001954827, 151460662541253, + 825325739271555, 1554306377287556 +#else + 30860084, 12735208, 65220619, 28854697, 50133957, 2256939, + 58942851, 12298311, 58558340, 23160969 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1497138821904622, 1044820250515590, 1742593886423484, + 1237204112746837, 849047450816987 +#else + 61389038, 22309106, 65198214, 15569034, 26642876, 25966672, + 61319509, 18435777, 62132699, 12651792 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 667962773375330, 1897271816877105, 1399712621683474, + 1143302161683099, 2081798441209593 +#else + 64260450, 9953420, 11531313, 28271553, 26895122, 20857343, + 53990043, 17036529, 9768697, 31021214 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 127147851567005, 1936114012888110, 1704424366552046, + 856674880716312, 716603621335359 +#else + 42389405, 1894650, 66821166, 28850346, 15348718, 25397902, + 32767512, 12765450, 4940095, 10678226 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1072409664800960, 2146937497077528, 1508780108920651, + 935767602384853, 1112800433544068 +#else + 18860224, 15980149, 48121624, 31991861, 40875851, 22482575, + 59264981, 13944023, 42736516, 16582018 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 333549023751292, 280219272863308, 2104176666454852, + 1036466864875785, 536135186520207 +#else + 51604604, 4970267, 37215820, 4175592, 46115652, 31354675, + 55404809, 15444559, 56105103, 7989036 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 373666279883137, 146457241530109, 304116267127857, + 416088749147715, 1258577131183391 +#else + 31490433, 5568061, 64696061, 2182382, 34772017, 4531685, + 35030595, 6200205, 47422751, 18754260 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1186115062588401, 2251609796968486, 1098944457878953, + 1153112761201374, 1791625503417267 +#else + 49800177, 17674491, 35586086, 33551600, 34221481, 16375548, + 8680158, 17182719, 28550067, 26697300 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1870078460219737, 2129630962183380, 852283639691142, + 292865602592851, 401904317342226 +#else + 38981977, 27866340, 16837844, 31733974, 60258182, 12700015, + 37068883, 4364037, 1155602, 5988841 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1361070124828035, 815664541425524, 1026798897364671, + 1951790935390647, 555874891834790 +#else + 21890435, 20281525, 54484852, 12154348, 59276991, 15300495, + 23148983, 29083951, 24618406, 8283181 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1546301003424277, 459094500062839, 1097668518375311, + 1780297770129643, 720763293687608 +#else + 33972757, 23041680, 9975415, 6841041, 35549071, 16356535, + 3070187, 26528504, 1466168, 10740210 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1212405311403990, 1536693382542438, 61028431067459, + 1863929423417129, 1223219538638038 +#else + 65599446, 18066246, 53605478, 22898515, 32799043, 909394, + 53169961, 27774712, 34944214, 18227391 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1294303766540260, 1183557465955093, 882271357233093, + 63854569425375, 2213283684565087 +#else + 3960804, 19286629, 39082773, 17636380, 47704005, 13146867, + 15567327, 951507, 63848543, 32980496 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 339050984211414, 601386726509773, 413735232134068, + 966191255137228, 1839475899458159 +#else + 24740822, 5052253, 37014733, 8961360, 25877428, 6165135, + 42740684, 14397371, 59728495, 27410326 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 235605972169408, 2174055643032978, 1538335001838863, + 1281866796917192, 1815940222628465 +#else + 38220480, 3510802, 39005586, 32395953, 55870735, 22922977, + 51667400, 19101303, 65483377, 27059617 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1632352921721536, 1833328609514701, 2092779091951987, + 1923956201873226, 2210068022482919 +#else + 793280, 24323954, 8836301, 27318725, 39747955, 31184838, + 33152842, 28669181, 57202663, 32932579 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 35271216625062, 1712350667021807, 983664255668860, + 98571260373038, 1232645608559836 +#else + 5666214, 525582, 20782575, 25516013, 42570364, 14657739, + 16099374, 1468826, 60937436, 18367850 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1998172393429622, 1798947921427073, 784387737563581, + 1589352214827263, 1589861734168180 +#else + 62249590, 29775088, 64191105, 26806412, 7778749, 11688288, + 36704511, 23683193, 65549940, 23690785 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1733739258725305, 31715717059538, 201969945218860, + 992093044556990, 1194308773174556 +#else + 10896313, 25834728, 824274, 472601, 47648556, 3009586, 25248958, + 14783338, 36527388, 17796587 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 846415389605137, 746163495539180, 829658752826080, + 592067705956946, 957242537821393 +#else + 10566929, 12612572, 35164652, 11118702, 54475488, 12362878, + 21752402, 8822496, 24003793, 14264025 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1758148849754419, 619249044817679, 168089007997045, + 1371497636330523, 1867101418880350 +#else + 27713843, 26198459, 56100623, 9227529, 27050101, 2504721, + 23886875, 20436907, 13958494, 27821979 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 326633984209635, 261759506071016, 1700682323676193, + 1577907266349064, 1217647663383016 +#else + 43627235, 4867225, 39861736, 3900520, 29838369, 25342141, + 35219464, 23512650, 7340520, 18144364 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1714182387328607, 1477856482074168, 574895689942184, + 2159118410227270, 1555532449716575 +#else + 4646495, 25543308, 44342840, 22021777, 23184552, 8566613, + 31366726, 32173371, 52042079, 23179239 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 853828206885131, 998498946036955, 1835887550391235, + 207627336608048, 258363815956050 +#else + 49838347, 12723031, 50115803, 14878793, 21619651, 27356856, + 27584816, 3093888, 58265170, 3849920 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 141141474651677, 1236728744905256, 643101419899887, + 1646615130509173, 1208239602291765 +#else + 58043933, 2103171, 25561640, 18428694, 61869039, 9582957, + 32477045, 24536477, 5002293, 18004173 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1501663228068911, 1354879465566912, 1444432675498247, + 897812463852601, 855062598754348 +#else + 55051311, 22376525, 21115584, 20189277, 8808711, 21523724, + 16489529, 13378448, 41263148, 12741425 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 714380763546606, 1032824444965790, 1774073483745338, + 1063840874947367, 1738680636537158 +#else + 61162478, 10645102, 36197278, 15390283, 63821882, 26435754, + 24306471, 15852464, 28834118, 25908360 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1640635546696252, 633168953192112, 2212651044092396, + 30590958583852, 368515260889378 +#else + 49773116, 24447374, 42577584, 9434952, 58636780, 32971069, + 54018092, 455840, 20461858, 5491305 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1171650314802029, 1567085444565577, 1453660792008405, + 757914533009261, 1619511342778196 +#else + 13669229, 17458950, 54626889, 23351392, 52539093, 21661233, + 42112877, 11293806, 38520660, 24132599 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 420958967093237, 971103481109486, 2169549185607107, + 1301191633558497, 1661514101014240 +#else + 28497909, 6272777, 34085870, 14470569, 8906179, 32328802, + 18504673, 19389266, 29867744, 24758489 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 907123651818302, 1332556122804146, 1824055253424487, + 1367614217442959, 1982558335973172 +#else + 50901822, 13517195, 39309234, 19856633, 24009063, 27180541, + 60741263, 20379039, 22853428, 29542421 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1121533090144639, 1021251337022187, 110469995947421, + 1511059774758394, 2110035908131662 +#else + 24191359, 16712145, 53177067, 15217830, 14542237, 1646131, + 18603514, 22516545, 12876622, 31441985 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 303213233384524, 2061932261128138, 352862124777736, + 40828818670255, 249879468482660 +#else + 17902668, 4518229, 66697162, 30725184, 26878216, 5258055, + 54248111, 608396, 16031844, 3723494 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 856559257852200, 508517664949010, 1378193767894916, + 1723459126947129, 1962275756614521 +#else + 38476072, 12763727, 46662418, 7577503, 33001348, 20536687, + 17558841, 25681542, 23896953, 29240187 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1445691340537320, 40614383122127, 402104303144865, + 485134269878232, 1659439323587426 +#else + 47103464, 21542479, 31520463, 605201, 2543521, 5991821, + 64163800, 7229063, 57189218, 24727572 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 20057458979482, 1183363722525800, 2140003847237215, + 2053873950687614, 2112017736174909 +#else + 28816026, 298879, 38943848, 17633493, 19000927, 31888542, + 54428030, 30605106, 49057085, 31471516 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2228654250927986, 1483591363415267, 1368661293910956, + 1076511285177291, 526650682059608 +#else + 16000882, 33209536, 3493091, 22107234, 37604268, 20394642, + 12577739, 16041268, 47393624, 7847706 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 709481497028540, 531682216165724, 316963769431931, + 1814315888453765, 258560242424104 +#else + 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, + 34252933, 27035413, 57088296, 3852847 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1053447823660455, 1955135194248683, 1010900954918985, + 1182614026976701, 1240051576966610 +#else + 55678375, 15697595, 45987307, 29133784, 5386313, 15063598, + 16514493, 17622322, 29330898, 18478208 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1957943897155497, 1788667368028035, 137692910029106, + 1039519607062, 826404763313028 +#else + 41609129, 29175637, 51885955, 26653220, 16615730, 2051784, + 3303702, 15490, 39560068, 12314390 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1848942433095597, 1582009882530495, 1849292741020143, + 1068498323302788, 2001402229799484 +#else + 15683501, 27551389, 18109119, 23573784, 15337967, 27556609, + 50391428, 15921865, 16103996, 29823217 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1528282417624269, 2142492439828191, 2179662545816034, + 362568973150328, 1591374675250271 +#else + 43939021, 22773182, 13588191, 31925625, 63310306, 32479502, + 47835256, 5402698, 37293151, 23713330 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 160026679434388, 232341189218716, 2149181472355545, + 598041771119831, 183859001910173 +#else + 23190676, 2384583, 34394524, 3462153, 37205209, 32025299, + 55842007, 8911516, 41903005, 2739712 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2013278155187349, 662660471354454, 793981225706267, + 411706605985744, 804490933124791 +#else + 21374101, 30000182, 33584214, 9874410, 15377179, 11831242, + 33578960, 6134906, 4931255, 11987849 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2051892037280204, 488391251096321, 2230187337030708, + 930221970662692, 679002758255210 +#else + 67101132, 30575573, 50885377, 7277596, 105524, 33232381, + 35628324, 13861387, 37032554, 10117929 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1530723630438670, 875873929577927, 341560134269988, + 449903119530753, 1055551308214179 +#else + 37607694, 22809559, 40945095, 13051538, 41483300, 5089642, + 60783361, 6704078, 12890019, 15728940 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1461835919309432, 1955256480136428, 180866187813063, + 1551979252664528, 557743861963950 +#else + 45136504, 21783052, 66157804, 29135591, 14704839, 2695116, + 903376, 23126293, 12885166, 8311031 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 359179641731115, 1324915145732949, 902828372691474, + 294254275669987, 1887036027752957 +#else + 49592363, 5352193, 10384213, 19742774, 7506450, 13453191, + 26423267, 4384730, 1888765, 28119028 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2043271609454323, 2038225437857464, 1317528426475850, + 1398989128982787, 2027639881006861 +#else + 41291507, 30447119, 53614264, 30371925, 30896458, 19632703, + 34857219, 20846562, 47644429, 30214188 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2072902725256516, 312132452743412, 309930885642209, + 996244312618453, 1590501300352303 +#else + 43500868, 30888657, 66582772, 4651135, 5765089, 4618330, + 6092245, 14845197, 17151279, 23700316 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1397254305160710, 695734355138021, 2233992044438756, + 1776180593969996, 1085588199351115 +#else + 42278406, 20820711, 51942885, 10367249, 37577956, 33289075, + 22825804, 26467153, 50242379, 16176524 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 440567051331029, 254894786356681, 493869224930222, + 1556322069683366, 1567456540319218 +#else + 43525589, 6564960, 20063689, 3798228, 62368686, 7359224, + 2006182, 23191006, 38362610, 23356922 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1950722461391320, 1907845598854797, 1822757481635527, + 2121567704750244, 73811931471221 +#else + 56482264, 29068029, 53788301, 28429114, 3432135, 27161203, + 23632036, 31613822, 32808309, 1099883 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 387139307395758, 2058036430315676, 1220915649965325, + 1794832055328951, 1230009312169328 +#else + 15030958, 5768825, 39657628, 30667132, 60681485, 18193060, + 51830967, 26745081, 2051440, 18328567 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1765973779329517, 659344059446977, 19821901606666, + 1301928341311214, 1116266004075885 +#else + 63746541, 26315059, 7517889, 9824992, 23555850, 295369, 5148398, + 19400244, 44422509, 16633659 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1127572801181483, 1224743760571696, 1276219889847274, + 1529738721702581, 1589819666871853 +#else + 4577067, 16802144, 13249840, 18250104, 19958762, 19017158, + 18559669, 22794883, 8402477, 23690159 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2181229378964934, 2190885205260020, 1511536077659137, + 1246504208580490, 668883326494241 +#else + 38702534, 32502850, 40318708, 32646733, 49896449, 22523642, + 9453450, 18574360, 17983009, 9967138 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 437866655573314, 669026411194768, 81896997980338, + 523874406393178, 245052060935236 +#else + 41346370, 6524721, 26585488, 9969270, 24709298, 1220360, + 65430874, 7806336, 17507396, 3651560 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1975438052228868, 1071801519999806, 594652299224319, + 1877697652668809, 1489635366987285 +#else + 56688388, 29436320, 14584638, 15971087, 51340543, 8861009, + 26556809, 27979875, 48555541, 22197296 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 958592545673770, 233048016518599, 851568750216589, + 567703851596087, 1740300006094761 +#else + 2839082, 14284142, 4029895, 3472686, 14402957, 12689363, + 40466743, 8459446, 61503401, 25932490 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2014540178270324, 192672779514432, 213877182641530, + 2194819933853411, 1716422829364835 +#else + 62269556, 30018987, 9744960, 2871048, 25113978, 3187018, + 41998051, 32705365, 17258083, 25576693 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1540769606609725, 2148289943846077, 1597804156127445, + 1230603716683868, 815423458809453 +#else + 18164541, 22959256, 49953981, 32012014, 19237077, 23809137, + 23357532, 18337424, 26908269, 12150756 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1738560251245018, 1779576754536888, 1783765347671392, + 1880170990446751, 1088225159617541 +#else + 36843994, 25906566, 5112248, 26517760, 65609056, 26580174, + 43167, 28016731, 34806789, 16215818 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 659303913929492, 1956447718227573, 1830568515922666, + 841069049744408, 1669607124206368 +#else + 60209940, 9824393, 54804085, 29153342, 35711722, 27277596, + 32574488, 12532905, 59605792, 24879084 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1143465490433355, 1532194726196059, 1093276745494697, + 481041706116088, 2121405433561163 +#else + 39765323, 17038963, 39957339, 22831480, 946345, 16291093, + 254968, 7168080, 21676107, 31611404 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1686424298744462, 1451806974487153, 266296068846582, + 1834686947542675, 1720762336132256 +#else + 21260942, 25129680, 50276977, 21633609, 43430902, 3968120, + 63456915, 27338965, 63552672, 25641356 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 889217026388959, 1043290623284660, 856125087551909, + 1669272323124636, 1603340330827879 +#else + 16544735, 13250366, 50304436, 15546241, 62525861, 12757257, + 64646556, 24874095, 48201831, 23891632 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1206396181488998, 333158148435054, 1402633492821422, + 1120091191722026, 1945474114550509 +#else + 64693606, 17976703, 18312302, 4964443, 51836334, 20900867, + 26820650, 16690659, 25459437, 28989823 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 766720088232571, 1512222781191002, 1189719893490790, + 2091302129467914, 2141418006894941 +#else + 41964155, 11425019, 28423002, 22533875, 60963942, 17728207, + 9142794, 31162830, 60676445, 31909614 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 419663647306612, 1998875112167987, 1426599870253707, + 1154928355379510, 486538532138187 +#else + 44004212, 6253475, 16964147, 29785560, 41994891, 21257994, + 39651638, 17209773, 6335691, 7249989 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 938160078005954, 1421776319053174, 1941643234741774, + 180002183320818, 1414380336750546 +#else + 36775618, 13979674, 7503222, 21186118, 55152142, 28932738, + 36836594, 2682241, 25993170, 21075909 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 398001940109652, 1577721237663248, 1012748649830402, + 1540516006905144, 1011684812884559 +#else + 4364628, 5930691, 32304656, 23509878, 59054082, 15091130, + 22857016, 22955477, 31820367, 15075278 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1653276489969630, 6081825167624, 1921777941170836, + 1604139841794531, 861211053640641 +#else + 31879134, 24635739, 17258760, 90626, 59067028, 28636722, + 24162787, 23903546, 49138625, 12833044 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 996661541407379, 1455877387952927, 744312806857277, + 139213896196746, 1000282908547789 +#else + 19073683, 14851414, 42705695, 21694263, 7625277, 11091125, + 47489674, 2074448, 57694925, 14905376 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1450817495603008, 1476865707053229, 1030490562252053, + 620966950353376, 1744760161539058 +#else + 24483648, 21618865, 64589997, 22007013, 65555733, 15355505, + 41826784, 9253128, 27628530, 25998952 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 559728410002599, 37056661641185, 2038622963352006, + 1637244893271723, 1026565352238948 +#else + 17597607, 8340603, 19355617, 552187, 26198470, 30377849, + 4593323, 24396850, 52997988, 15297015 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 962165956135846, 1116599660248791, 182090178006815, + 1455605467021751, 196053588803284 +#else + 510886, 14337390, 35323607, 16638631, 6328095, 2713355, + 46891447, 21690211, 8683220, 2921426 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 796863823080135, 1897365583584155, 420466939481601, + 2165972651724672, 932177357788289 +#else + 18606791, 11874196, 27155355, 28272950, 43077121, 6265445, + 41930624, 32275507, 4674689, 13890525 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 877047233620632, 1375632631944375, 643773611882121, + 660022738847877, 19353932331831 +#else + 13609624, 13069022, 39736503, 20498523, 24360585, 9592974, + 14977157, 9835105, 4389687, 288396 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2216943882299338, 394841323190322, 2222656898319671, + 558186553950529, 1077236877025190 +#else + 9922506, 33035038, 13613106, 5883594, 48350519, 33120168, + 54804801, 8317627, 23388070, 16052080 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 801118384953213, 1914330175515892, 574541023311511, + 1471123787903705, 1526158900256288 +#else + 12719997, 11937594, 35138804, 28525742, 26900119, 8561328, + 46953177, 21921452, 52354592, 22741539 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 949617889087234, 2207116611267331, 912920039141287, + 501158539198789, 62362560771472 +#else + 15961858, 14150409, 26716931, 32888600, 44314535, 13603568, + 11829573, 7467844, 38286736, 929274 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1474518386765335, 1760793622169197, 1157399790472736, + 1622864308058898, 165428294422792 +#else + 11038231, 21972036, 39798381, 26237869, 56610336, 17246600, + 43629330, 24182562, 45715720, 2465073 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1961673048027128, 102619413083113, 1051982726768458, + 1603657989805485, 1941613251499678 +#else + 20017144, 29231206, 27915241, 1529148, 12396362, 15675764, + 13817261, 23896366, 2463390, 28932292 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1401939116319266, 335306339903072, 72046196085786, + 862423201496006, 850518754531384 +#else + 50749986, 20890520, 55043680, 4996453, 65852442, 1073571, + 9583558, 12851107, 4003896, 12673717 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1234706593321979, 1083343891215917, 898273974314935, + 1640859118399498, 157578398571149 +#else + 65377275, 18398561, 63845933, 16143081, 19294135, 13385325, + 14741514, 24450706, 7903885, 2348101 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1143483057726416, 1992614991758919, 674268662140796, + 1773370048077526, 674318359920189 +#else + 24536016, 17039225, 12715591, 29692277, 1511292, 10047386, + 63266518, 26425272, 38731325, 10048126 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1835401379538542, 173900035308392, 818247630716732, + 1762100412152786, 1021506399448291 +#else + 54486638, 27349611, 30718824, 2591312, 56491836, 12192839, + 18873298, 26257342, 34811107, 15221631 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1506632088156630, 2127481795522179, 513812919490255, + 140643715928370, 442476620300318 +#else + 40630742, 22450567, 11546243, 31701949, 9180879, 7656409, + 45764914, 2095754, 29769758, 6593415 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2056683376856736, 219094741662735, 2193541883188309, + 1841182310235800, 556477468664293 +#else + 35114656, 30646970, 4176911, 3264766, 12538965, 32686321, + 26312344, 27435754, 30958053, 8292160 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1315019427910827, 1049075855992603, 2066573052986543, + 266904467185534, 2040482348591520 +#else + 31429803, 19595316, 29173531, 15632448, 12174511, 30794338, + 32808830, 3977186, 26143136, 30405556 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 94096246544434, 922482381166992, 24517828745563, + 2139430508542503, 2097139044231004 +#else + 22648882, 1402143, 44308880, 13746058, 7936347, 365344, + 58440231, 31879998, 63350620, 31249806 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 537697207950515, 1399352016347350, 1563663552106345, + 2148749520888918, 549922092988516 +#else + 51616947, 8012312, 64594134, 20851969, 43143017, 23300402, + 65496150, 32018862, 50444388, 8194477 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1747985413252434, 680511052635695, 1809559829982725, + 594274250930054, 201673170745982 +#else + 27338066, 26047012, 59694639, 10140404, 48082437, 26964542, + 27277190, 8855376, 28572286, 3005164 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 323583936109569, 1973572998577657, 1192219029966558, + 79354804385273, 1374043025560347 +#else + 26287105, 4821776, 25476601, 29408529, 63344350, 17765447, + 49100281, 1182478, 41014043, 20474836 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 213277331329947, 416202017849623, 1950535221091783, + 1313441578103244, 2171386783823658 +#else + 59937691, 3178079, 23970071, 6201893, 49913287, 29065239, + 45232588, 19571804, 32208682, 32356184 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 189088804229831, 993969372859110, 895870121536987, + 1547301535298256, 1477373024911350 +#else + 50451143, 2817642, 56822502, 14811297, 6024667, 13349505, + 39793360, 23056589, 39436278, 22014573 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1620578418245010, 541035331188469, 2235785724453865, + 2154865809088198, 1974627268751826 +#else + 15941010, 24148500, 45741813, 8062054, 31876073, 33315803, + 51830470, 32110002, 15397330, 29424239 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1346805451740245, 1350981335690626, 942744349501813, + 2155094562545502, 1012483751693409 +#else + 8934485, 20068965, 43822466, 20131190, 34662773, 14047985, + 31170398, 32113411, 39603297, 15087183 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2107080134091762, 1132567062788208, 1824935377687210, + 769194804343737, 1857941799971888 +#else + 48751602, 31397940, 24524912, 16876564, 15520426, 27193656, + 51606457, 11461895, 16788528, 27685490 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1074666112436467, 249279386739593, 1174337926625354, + 1559013532006480, 1472287775519121 +#else + 65161459, 16013772, 21750665, 3714552, 49707082, 17498998, + 63338576, 23231111, 31322513, 21938797 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1872620123779532, 1892932666768992, 1921559078394978, + 1270573311796160, 1438913646755037 +#else + 21426636, 27904214, 53460576, 28206894, 38296674, 28633461, + 48833472, 18933017, 13040861, 21441484 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 837390187648199, 1012253300223599, 989780015893987, + 1351393287739814, 328627746545550 +#else + 11293895, 12478086, 39972463, 15083749, 37801443, 14748871, + 14555558, 20137329, 1613710, 4896935 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1028328827183114, 1711043289969857, 1350832470374933, + 1923164689604327, 1495656368846911 +#else + 41213962, 15323293, 58619073, 25496531, 25967125, 20128972, + 2825959, 28657387, 43137087, 22287016 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1900828492104143, 430212361082163, 687437570852799, + 832514536673512, 1685641495940794 +#else + 51184079, 28324551, 49665331, 6410663, 3622847, 10243618, + 20615400, 12405433, 43355834, 25118015 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 842632847936398, 605670026766216, 290836444839585, + 163210774892356, 2213815011799645 +#else + 60017550, 12556207, 46917512, 9025186, 50036385, 4333800, + 4378436, 2432030, 23097949, 32988414 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1176336383453996, 1725477294339771, 12700622672454, + 678015708818208, 162724078519879 +#else + 4565804, 17528778, 20084411, 25711615, 1724998, 189254, + 24767264, 10103221, 48596551, 2424777 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1448049969043497, 1789411762943521, 385587766217753, + 90201620913498, 832999441066823 +#else + 366633, 21577626, 8173089, 26664313, 30788633, 5745705, + 59940186, 1344108, 63466311, 12412658 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 516086333293313, 2240508292484616, 1351669528166508, + 1223255565316488, 750235824427138 +#else + 43107073, 7690285, 14929416, 33386175, 34898028, 20141445, + 24162696, 18227928, 63967362, 11179384 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1263624896582495, 1102602401673328, 526302183714372, + 2152015839128799, 1483839308490010 +#else + 18289503, 18829478, 8056944, 16430056, 45379140, 7842513, + 61107423, 32067534, 48424218, 22110928 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 442991718646863, 1599275157036458, 1925389027579192, + 899514691371390, 350263251085160 +#else + 476239, 6601091, 60956074, 23831056, 17503544, 28690532, + 27672958, 13403813, 11052904, 5219329 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1689713572022143, 593854559254373, 978095044791970, + 1985127338729499, 1676069120347625 +#else + 20678527, 25178694, 34436965, 8849122, 62099106, 14574751, + 31186971, 29580702, 9014761, 24975376 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1557207018622683, 340631692799603, 1477725909476187, + 614735951619419, 2033237123746766 +#else + 53464795, 23204192, 51146355, 5075807, 65594203, 22019831, + 34006363, 9160279, 8473550, 30297594 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 968764929340557, 1225534776710944, 662967304013036, + 1155521416178595, 791142883466590 +#else + 24900749, 14435722, 17209120, 18261891, 44516588, 9878982, + 59419555, 17218610, 42540382, 11788947 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1487081286167458, 993039441814934, 1792378982844640, + 698652444999874, 2153908693179754 +#else + 63990690, 22159237, 53306774, 14797440, 9652448, 26708528, + 47071426, 10410732, 42540394, 32095740 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1123181311102823, 685575944875442, 507605465509927, + 1412590462117473, 568017325228626 +#else + 51449703, 16736705, 44641714, 10215877, 58011687, 7563910, + 11871841, 21049238, 48595538, 8464117 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 560258797465417, 2193971151466401, 1824086900849026, + 579056363542056, 1690063960036441 +#else + 43708233, 8348506, 52522913, 32692717, 63158658, 27181012, + 14325288, 8628612, 33313881, 25183915 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1918407319222416, 353767553059963, 1930426334528099, + 1564816146005724, 1861342381708096 +#else + 46921872, 28586496, 22367355, 5271547, 66011747, 28765593, + 42303196, 23317577, 58168128, 27736162 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2131325168777276, 1176636658428908, 1756922641512981, + 1390243617176012, 1966325177038383 +#else + 60160060, 31759219, 34483180, 17533252, 32635413, 26180187, + 15989196, 20716244, 28358191, 29300528 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2063958120364491, 2140267332393533, 699896251574968, + 273268351312140, 375580724713232 +#else + 43547083, 30755372, 34757181, 31892468, 57961144, 10429266, + 50471180, 4072015, 61757200, 5596588 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2024297515263178, 416959329722687, 1079014235017302, + 171612225573183, 1031677520051053 +#else + 38872266, 30164383, 12312895, 6213178, 3117142, 16078565, + 29266239, 2557221, 1768301, 15373193 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2033900009388450, 1744902869870788, 2190580087917640, + 1949474984254121, 231049754293748 +#else + 59865506, 30307471, 62515396, 26001078, 66980936, 32642186, + 66017961, 29049440, 42448372, 3442909 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 343868674606581, 550155864008088, 1450580864229630, + 481603765195050, 896972360018042 +#else + 36898293, 5124042, 14181784, 8197961, 18964734, 21615339, + 22597930, 7176455, 48523386, 13365929 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2151139328380127, 314745882084928, 59756825775204, + 1676664391494651, 2048348075599360 +#else + 59231455, 32054473, 8324672, 4690079, 6261860, 890446, 24538107, + 24984246, 57419264, 30522764 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1528930066340597, 1605003907059576, 1055061081337675, + 1458319101947665, 1234195845213142 +#else + 25008885, 22782833, 62803832, 23916421, 16265035, 15721635, + 683793, 21730648, 15723478, 18390951 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 830430507734812, 1780282976102377, 1425386760709037, + 362399353095425, 2168861579799910 +#else + 57448220, 12374378, 40101865, 26528283, 59384749, 21239917, + 11879681, 5400171, 519526, 32318556 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1155762232730333, 980662895504006, 2053766700883521, + 490966214077606, 510405877041357 +#else + 22258397, 17222199, 59239046, 14613015, 44588609, 30603508, + 46754982, 7315966, 16648397, 7605640 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1683750316716132, 652278688286128, 1221798761193539, + 1897360681476669, 319658166027343 +#else + 59027556, 25089834, 58885552, 9719709, 19259459, 18206220, + 23994941, 28272877, 57640015, 4763277 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 618808732869972, 72755186759744, 2060379135624181, + 1730731526741822, 48862757828238 +#else + 45409620, 9220968, 51378240, 1084136, 41632757, 30702041, + 31088446, 25789909, 55752334, 728111 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1463171970593505, 1143040711767452, 614590986558883, + 1409210575145591, 1882816996436803 +#else + 26047201, 21802961, 60208540, 17032633, 24092067, 9158119, + 62835319, 20998873, 37743427, 28056159 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2230133264691131, 563950955091024, 2042915975426398, + 827314356293472, 672028980152815 +#else + 17510331, 33231575, 5854288, 8403524, 17133918, 30441820, + 38997856, 12327944, 10750447, 10014012 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 264204366029760, 1654686424479449, 2185050199932931, + 2207056159091748, 506015669043634 +#else + 56796096, 3936951, 9156313, 24656749, 16498691, 32559785, + 39627812, 32887699, 3424690, 7540221 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1784446333136569, 1973746527984364, 334856327359575, + 1156769775884610, 1023950124675478 +#else + 30322361, 26590322, 11361004, 29411115, 7433303, 4989748, + 60037442, 17237212, 57864598, 15258045 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2065270940578383, 31477096270353, 306421879113491, + 181958643936686, 1907105536686083 +#else + 13054543, 30774935, 19155473, 469045, 54626067, 4566041, + 5631406, 2711395, 1062915, 28418087 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1496516440779464, 1748485652986458, 872778352227340, + 818358834654919, 97932669284220 +#else + 47868616, 22299832, 37599834, 26054466, 61273100, 13005410, + 61042375, 12194496, 32960380, 1459310 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 471636015770351, 672455402793577, 1804995246884103, + 1842309243470804, 1501862504981682 +#else + 19852015, 7027924, 23669353, 10020366, 8586503, 26896525, + 394196, 27452547, 18638002, 22379495 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1013216974933691, 538921919682598, 1915776722521558, + 1742822441583877, 1886550687916656 +#else + 31395515, 15098109, 26581030, 8030562, 50580950, 28547297, + 9012485, 25970078, 60465776, 28111795 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2094270000643336, 303971879192276, 40801275554748, + 649448917027930, 1818544418535447 +#else + 57916680, 31207054, 65111764, 4529533, 25766844, 607986, + 67095642, 9677542, 34813975, 27098423 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2241737709499165, 549397817447461, 838180519319392, + 1725686958520781, 1705639080897747 +#else + 64664349, 33404494, 29348901, 8186665, 1873760, 12489863, + 36174285, 25714739, 59256019, 25416002 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1216074541925116, 50120933933509, 1565829004133810, + 721728156134580, 349206064666188 +#else + 51872508, 18120922, 7766469, 746860, 26346930, 23332670, + 39775412, 10754587, 57677388, 5203575 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 948617110470858, 346222547451945, 1126511960599975, + 1759386906004538, 493053284802266 +#else + 31834314, 14135496, 66338857, 5159117, 20917671, 16786336, + 59640890, 26216907, 31809242, 7347066 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1454933046815146, 874696014266362, 1467170975468588, + 1432316382418897, 2111710746366763 +#else + 57502122, 21680191, 20414458, 13033986, 13716524, 21862551, + 19797969, 21343177, 15192875, 31466942 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2105387117364450, 1996463405126433, 1303008614294500, + 851908115948209, 1353742049788635 +#else + 54445282, 31372712, 1168161, 29749623, 26747876, 19416341, + 10609329, 12694420, 33473243, 20172328 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 750300956351719, 1487736556065813, 15158817002104, + 1511998221598392, 971739901354129 +#else + 33184999, 11180355, 15832085, 22169002, 65475192, 225883, + 15089336, 22530529, 60973201, 14480052 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1874648163531693, 2124487685930551, 1810030029384882, + 918400043048335, 586348627300650 +#else + 31308717, 27934434, 31030839, 31657333, 15674546, 26971549, + 5496207, 13685227, 27595050, 8737275 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1235084464747900, 1166111146432082, 1745394857881591, + 1405516473883040, 4463504151617 +#else + 46790012, 18404192, 10933842, 17376410, 8335351, 26008410, + 36100512, 20943827, 26498113, 66511 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1663810156463827, 327797390285791, 1341846161759410, + 1964121122800605, 1747470312055380 +#else + 22644435, 24792703, 50437087, 4884561, 64003250, 19995065, + 30540765, 29267685, 53781076, 26039336 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 660005247548233, 2071860029952887, 1358748199950107, + 911703252219107, 1014379923023831 +#else + 39091017, 9834844, 18617207, 30873120, 63706907, 20246925, + 8205539, 13585437, 49981399, 15115438 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2206641276178231, 1690587809721504, 1600173622825126, + 2156096097634421, 1106822408548216 +#else + 23711543, 32881517, 31206560, 25191721, 6164646, 23844445, + 33572981, 32128335, 8236920, 16492939 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1344788193552206, 1949552134239140, 1735915881729557, + 675891104100469, 1834220014427292 +#else + 43198286, 20038905, 40809380, 29050590, 25005589, 25867162, + 19574901, 10071562, 6708380, 27332008 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1920949492387964, 158885288387530, 70308263664033, + 626038464897817, 1468081726101009 +#else + 2101372, 28624378, 19702730, 2367575, 51681697, 1047674, + 5301017, 9328700, 29955601, 21876122 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 622221042073383, 1210146474039168, 1742246422343683, + 1403839361379025, 417189490895736 +#else + 3096359, 9271816, 45488000, 18032587, 52260867, 25961494, + 41216721, 20918836, 57191288, 6216607 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 22727256592983, 168471543384997, 1324340989803650, + 1839310709638189, 504999476432775 +#else + 34493015, 338662, 41913253, 2510421, 37895298, 19734218, + 24822829, 27407865, 40341383, 7525078 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1313240518756327, 1721896294296942, 52263574587266, + 2065069734239232, 804910473424630 +#else + 44042215, 19568808, 16133486, 25658254, 63719298, 778787, + 66198528, 30771936, 47722230, 11994100 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1337466662091884, 1287645354669772, 2018019646776184, + 652181229374245, 898011753211715 +#else + 21691500, 19929806, 66467532, 19187410, 3285880, 30070836, + 42044197, 9718257, 59631427, 13381417 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1969792547910734, 779969968247557, 2011350094423418, + 1823964252907487, 1058949448296945 +#else + 18445390, 29352196, 14979845, 11622458, 65381754, 29971451, + 23111647, 27179185, 28535281, 15779576 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 207343737062002, 1118176942430253, 758894594548164, + 806764629546266, 1157700123092949 +#else + 30098034, 3089662, 57874477, 16662134, 45801924, 11308410, + 53040410, 12021729, 9955285, 17251076 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1273565321399022, 1638509681964574, 759235866488935, + 666015124346707, 897983460943405 +#else + 9734894, 18977602, 59635230, 24415696, 2060391, 11313496, + 48682835, 9924398, 20194861, 13380996 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1717263794012298, 1059601762860786, 1837819172257618, + 1054130665797229, 680893204263559 +#else + 40730762, 25589224, 44941042, 15789296, 49053522, 27385639, + 65123949, 15707770, 26342023, 10146099 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2237039662793603, 2249022333361206, 2058613546633703, + 149454094845279, 2215176649164582 +#else + 41091971, 33334488, 21339190, 33513044, 19745255, 30675732, + 37471583, 2227039, 21612326, 33008704 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 79472182719605, 1851130257050174, 1825744808933107, + 821667333481068, 781795293511946 +#else + 54031477, 1184227, 23562814, 27583990, 46757619, 27205717, + 25764460, 12243797, 46252298, 11649657 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 755822026485370, 152464789723500, 1178207602290608, + 410307889503239, 156581253571278 +#else + 57077370, 11262625, 27384172, 2271902, 26947504, 17556661, + 39943, 6114064, 33514190, 2333242 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1418185496130297, 484520167728613, 1646737281442950, + 1401487684670265, 1349185550126961 +#else + 45675257, 21132610, 8119781, 7219913, 45278342, 24538297, + 60429113, 20883793, 24350577, 20104431 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1495380034400429, 325049476417173, 46346894893933, + 1553408840354856, 828980101835683 +#else + 62992557, 22282898, 43222677, 4843614, 37020525, 690622, + 35572776, 23147595, 8317859, 12352766 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1280337889310282, 2070832742866672, 1640940617225222, + 2098284908289951, 450929509534434 +#else + 18200138, 19078521, 34021104, 30857812, 43406342, 24451920, + 43556767, 31266881, 20712162, 6719373 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 407703353998781, 126572141483652, 286039827513621, + 1999255076709338, 2030511179441770 +#else + 26656189, 6075253, 59250308, 1886071, 38764821, 4262325, + 11117530, 29791222, 26224234, 30256974 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1254958221100483, 1153235960999843, 942907704968834, + 637105404087392, 1149293270147267 +#else + 49939907, 18700334, 63713187, 17184554, 47154818, 14050419, + 21728352, 9493610, 18620611, 17125804 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 894249020470196, 400291701616810, 406878712230981, + 1599128793487393, 1145868722604026 +#else + 53785524, 13325348, 11432106, 5964811, 18609221, 6062965, + 61839393, 23828875, 36407290, 17074774 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1497955250203334, 110116344653260, 1128535642171976, + 1900106496009660, 129792717460909 +#else + 43248326, 22321272, 26961356, 1640861, 34695752, 16816491, + 12248508, 28313793, 13735341, 1934062 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 452487513298665, 1352120549024569, 1173495883910956, + 1999111705922009, 367328130454226 +#else + 25089769, 6742589, 17081145, 20148166, 21909292, 17486451, + 51972569, 29789085, 45830866, 5473615 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1717539401269642, 1475188995688487, 891921989653942, + 836824441505699, 1885988485608364 +#else + 31883658, 25593331, 1083431, 21982029, 22828470, 13290673, + 59983779, 12469655, 29111212, 28103418 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1241784121422547, 187337051947583, 1118481812236193, + 428747751936362, 30358898927325 +#else + 24244947, 18504025, 40845887, 2791539, 52111265, 16666677, + 24367466, 6388839, 56813277, 452382 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2022432361201842, 1088816090685051, 1977843398539868, + 1854834215890724, 564238862029357 +#else + 41468082, 30136590, 5217915, 16224624, 19987036, 29472163, + 42872612, 27639183, 15766061, 8407814 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 938868489100585, 1100285072929025, 1017806255688848, + 1957262154788833, 152787950560442 +#else + 46701865, 13990230, 15495425, 16395525, 5377168, 15166495, + 58191841, 29165478, 59040954, 2276717 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 867319417678923, 620471962942542, 226032203305716, + 342001443957629, 1761675818237336 +#else + 30157899, 12924066, 49396814, 9245752, 19895028, 3368142, + 43281277, 5096218, 22740376, 26251015 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1295072362439987, 931227904689414, 1355731432641687, + 922235735834035, 892227229410209 +#else + 2041139, 19298082, 7783686, 13876377, 41161879, 20201972, + 24051123, 13742383, 51471265, 13295221 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1680989767906154, 535362787031440, 2136691276706570, + 1942228485381244, 1267350086882274 +#else + 33338218, 25048699, 12532112, 7977527, 9106186, 31839181, + 49388668, 28941459, 62657506, 18884987 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 366018233770527, 432660629755596, 126409707644535, + 1973842949591662, 645627343442376 +#else + 47063583, 5454096, 52762316, 6447145, 28862071, 1883651, + 64639598, 29412551, 7770568, 9620597 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 535509430575217, 546885533737322, 1524675609547799, + 2138095752851703, 1260738089896827 +#else + 23208049, 7979712, 33071466, 8149229, 1758231, 22719437, + 30945527, 31860109, 33606523, 18786461 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1159906385590467, 2198530004321610, 714559485023225, + 81880727882151, 1484020820037082 +#else + 1439939, 17283952, 66028874, 32760649, 4625401, 10647766, + 62065063, 1220117, 30494170, 22113633 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1377485731340769, 2046328105512000, 1802058637158797, + 62146136768173, 1356993908853901 +#else + 62071265, 20526136, 64138304, 30492664, 15640973, 26852766, + 40369837, 926049, 65424525, 20220784 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2013612215646735, 1830770575920375, 536135310219832, + 609272325580394, 270684344495013 +#else + 13908495, 30005160, 30919927, 27280607, 45587000, 7989038, + 9021034, 9078865, 3353509, 4033511 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1237542585982777, 2228682050256790, 1385281931622824, + 593183794882890, 493654978552689 +#else + 37445433, 18440821, 32259990, 33209950, 24295848, 20642309, + 23161162, 8839127, 27485041, 7356032 +#endif + }}, + }, + }, + { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 47341488007760, 1891414891220257, 983894663308928, + 176161768286818, 1126261115179708 +#else + 9661008, 705443, 11980065, 28184278, 65480320, 14661172, + 60762722, 2625014, 28431036, 16782598 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1694030170963455, 502038567066200, 1691160065225467, + 949628319562187, 275110186693066 +#else + 43269631, 25243016, 41163352, 7480957, 49427195, 25200248, + 44562891, 14150564, 15970762, 4099461 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1124515748676336, 1661673816593408, 1499640319059718, + 1584929449166988, 558148594103306 +#else + 29262576, 16756590, 26350592, 24760869, 8529670, 22346382, + 13617292, 23617289, 11465738, 8317062 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1784525599998356, 1619698033617383, 2097300287550715, + 258265458103756, 1905684794832758 +#else + 41615764, 26591503, 32500199, 24135381, 44070139, 31252209, + 14898636, 3848455, 20969334, 28396916 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1288941072872766, 931787902039402, 190731008859042, + 2006859954667190, 1005931482221702 +#else + 46724414, 19206718, 48772458, 13884721, 34069410, 2842113, + 45498038, 29904543, 11177094, 14989547 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1465551264822703, 152905080555927, 680334307368453, + 173227184634745, 666407097159852 +#else + 42612143, 21838415, 16959895, 2278463, 12066309, 10137771, + 13515641, 2581286, 38621356, 9930239 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2111017076203943, 1378760485794347, 1248583954016456, + 1352289194864422, 1895180776543896 +#else + 49357223, 31456605, 16544299, 20545132, 51194056, 18605350, + 18345766, 20150679, 16291480, 28240394 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 171348223915638, 662766099800389, 462338943760497, + 466917763340314, 656911292869115 +#else + 33879670, 2553287, 32678213, 9875984, 8534129, 6889387, + 57432090, 6957616, 4368891, 9788741 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 488623681976577, 866497561541722, 1708105560937768, + 1673781214218839, 1506146329818807 +#else + 16660737, 7281060, 56278106, 12911819, 20108584, 25452756, + 45386327, 24941283, 16250551, 22443329 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 160425464456957, 950394373239689, 430497123340934, + 711676555398832, 320964687779005 +#else + 47343357, 2390525, 50557833, 14161979, 1905286, 6414907, + 4689584, 10604807, 36918461, 4782746 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 988979367990485, 1359729327576302, 1301834257246029, + 294141160829308, 29348272277475 +#else + 65754325, 14736940, 59741422, 20261545, 7710541, 19398842, + 57127292, 4383044, 22546403, 437323 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1434382743317910, 100082049942065, 221102347892623, + 186982837860588, 1305765053501834 +#else + 31665558, 21373968, 50922033, 1491338, 48740239, 3294681, + 27343084, 2786261, 36475274, 19457415 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2205916462268190, 499863829790820, 961960554686616, + 158062762756985, 1841471168298305 +#else + 52641566, 32870716, 33734756, 7448551, 19294360, 14334329, + 47418233, 2355318, 47824193, 27440058 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1191737341426592, 1847042034978363, 1382213545049056, + 1039952395710448, 788812858896859 +#else + 15121312, 17758270, 6377019, 27523071, 56310752, 20596586, + 18952176, 15496498, 37728731, 11754227 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1346965964571152, 1291881610839830, 2142916164336056, + 786821641205979, 1571709146321039 +#else + 64471568, 20071356, 8488726, 19250536, 12728760, 31931939, + 7141595, 11724556, 22761615, 23420291 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 787164375951248, 202869205373189, 1356590421032140, + 1431233331032510, 786341368775957 +#else + 16918416, 11729663, 49025285, 3022986, 36093132, 20214772, + 38367678, 21327038, 32851221, 11717399 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 492448143532951, 304105152670757, 1761767168301056, + 233782684697790, 1981295323106089 +#else + 11166615, 7338049, 60386341, 4531519, 37640192, 26252376, + 31474878, 3483633, 65915689, 29523600 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 665807507761866, 1343384868355425, 895831046139653, + 439338948736892, 1986828765695105 +#else + 66923210, 9921304, 31456609, 20017994, 55095045, 13348922, + 33142652, 6546660, 47123585, 29606055 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 756096210874553, 1721699973539149, 258765301727885, + 1390588532210645, 1212530909934781 +#else + 34648249, 11266711, 55911757, 25655328, 31703693, 3855903, + 58571733, 20721383, 36336829, 18068118 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 852891097972275, 1816988871354562, 1543772755726524, + 1174710635522444, 202129090724628 +#else + 49102387, 12709067, 3991746, 27075244, 45617340, 23004006, + 35973516, 17504552, 10928916, 3011958 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1205281565824323, 22430498399418, 992947814485516, + 1392458699738672, 688441466734558 +#else + 60151107, 17960094, 31696058, 334240, 29576716, 14796075, + 36277808, 20749251, 18008030, 10258577 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1050627428414972, 1955849529137135, 2171162376368357, + 91745868298214, 447733118757826 +#else + 44660220, 15655568, 7018479, 29144429, 36794597, 32352840, + 65255398, 1367119, 25127874, 6671743 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1287181461435438, 622722465530711, 880952150571872, + 741035693459198, 311565274989772 +#else + 29701166, 19180498, 56230743, 9279287, 67091296, 13127209, + 21382910, 11042292, 25838796, 4642684 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1003649078149734, 545233927396469, 1849786171789880, + 1318943684880434, 280345687170552 +#else + 46678630, 14955536, 42982517, 8124618, 61739576, 27563961, + 30468146, 19653792, 18423288, 4177476 +#endif + }}, + }, + }, +}; + +#endif // CONFIG_SMALL + +// Bi[i] = (2*i+1)*B +static const ge_precomp Bi[8] = { + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1288382639258501, 245678601348599, 269427782077623, + 1462984067271730, 137412439391563 +#else + 25967493, 19198397, 29566455, 3660896, 54414519, 4014786, 27544626, + 21800161, 61029707, 2047604 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 62697248952638, 204681361388450, 631292143396476, 338455783676468, + 1213667448819585 +#else + 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, + 5043384, 19500929, 18085054 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 301289933810280, 1259582250014073, 1422107436869536, + 796239922652654, 1953934009299142 +#else + 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, + 11864899, 42594502, 29115885 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1601611775252272, 1720807796594148, 1132070835939856, + 1260455018889551, 2147779492816911 +#else + 15636272, 23865875, 24204772, 25642034, 616976, 16869170, 27787599, + 18782243, 28944399, 32004408 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 316559037616741, 2177824224946892, 1459442586438991, + 1461528397712656, 751590696113597 +#else + 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, + 21778470, 7689661, 11199574 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1850748884277385, 1200145853858453, 1068094770532492, + 672251375690438, 1586055907191707 +#else + 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, + 10017326, 49359771, 23634074 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 769950342298419, 132954430919746, 844085933195555, 974092374476333, + 726076285546016 +#else + 10861363, 11473154, 27284546, 1981175, 37044515, 12577860, 32867885, + 14515107, 51670560, 10819379 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 425251763115706, 608463272472562, 442562545713235, 837766094556764, + 374555092627893 +#else + 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, + 12483687, 54440373, 5581305 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1086255230780037, 274979815921559, 1960002765731872, + 929474102396301, 1190409889297339 +#else + 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, + 13850243, 43430843, 17738489 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 665000864555967, 2065379846933859, 370231110385876, 350988370788628, + 1233371373142985 +#else + 5153727, 9909285, 1723747, 30776558, 30523604, 5516873, 19480852, + 5230134, 43156425, 18378665 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2019367628972465, 676711900706637, 110710997811333, + 1108646842542025, 517791959672113 +#else + 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, + 16520125, 30598449, 7715701 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 965130719900578, 247011430587952, 526356006571389, 91986625355052, + 2157223321444601 +#else + 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, + 1370707, 29794553, 32145132 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1802695059465007, 1664899123557221, 593559490740857, + 2160434469266659, 927570450755031 +#else + 44589871, 26862249, 14201701, 24808930, 43598457, 8844725, 18474211, + 32192982, 54046167, 13821876 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1725674970513508, 1933645953859181, 1542344539275782, + 1767788773573747, 1297447965928905 +#else + 60653668, 25714560, 3374701, 28813570, 40010246, 22982724, 31655027, + 26342105, 18853321, 19333481 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1381809363726107, 1430341051343062, 2061843536018959, + 1551778050872521, 2036394857967624 +#else + 4566811, 20590564, 38133974, 21313742, 59506191, 30723862, 58594505, + 23123294, 2207752, 30344648 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1970894096313054, 528066325833207, 1619374932191227, + 2207306624415883, 1169170329061080 +#else + 41954014, 29368610, 29681143, 7868801, 60254203, 24130566, 54671499, + 32891431, 35997400, 17421995 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 2070390218572616, 1458919061857835, 624171843017421, + 1055332792707765, 433987520732508 +#else + 25576264, 30851218, 7349803, 21739588, 16472781, 9300885, 3844789, + 15725684, 171356, 6466918 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 893653801273833, 1168026499324677, 1242553501121234, + 1306366254304474, 1086752658510815 +#else + 23103977, 13316479, 9739013, 17404951, 817874, 18515490, 8965338, + 19466374, 36393951, 16193876 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 213454002618221, 939771523987438, 1159882208056014, 317388369627517, + 621213314200687 +#else + 33587053, 3180712, 64714734, 14003686, 50205390, 17283591, 17238397, + 4729455, 49034351, 9256799 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1971678598905747, 338026507889165, 762398079972271, 655096486107477, + 42299032696322 +#else + 41926547, 29380300, 32336397, 5036987, 45872047, 11360616, 22616405, + 9761698, 47281666, 630304 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 177130678690680, 1754759263300204, 1864311296286618, + 1180675631479880, 1292726903152791 +#else + 53388152, 2639452, 42871404, 26147950, 9494426, 27780403, 60554312, + 17593437, 64659607, 19263131 +#endif + }}, + }, + { + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1913163449625248, 460779200291993, 2193883288642314, + 1008900146920800, 1721983679009502 +#else + 63957664, 28508356, 9282713, 6866145, 35201802, 32691408, 48168288, + 15033783, 25105118, 25659556 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 1070401523076875, 1272492007800961, 1910153608563310, + 2075579521696771, 1191169788841221 +#else + 42782475, 15950225, 35307649, 18961608, 55446126, 28463506, 1573891, + 30928545, 2198789, 17749813 +#endif + }}, + {{ +#if defined(BORINGSSL_CURVE25519_64BIT) + 692896803108118, 500174642072499, 2068223309439677, + 1162190621851337, 1426986007309901 +#else + 64009494, 10324966, 64867251, 7453182, 61661885, 30818928, 53296841, + 17317989, 34647629, 21263748 +#endif + }}, + }, +}; diff --git a/src/plugins/preauth/spake/groups.c b/src/plugins/preauth/spake/groups.c new file mode 100644 index 000000000..a195cc195 --- /dev/null +++ b/src/plugins/preauth/spake/groups.c @@ -0,0 +1,442 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/groups.c - SPAKE group interfaces */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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. + */ + +/* + * The SPAKE2 algorithm works as follows: + * + * 1. The parties agree on a group, a base element G, and constant elements M + * and N. In this mechanism, these parameters are determined by the + * registered group number. + * 2. Both parties derive a scalar value w from the initial key. + * 3. The first party (the KDC, in this mechanism) chooses a random secret + * scalar x and sends T=xG+wM. + * 4. The second party (the client, in this mechanism) chooses a random + * secret scalar y and sends S=yG+wN. + * 5. The first party computes K=x(S-wN). + * 6. The second party computes the same value as K=y(T-wM). + * 7. Both parties derive a key from a random oracle whose input incorporates + * the party identities, w, T, S, and K. + * + * We implement the algorithm using a vtable for each group, where the primary + * vtable methods are "keygen" (corresponding to step 3 or 4) and "result" + * (corresponding to step 5 or 6). We use the term "private scalar" to refer + * to x or y, and "public element" to refer to S or T. + */ + +#include "iana.h" +#include "trace.h" +#include "groups.h" + +#define DEFAULT_GROUPS_CLIENT "edwards25519" +#define DEFAULT_GROUPS_KDC "" + +typedef struct groupent_st { + const groupdef *gdef; + groupdata *gdata; +} groupent; + +struct groupstate_st { + krb5_boolean is_kdc; + + /* Permitted and groups, from configuration */ + int32_t *permitted; + size_t npermitted; + + /* Optimistic challenge group, from configuration */ + int32_t challenge_group; + + /* Lazily-initialized list of gdata objects. */ + groupent *data; + size_t ndata; +}; + +extern groupdef builtin_edwards25519; +#ifdef SPAKE_OPENSSL +extern groupdef ossl_P256; +extern groupdef ossl_P384; +extern groupdef ossl_P521; +#endif + +static const groupdef *groupdefs[] = { + &builtin_edwards25519, +#ifdef SPAKE_OPENSSL + &ossl_P256, + &ossl_P384, + &ossl_P521, +#endif + NULL +}; + +/* Find a groupdef structure by group number. Return NULL on failure. */ +static const groupdef * +find_gdef(int32_t group) +{ + size_t i; + + for (i = 0; groupdefs[i] != NULL; i++) { + if (groupdefs[i]->reg->id == group) + return groupdefs[i]; + } + + return NULL; +} + +/* Find a group number by name. Return 0 on failure. */ +static int32_t +find_gnum(const char *name) +{ + size_t i; + + for (i = 0; groupdefs[i] != NULL; i++) { + if (strcasecmp(name, groupdefs[i]->reg->name) == 0) + return groupdefs[i]->reg->id; + } + return 0; +} + +static krb5_boolean +in_grouplist(const int32_t *list, size_t count, int32_t group) +{ + size_t i; + + for (i = 0; i < count; i++) { + if (list[i] == group) + return TRUE; + } + + return FALSE; +} + +/* Retrieve a group data object for group within gstate, lazily initializing it + * if necessary. */ +static krb5_error_code +get_gdata(krb5_context context, groupstate *gstate, const groupdef *gdef, + groupdata **gdata_out) +{ + krb5_error_code ret; + groupent *ent, *newptr; + + *gdata_out = NULL; + + /* Look for an existing entry. */ + for (ent = gstate->data; ent < gstate->data + gstate->ndata; ent++) { + if (ent->gdef == gdef) { + *gdata_out = ent->gdata; + return 0; + } + } + + /* Make a new entry. */ + newptr = realloc(gstate->data, (gstate->ndata + 1) * sizeof(groupent)); + if (newptr == NULL) + return ENOMEM; + gstate->data = newptr; + ent = &gstate->data[gstate->ndata]; + ent->gdef = gdef; + ent->gdata = NULL; + if (gdef->init != NULL) { + ret = gdef->init(context, gdef, &ent->gdata); + if (ret) + return ret; + } + gstate->ndata++; + *gdata_out = ent->gdata; + return 0; +} + +/* Destructively parse str into a list of group numbers. */ +static krb5_error_code +parse_groups(krb5_context context, char *str, int32_t **list_out, + size_t *count_out) +{ + const char *const delim = " \t\r\n,"; + char *token, *save = NULL; + int32_t group, *newptr, *list = NULL; + size_t count = 0; + + *list_out = NULL; + *count_out = 0; + + /* Walk through the words in profstr. */ + for (token = strtok_r(str, delim, &save); token != NULL; + token = strtok_r(NULL, delim, &save)) { + group = find_gnum(token); + if (!group) { + TRACE_SPAKE_UNKNOWN_GROUP(context, token); + continue; + } + if (in_grouplist(list, count, group)) + continue; + newptr = realloc(list, (count + 1) * sizeof(*list)); + if (newptr == NULL) { + free(list); + return ENOMEM; + } + list = newptr; + list[count++] = group; + } + + *list_out = list; + *count_out = count; + return 0; +} + +krb5_error_code +group_init_state(krb5_context context, krb5_boolean is_kdc, + groupstate **gstate_out) +{ + krb5_error_code ret; + groupstate *gstate; + const char *defgroups; + char *profstr1 = NULL, *profstr2 = NULL; + int32_t *permitted = NULL, challenge_group = 0; + size_t npermitted; + + *gstate_out = NULL; + + defgroups = is_kdc ? DEFAULT_GROUPS_KDC : DEFAULT_GROUPS_CLIENT; + ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS, + KRB5_CONF_SPAKE_PREAUTH_GROUPS, NULL, defgroups, + &profstr1); + if (ret) + goto cleanup; + ret = parse_groups(context, profstr1, &permitted, &npermitted); + if (ret) + goto cleanup; + if (npermitted == 0) { + ret = KRB5_PLUGIN_OP_NOTSUPP; + k5_setmsg(context, ret, _("No SPAKE preauth groups configured")); + goto cleanup; + } + + if (is_kdc) { + /* + * Check for a configured optimistic challenge group. If one is set, + * the KDC will send a challenge in the PREAUTH_REQUIRED method data, + * before receiving the list of supported groups. + */ + ret = profile_get_string(context->profile, KRB5_CONF_KDCDEFAULTS, + KRB5_CONF_SPAKE_PREAUTH_KDC_CHALLENGE, NULL, + NULL, &profstr2); + if (ret) + goto cleanup; + if (profstr2 != NULL) { + challenge_group = find_gnum(profstr2); + if (!in_grouplist(permitted, npermitted, challenge_group)) { + ret = KRB5_PLUGIN_OP_NOTSUPP; + k5_setmsg(context, ret, + _("SPAKE challenge group not a permitted group: %s"), + profstr2); + goto cleanup; + } + } + } + + gstate = k5alloc(sizeof(*gstate), &ret); + if (gstate == NULL) + goto cleanup; + gstate->is_kdc = is_kdc; + gstate->permitted = permitted; + gstate->npermitted = npermitted; + gstate->challenge_group = challenge_group; + permitted = NULL; + gstate->data = NULL; + gstate->ndata = 0; + *gstate_out = gstate; + +cleanup: + profile_release_string(profstr1); + profile_release_string(profstr2); + free(permitted); + return ret; +} + + +void +group_free_state(groupstate *gstate) +{ + groupent *ent; + + for (ent = gstate->data; ent < gstate->data + gstate->ndata; ent++) { + if (ent->gdata != NULL && ent->gdef->fini != NULL) + ent->gdef->fini(ent->gdata); + } + + free(gstate->permitted); + free(gstate->data); + free(gstate); +} + +krb5_boolean +group_is_permitted(groupstate *gstate, int32_t group) +{ + return in_grouplist(gstate->permitted, gstate->npermitted, group); +} + +void +group_get_permitted(groupstate *gstate, int32_t **list_out, int32_t *count_out) +{ + *list_out = gstate->permitted; + *count_out = gstate->npermitted; +} + +krb5_int32 +group_optimistic_challenge(groupstate *gstate) +{ + assert(gstate->is_kdc); + return gstate->challenge_group; +} + +krb5_error_code +group_mult_len(int32_t group, size_t *len_out) +{ + const groupdef *gdef; + + *len_out = 0; + gdef = find_gdef(group); + if (gdef == NULL) + return EINVAL; + *len_out = gdef->reg->mult_len; + return 0; +} + +krb5_error_code +group_keygen(krb5_context context, groupstate *gstate, int32_t group, + const krb5_data *wbytes, krb5_data *priv_out, krb5_data *pub_out) +{ + krb5_error_code ret; + const groupdef *gdef; + groupdata *gdata; + uint8_t *priv = NULL, *pub = NULL; + + *priv_out = empty_data(); + *pub_out = empty_data(); + gdef = find_gdef(group); + if (gdef == NULL || wbytes->length != gdef->reg->mult_len) + return EINVAL; + ret = get_gdata(context, gstate, gdef, &gdata); + if (ret) + return ret; + + priv = k5alloc(gdef->reg->mult_len, &ret); + if (priv == NULL) + goto cleanup; + pub = k5alloc(gdef->reg->elem_len, &ret); + if (pub == NULL) + goto cleanup; + + ret = gdef->keygen(context, gdata, (uint8_t *)wbytes->data, gstate->is_kdc, + priv, pub); + if (ret) + goto cleanup; + + *priv_out = make_data(priv, gdef->reg->mult_len); + *pub_out = make_data(pub, gdef->reg->elem_len); + priv = pub = NULL; + TRACE_SPAKE_KEYGEN(context, pub_out); + +cleanup: + zapfree(priv, gdef->reg->mult_len); + free(pub); + return ret; +} + +krb5_error_code +group_result(krb5_context context, groupstate *gstate, int32_t group, + const krb5_data *wbytes, const krb5_data *ourpriv, + const krb5_data *theirpub, krb5_data *spakeresult_out) +{ + krb5_error_code ret; + const groupdef *gdef; + groupdata *gdata; + uint8_t *spakeresult = NULL; + + *spakeresult_out = empty_data(); + gdef = find_gdef(group); + if (gdef == NULL || wbytes->length != gdef->reg->mult_len) + return EINVAL; + if (ourpriv->length != gdef->reg->mult_len || + theirpub->length != gdef->reg->elem_len) + return EINVAL; + ret = get_gdata(context, gstate, gdef, &gdata); + if (ret) + return ret; + + spakeresult = k5alloc(gdef->reg->elem_len, &ret); + if (spakeresult == NULL) + goto cleanup; + + /* Invert is_kdc here to use the other party's constant. */ + ret = gdef->result(context, gdata, (uint8_t *)wbytes->data, + (uint8_t *)ourpriv->data, (uint8_t *)theirpub->data, + !gstate->is_kdc, spakeresult); + if (ret) + goto cleanup; + + *spakeresult_out = make_data(spakeresult, gdef->reg->elem_len); + spakeresult = NULL; + TRACE_SPAKE_RESULT(context, spakeresult_out); + +cleanup: + zapfree(spakeresult, gdef->reg->elem_len); + return ret; +} + +krb5_error_code +group_hash_len(int32_t group, size_t *len_out) +{ + const groupdef *gdef; + + *len_out = 0; + gdef = find_gdef(group); + if (gdef == NULL) + return EINVAL; + *len_out = gdef->reg->hash_len; + return 0; +} + +krb5_error_code +group_hash(krb5_context context, groupstate *gstate, int32_t group, + const krb5_data *dlist, size_t ndata, uint8_t *result_out) +{ + krb5_error_code ret; + const groupdef *gdef; + groupdata *gdata; + + gdef = find_gdef(group); + if (gdef == NULL) + return EINVAL; + ret = get_gdata(context, gstate, gdef, &gdata); + if (ret) + return ret; + return gdef->hash(context, gdata, dlist, ndata, result_out); +} diff --git a/src/plugins/preauth/spake/groups.h b/src/plugins/preauth/spake/groups.h new file mode 100644 index 000000000..3add69494 --- /dev/null +++ b/src/plugins/preauth/spake/groups.h @@ -0,0 +1,148 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/groups.h - SPAKE group interfaces */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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. + */ + +#ifndef GROUPS_H +#define GROUPS_H + +#include "k5-int.h" +#include "iana.h" + +typedef struct groupstate_st groupstate; +typedef struct groupdata_st groupdata; +typedef struct groupdef_st groupdef; + +struct groupdef_st { + const spake_iana *reg; + + /* + * Optional: create a per-group data object to allow more efficient keygen + * and result computations. Saving a reference to gdef is okay; its + * lifetime will always be longer than the resulting object. + */ + krb5_error_code (*init)(krb5_context context, const groupdef *gdef, + groupdata **gdata_out); + + /* Optional: release a group data object. */ + void (*fini)(groupdata *gdata); + + /* + * Mandatory: generate a random private scalar (x or y) and a public + * element (T or S), using wbytes for the w value. If use_m is true, use + * the M element (generating T); otherwise use the N element (generating + * S). wbytes and priv_out have length reg->mult_len; pub_out has length + * reg->elem_len. priv_out and pub_out are caller-allocated. + */ + krb5_error_code (*keygen)(krb5_context context, groupdata *gdata, + const uint8_t *wbytes, krb5_boolean use_m, + uint8_t *priv_out, uint8_t *pub_out); + + /* + * Mandatory: compute K given a private scalar (x or y) and the other + * party's public element (S or T), using wbytes for the w value. If use_m + * is true, use the M element (computing K from y and T); otherwise use the + * N element (computing K from x and S). wbytes and ourpriv have length + * reg->mult_len; theirpub and elem_out have length reg->elem_len. + * elem_out is caller-allocated. + */ + krb5_error_code (*result)(krb5_context context, groupdata *gdata, + const uint8_t *wbytes, const uint8_t *ourpriv, + const uint8_t *theirpub, krb5_boolean use_m, + uint8_t *elem_out); + + /* + * Mandatory: compute the group's specified hash function over datas (with + * ndata elements), placing the result in result_out. result_out is + * caller-allocated with length reg->hash_len. + */ + krb5_error_code (*hash)(krb5_context context, groupdata *gdata, + const krb5_data *datas, size_t ndata, + uint8_t *result_out); +}; + +/* Initialize an object which holds group configuration and pre-computation + * state for each group. is_kdc is true for KDCs, false for clients. */ +krb5_error_code group_init_state(krb5_context context, krb5_boolean is_kdc, + groupstate **out); + +/* Release resources held by gstate. */ +void group_free_state(groupstate *gstate); + +/* Return true if group is permitted by configuration. */ +krb5_boolean group_is_permitted(groupstate *gstate, int32_t group); + +/* Set *list_out and *count_out to the list of groups permitted by + * configuration. */ +void group_get_permitted(groupstate *gstate, int32_t **list_out, + int32_t *count_out); + +/* Return the KDC optimistic challenge group if one is configured. Valid for + * KDC groupstate objects only. */ +krb5_int32 group_optimistic_challenge(groupstate *gstate); + +/* Set *len_out to the multiplier length for group. */ +krb5_error_code group_mult_len(int32_t group, size_t *len_out); + +/* + * Generate a SPAKE private scalar (x or y) and public element (T or S), given + * an input multiplier wbytes. Use constant M if gstate is a KDC groupstate + * object, N if it is a client object. Allocate storage and place the results + * in *priv_out and *pub_out. + */ +krb5_error_code group_keygen(krb5_context context, groupstate *gstate, + int32_t group, const krb5_data *wbytes, + krb5_data *priv_out, krb5_data *pub_out); + +/* + * Compute the SPAKE result K from our private scalar (x or y) and their public + * key (S or T), deriving the input scalar w from ikey. Use the other party's + * constant, N if gstate is a KDC groupstate object or M if it is a client + * object. Allocate storage and place the result in *spakeresult_out. + */ +krb5_error_code group_result(krb5_context context, groupstate *gstate, + int32_t group, const krb5_data *wbytes, + const krb5_data *ourpriv, + const krb5_data *theirpub, + krb5_data *spakeresult_out); + +/* Set *result_out to the hash output length for group. */ +krb5_error_code group_hash_len(int32_t group, size_t *result_out); + +/* + * Compute the group's specified hash function over dlist (with ndata + * elements). result_out is caller-allocated with enough bytes for the hash + * output as given by group_hash_len(). + */ +krb5_error_code group_hash(krb5_context context, groupstate *gstate, + int32_t group, const krb5_data *dlist, size_t ndata, + uint8_t *result_out); + +#endif /* GROUPS_H */ diff --git a/src/plugins/preauth/spake/iana.c b/src/plugins/preauth/spake/iana.c new file mode 100644 index 000000000..e7901dedf --- /dev/null +++ b/src/plugins/preauth/spake/iana.c @@ -0,0 +1,108 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/iana.c - SPAKE IANA registry contents */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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 "iana.h" + +static uint8_t edwards25519_M[] = { + 0xD0, 0x48, 0x03, 0x2C, 0x6E, 0xA0, 0xB6, 0xD6, 0x97, 0xDD, 0xC2, 0xE8, + 0x6B, 0xDA, 0x85, 0xA3, 0x3A, 0xDA, 0xC9, 0x20, 0xF1, 0xBF, 0x18, 0xE1, + 0xB0, 0xC6, 0xD1, 0x66, 0xA5, 0xCE, 0xCD, 0xAF +}; + +static uint8_t edwards25519_N[] = { + 0xD3, 0xBF, 0xB5, 0x18, 0xF4, 0x4F, 0x34, 0x30, 0xF2, 0x9D, 0x0C, 0x92, + 0xAF, 0x50, 0x38, 0x65, 0xA1, 0xED, 0x32, 0x81, 0xDC, 0x69, 0xB3, 0x5D, + 0xD8, 0x68, 0xBA, 0x85, 0xF8, 0x86, 0xC4, 0xAB +}; + +static uint8_t P256_M[] = { + 0x02, 0x88, 0x6E, 0x2F, 0x97, 0xAC, 0xE4, 0x6E, 0x55, 0xBA, 0x9D, 0xD7, + 0x24, 0x25, 0x79, 0xF2, 0x99, 0x3B, 0x64, 0xE1, 0x6E, 0xF3, 0xDC, 0xAB, + 0x95, 0xAF, 0xD4, 0x97, 0x33, 0x3D, 0x8F, 0xA1, 0x2F +}; + +static uint8_t P256_N[] = { + 0x03, 0xD8, 0xBB, 0xD6, 0xC6, 0x39, 0xC6, 0x29, 0x37, 0xB0, 0x4D, 0x99, + 0x7F, 0x38, 0xC3, 0x77, 0x07, 0x19, 0xC6, 0x29, 0xD7, 0x01, 0x4D, 0x49, + 0xA2, 0x4B, 0x4F, 0x98, 0xBA, 0xA1, 0x29, 0x2B, 0x49 +}; + +static uint8_t P384_M[] = { + 0x03, 0x0F, 0xF0, 0x89, 0x5A, 0xE5, 0xEB, 0xF6, 0x18, 0x70, 0x80, 0xA8, + 0x2D, 0x82, 0xB4, 0x2E, 0x27, 0x65, 0xE3, 0xB2, 0xF8, 0x74, 0x9C, 0x7E, + 0x05, 0xEB, 0xA3, 0x66, 0x43, 0x4B, 0x36, 0x3D, 0x3D, 0xC3, 0x6F, 0x15, + 0x31, 0x47, 0x39, 0x07, 0x4D, 0x2E, 0xB8, 0x61, 0x3F, 0xCE, 0xEC, 0x28, + 0x53 +}; + +static uint8_t P384_N[] = { + 0x02, 0xC7, 0x2C, 0xF2, 0xE3, 0x90, 0x85, 0x3A, 0x1C, 0x1C, 0x4A, 0xD8, + 0x16, 0xA6, 0x2F, 0xD1, 0x58, 0x24, 0xF5, 0x60, 0x78, 0x91, 0x8F, 0x43, + 0xF9, 0x22, 0xCA, 0x21, 0x51, 0x8F, 0x9C, 0x54, 0x3B, 0xB2, 0x52, 0xC5, + 0x49, 0x02, 0x14, 0xCF, 0x9A, 0xA3, 0xF0, 0xBA, 0xAB, 0x4B, 0x66, 0x5C, + 0x10 +}; + +static uint8_t P521_M[] = { + 0x02, 0x00, 0x3F, 0x06, 0xF3, 0x81, 0x31, 0xB2, 0xBA, 0x26, 0x00, 0x79, + 0x1E, 0x82, 0x48, 0x8E, 0x8D, 0x20, 0xAB, 0x88, 0x9A, 0xF7, 0x53, 0xA4, + 0x18, 0x06, 0xC5, 0xDB, 0x18, 0xD3, 0x7D, 0x85, 0x60, 0x8C, 0xFA, 0xE0, + 0x6B, 0x82, 0xE4, 0xA7, 0x2C, 0xD7, 0x44, 0xC7, 0x19, 0x19, 0x35, 0x62, + 0xA6, 0x53, 0xEA, 0x1F, 0x11, 0x9E, 0xEF, 0x93, 0x56, 0x90, 0x7E, 0xDC, + 0x9B, 0x56, 0x97, 0x99, 0x62, 0xD7, 0xAA +}; + +static uint8_t P521_N[] = { + 0x02, 0x00, 0xC7, 0x92, 0x4B, 0x9E, 0xC0, 0x17, 0xF3, 0x09, 0x45, 0x62, + 0x89, 0x43, 0x36, 0xA5, 0x3C, 0x50, 0x16, 0x7B, 0xA8, 0xC5, 0x96, 0x38, + 0x76, 0x88, 0x05, 0x42, 0xBC, 0x66, 0x9E, 0x49, 0x4B, 0x25, 0x32, 0xD7, + 0x6C, 0x5B, 0x53, 0xDF, 0xB3, 0x49, 0xFD, 0xF6, 0x91, 0x54, 0xB9, 0xE0, + 0x04, 0x8C, 0x58, 0xA4, 0x2E, 0x8E, 0xD0, 0x4C, 0xEF, 0x05, 0x2A, 0x3B, + 0xC3, 0x49, 0xD9, 0x55, 0x75, 0xCD, 0x25 +}; + +const spake_iana spake_iana_edwards25519 = { + SPAKE_GROUP_EDWARDS25519, "edwards25519", 32, 32, + edwards25519_M, edwards25519_N, 32 +}; + +const spake_iana spake_iana_p256 = { + SPAKE_GROUP_P256, "P-256", 32, 33, P256_M, P256_N, 32 +}; + +const spake_iana spake_iana_p384 = { + SPAKE_GROUP_P384, "P-384", 48, 49, P384_M, P384_N, 48 +}; + +const spake_iana spake_iana_p521 = { + SPAKE_GROUP_P521, "P-521", 66, 67, P521_M, P521_N, 64 +}; diff --git a/src/plugins/preauth/spake/iana.h b/src/plugins/preauth/spake/iana.h new file mode 100644 index 000000000..1d99c4dd6 --- /dev/null +++ b/src/plugins/preauth/spake/iana.h @@ -0,0 +1,65 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/iana.h - SPAKE IANA registry contents */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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. + */ + +#ifndef IANA_H +#define IANA_H + +#include +#include + +typedef enum { + SPAKE_SF_NONE = 1, +} spake_sf_type; + +typedef enum { + SPAKE_GROUP_EDWARDS25519 = 1, + SPAKE_GROUP_P256 = 2, + SPAKE_GROUP_P384 = 3, + SPAKE_GROUP_P521 = 4, +} spake_group; + +typedef struct { + int32_t id; + const char *name; + size_t mult_len; + size_t elem_len; + const uint8_t *m; + const uint8_t *n; + size_t hash_len; +} spake_iana; + +extern const spake_iana spake_iana_edwards25519; +extern const spake_iana spake_iana_p256; +extern const spake_iana spake_iana_p384; +extern const spake_iana spake_iana_p521; + +#endif /* IANA_H */ diff --git a/src/plugins/preauth/spake/openssl.c b/src/plugins/preauth/spake/openssl.c new file mode 100644 index 000000000..b821a9158 --- /dev/null +++ b/src/plugins/preauth/spake/openssl.c @@ -0,0 +1,315 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/openssl.c - SPAKE implementations using OpenSSL */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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 "k5-int.h" + +#include "groups.h" +#include "iana.h" + +#ifdef SPAKE_OPENSSL +#include +#include +#include +#include + +/* OpenSSL 1.1 standardizes constructor and destructor names, renaming + * EVP_MD_CTX_create and EVP_MD_CTX_destroy. */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define EVP_MD_CTX_new EVP_MD_CTX_create +#define EVP_MD_CTX_free EVP_MD_CTX_destroy +#endif + +struct groupdata_st { + const groupdef *gdef; + EC_GROUP *group; + BIGNUM *order; + BN_CTX *ctx; + EC_POINT *M; + EC_POINT *N; + const EVP_MD *md; +}; + +static void +ossl_fini(groupdata *gd) +{ + if (gd == NULL) + return; + + EC_GROUP_free(gd->group); + EC_POINT_free(gd->M); + EC_POINT_free(gd->N); + BN_CTX_free(gd->ctx); + BN_free(gd->order); +} + +static krb5_error_code +ossl_init(krb5_context context, const groupdef *gdef, groupdata **gdata_out) +{ + const spake_iana *reg = gdef->reg; + const EVP_MD *md; + groupdata *gd; + int nid; + + switch (reg->id) { + case SPAKE_GROUP_P256: + nid = NID_X9_62_prime256v1; + md = EVP_sha256(); + break; + case SPAKE_GROUP_P384: + nid = NID_secp384r1; + md = EVP_sha384(); + break; + case SPAKE_GROUP_P521: + nid = NID_secp521r1; + md = EVP_sha512(); + break; + default: + return EINVAL; + }; + + gd = calloc(1, sizeof(*gd)); + if (gd == NULL) + return ENOMEM; + gd->gdef = gdef; + + gd->group = EC_GROUP_new_by_curve_name(nid); + if (gd->group == NULL) + goto error; + + gd->ctx = BN_CTX_new(); + if (gd->ctx == NULL) + goto error; + + gd->order = BN_new(); + if (gd->order == NULL) + goto error; + if (!EC_GROUP_get_order(gd->group, gd->order, gd->ctx)) + goto error; + + gd->M = EC_POINT_new(gd->group); + if (gd->M == NULL) + goto error; + if (!EC_POINT_oct2point(gd->group, gd->M, reg->m, reg->elem_len, gd->ctx)) + goto error; + + gd->N = EC_POINT_new(gd->group); + if (gd->N == NULL) + goto error; + if (!EC_POINT_oct2point(gd->group, gd->N, reg->n, reg->elem_len, gd->ctx)) + goto error; + + gd->md = md; + + *gdata_out = gd; + return 0; + +error: + ossl_fini(gd); + return ENOMEM; +} + +/* Convert pseudo-random bytes into a scalar value in constant time. + * Return NULL on failure. */ +static BIGNUM * +unmarshal_w(const groupdata *gdata, const uint8_t *wbytes) +{ + const spake_iana *reg = gdata->gdef->reg; + BIGNUM *w = NULL; + + w = BN_new(); + if (w == NULL) + return NULL; + + BN_set_flags(w, BN_FLG_CONSTTIME); + + if (BN_bin2bn(wbytes, reg->mult_len, w) && + BN_div(NULL, w, w, gdata->order, gdata->ctx)) + return w; + + BN_free(w); + return NULL; +} + +static krb5_error_code +ossl_keygen(krb5_context context, groupdata *gdata, const uint8_t *wbytes, + krb5_boolean use_m, uint8_t *priv_out, uint8_t *pub_out) +{ + const spake_iana *reg = gdata->gdef->reg; + const EC_POINT *constant = use_m ? gdata->M : gdata->N; + krb5_boolean success = FALSE; + EC_POINT *pub = NULL; + BIGNUM *priv = NULL, *w = NULL; + size_t len; + + w = unmarshal_w(gdata, wbytes); + if (w == NULL) + goto cleanup; + + pub = EC_POINT_new(gdata->group); + if (pub == NULL) + goto cleanup; + + priv = BN_new(); + if (priv == NULL) + goto cleanup; + + if (!BN_rand_range(priv, gdata->order)) + goto cleanup; + + /* Compute priv*G + w*constant; EC_POINT_mul() does this in one call. */ + if (!EC_POINT_mul(gdata->group, pub, priv, constant, w, gdata->ctx)) + goto cleanup; + + /* Marshal priv into priv_out. */ + memset(priv_out, 0, reg->mult_len); + BN_bn2bin(priv, &priv_out[reg->mult_len - BN_num_bytes(priv)]); + + /* Marshal pub into pub_out. */ + len = EC_POINT_point2oct(gdata->group, pub, POINT_CONVERSION_COMPRESSED, + pub_out, reg->elem_len, gdata->ctx); + if (len != reg->elem_len) + goto cleanup; + + success = TRUE; + +cleanup: + EC_POINT_free(pub); + BN_clear_free(priv); + BN_clear_free(w); + return success ? 0 : ENOMEM; +} + +static krb5_error_code +ossl_result(krb5_context context, groupdata *gdata, const uint8_t *wbytes, + const uint8_t *ourpriv, const uint8_t *theirpub, + krb5_boolean use_m, uint8_t *elem_out) +{ + const spake_iana *reg = gdata->gdef->reg; + const EC_POINT *constant = use_m ? gdata->M : gdata->N; + krb5_boolean success = FALSE, invalid = FALSE; + EC_POINT *result = NULL, *pub = NULL; + BIGNUM *priv = NULL, *w = NULL; + size_t len; + + w = unmarshal_w(gdata, wbytes); + if (w == NULL) + goto cleanup; + + priv = BN_bin2bn(ourpriv, reg->mult_len, NULL); + if (priv == NULL) + goto cleanup; + + pub = EC_POINT_new(gdata->group); + if (pub == NULL) + goto cleanup; + if (!EC_POINT_oct2point(gdata->group, pub, theirpub, reg->elem_len, + gdata->ctx)) { + invalid = TRUE; + goto cleanup; + } + + /* Compute result = priv*(pub - w*constant), using result to hold the + * intermediate steps. */ + result = EC_POINT_new(gdata->group); + if (result == NULL) + goto cleanup; + if (!EC_POINT_mul(gdata->group, result, NULL, constant, w, gdata->ctx)) + goto cleanup; + if (!EC_POINT_invert(gdata->group, result, gdata->ctx)) + goto cleanup; + if (!EC_POINT_add(gdata->group, result, pub, result, gdata->ctx)) + goto cleanup; + if (!EC_POINT_mul(gdata->group, result, NULL, result, priv, gdata->ctx)) + goto cleanup; + + /* Marshal result into elem_out. */ + len = EC_POINT_point2oct(gdata->group, result, POINT_CONVERSION_COMPRESSED, + elem_out, reg->elem_len, gdata->ctx); + if (len != reg->elem_len) + goto cleanup; + + success = TRUE; + +cleanup: + BN_clear_free(priv); + BN_clear_free(w); + EC_POINT_free(pub); + EC_POINT_clear_free(result); + return invalid ? EINVAL : (success ? 0 : ENOMEM); +} + +static krb5_error_code +ossl_hash(krb5_context context, groupdata *gdata, const krb5_data *dlist, + size_t ndata, uint8_t *result_out) +{ + EVP_MD_CTX *ctx; + size_t i; + int ok; + + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) + return ENOMEM; + ok = EVP_DigestInit_ex(ctx, gdata->md, NULL); + for (i = 0; i < ndata; i++) + ok = ok && EVP_DigestUpdate(ctx, dlist[i].data, dlist[i].length); + ok = ok && EVP_DigestFinal_ex(ctx, result_out, NULL); + EVP_MD_CTX_free(ctx); + return ok ? 0 : ENOMEM; +} + +groupdef ossl_P256 = { + .reg = &spake_iana_p256, + .init = ossl_init, + .fini = ossl_fini, + .keygen = ossl_keygen, + .result = ossl_result, + .hash = ossl_hash, +}; + +groupdef ossl_P384 = { + .reg = &spake_iana_p384, + .init = ossl_init, + .fini = ossl_fini, + .keygen = ossl_keygen, + .result = ossl_result, + .hash = ossl_hash, +}; + +groupdef ossl_P521 = { + .reg = &spake_iana_p521, + .init = ossl_init, + .fini = ossl_fini, + .keygen = ossl_keygen, + .result = ossl_result, + .hash = ossl_hash, +}; +#endif /* SPAKE_OPENSSL */ diff --git a/src/plugins/preauth/spake/spake.exports b/src/plugins/preauth/spake/spake.exports new file mode 100644 index 000000000..81d100228 --- /dev/null +++ b/src/plugins/preauth/spake/spake.exports @@ -0,0 +1,2 @@ +clpreauth_spake_initvt +kdcpreauth_spake_initvt diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c new file mode 100644 index 000000000..d72bd64aa --- /dev/null +++ b/src/plugins/preauth/spake/spake_client.c @@ -0,0 +1,363 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/spake_client.c - SPAKE clpreauth module */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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 "k5-int.h" +#include "k5-spake.h" +#include "trace.h" +#include "util.h" +#include "iana.h" +#include "groups.h" +#include + +typedef struct reqstate_st { + krb5_keyblock *initial_key; + krb5_data *support; + krb5_data thash; + krb5_data spakeresult; +} reqstate; + +static krb5_error_code +spake_init(krb5_context context, krb5_clpreauth_moddata *moddata_out) +{ + krb5_error_code ret; + groupstate *gstate; + + ret = group_init_state(context, FALSE, &gstate); + if (ret) + return ret; + *moddata_out = (krb5_clpreauth_moddata)gstate; + return 0; +} + +static void +spake_fini(krb5_context context, krb5_clpreauth_moddata moddata) +{ + group_free_state((groupstate *)moddata); +} + +static void +spake_request_init(krb5_context context, krb5_clpreauth_moddata moddata, + krb5_clpreauth_modreq *modreq_out) +{ + *modreq_out = calloc(1, sizeof(reqstate)); +} + +static void +spake_request_fini(krb5_context context, krb5_clpreauth_moddata moddata, + krb5_clpreauth_modreq modreq) +{ + reqstate *st = (reqstate *)modreq; + + krb5_free_keyblock(context, st->initial_key); + krb5_free_data(context, st->support); + krb5_free_data_contents(context, &st->thash); + zapfree(st->spakeresult.data, st->spakeresult.length); + free(st); +} + +static krb5_error_code +spake_prep_questions(krb5_context context, krb5_clpreauth_moddata moddata, + krb5_clpreauth_modreq modreq, + krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb, + krb5_clpreauth_rock rock, krb5_kdc_req *req, + krb5_data *enc_req, krb5_data *enc_prev_req, + krb5_pa_data *pa_data) +{ + reqstate *st = (reqstate *)modreq; + + if (st == NULL) + return ENOMEM; + if (st->initial_key == NULL && pa_data->length > 0) + cb->need_as_key(context, rock); + + /* When second-factor is implemented, we should ask questions based on the + * factors in the challenge. */ + + return 0; +} + +/* + * Output a PA-SPAKE support message indicating which groups we support. This + * may be done for optimistic preauth, in response to an empty message, or in + * response to a challenge using a group we do not support. Save the support + * message in st->support. + */ +static krb5_error_code +send_support(krb5_context context, groupstate *gstate, reqstate *st, + krb5_pa_data ***pa_out) +{ + krb5_error_code ret; + krb5_data *support; + krb5_pa_spake msg; + + msg.choice = SPAKE_MSGTYPE_SUPPORT; + group_get_permitted(gstate, &msg.u.support.groups, &msg.u.support.ngroups); + ret = encode_krb5_pa_spake(&msg, &support); + if (ret) + return ret; + + /* Save the support message for later use in the transcript hash. */ + ret = krb5_copy_data(context, support, &st->support); + if (ret) { + krb5_free_data(context, support); + return ret; + } + + TRACE_SPAKE_SEND_SUPPORT(context); + return convert_to_padata(support, pa_out); +} + +/* Return true if SF-NONE is present in factors. */ +static krb5_boolean +contains_sf_none(krb5_spake_factor **factors) +{ + int i; + + for (i = 0; factors != NULL && factors[i] != NULL; i++) { + if (factors[i]->type == SPAKE_SF_NONE) + return TRUE; + } + return FALSE; +} + +static krb5_error_code +process_challenge(krb5_context context, groupstate *gstate, reqstate *st, + krb5_spake_challenge *ch, const krb5_data *der_msg, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_prompter_fct prompter, void *prompter_data, + const krb5_data *der_req, krb5_pa_data ***pa_out) +{ + krb5_error_code ret; + krb5_keyblock *k0 = NULL, *k1 = NULL; + krb5_spake_factor factor; + krb5_pa_spake msg; + krb5_data *der_factor = NULL, *response; + krb5_data clpriv = empty_data(), clpub = empty_data(); + krb5_data wbytes = empty_data(); + krb5_enc_data enc_factor; + + enc_factor.ciphertext = empty_data(); + + /* Not expected if we already computed the SPAKE result. */ + if (st->spakeresult.length != 0) + return KRB5KDC_ERR_PREAUTH_FAILED; + + if (!group_is_permitted(gstate, ch->group)) { + TRACE_SPAKE_REJECT_CHALLENGE(context, ch->group); + /* No point in sending a second support message. */ + if (st->support != NULL) + return KRB5KDC_ERR_PREAUTH_FAILED; + return send_support(context, gstate, st, pa_out); + } + + /* Initialize and update the transcript with the concatenation of the + * support message (if we sent one) and the received challenge. */ + ret = update_thash(context, gstate, ch->group, &st->thash, st->support, + der_msg); + if (ret) + return ret; + + TRACE_SPAKE_RECEIVE_CHALLENGE(context, ch->group, &ch->pubkey); + + /* When second factor support is implemented, we should check for a + * supported factor type instead of just checking for SF-NONE. */ + if (!contains_sf_none(ch->factors)) + return KRB5KDC_ERR_PREAUTH_FAILED; + + ret = derive_wbytes(context, ch->group, st->initial_key, &wbytes); + if (ret) + goto cleanup; + ret = group_keygen(context, gstate, ch->group, &wbytes, &clpriv, &clpub); + if (ret) + goto cleanup; + ret = group_result(context, gstate, ch->group, &wbytes, &clpriv, + &ch->pubkey, &st->spakeresult); + if (ret) + goto cleanup; + + ret = update_thash(context, gstate, ch->group, &st->thash, &clpub, NULL); + if (ret) + goto cleanup; + TRACE_SPAKE_CLIENT_THASH(context, &st->thash); + + /* Replace the reply key with K'[0]. */ + ret = derive_key(context, gstate, ch->group, st->initial_key, &wbytes, + &st->spakeresult, &st->thash, der_req, 0, &k0); + if (ret) + goto cleanup; + ret = cb->set_as_key(context, rock, k0); + if (ret) + goto cleanup; + + /* Encrypt a SPAKESecondFactor message with K'[1]. */ + ret = derive_key(context, gstate, ch->group, st->initial_key, &wbytes, + &st->spakeresult, &st->thash, der_req, 1, &k1); + if (ret) + goto cleanup; + /* When second factor support is implemented, we should construct an + * appropriate factor here instead of hardcoding SF-NONE. */ + factor.type = SPAKE_SF_NONE; + factor.data = NULL; + ret = encode_krb5_spake_factor(&factor, &der_factor); + if (ret) + goto cleanup; + ret = krb5_encrypt_helper(context, k1, KRB5_KEYUSAGE_SPAKE, der_factor, + &enc_factor); + if (ret) + goto cleanup; + + /* Encode and output a response message. */ + msg.choice = SPAKE_MSGTYPE_RESPONSE; + msg.u.response.pubkey = clpub; + msg.u.response.factor = enc_factor; + ret = encode_krb5_pa_spake(&msg, &response); + if (ret) + goto cleanup; + TRACE_SPAKE_SEND_RESPONSE(context); + ret = convert_to_padata(response, pa_out); + +cleanup: + krb5_free_keyblock(context, k0); + krb5_free_keyblock(context, k1); + krb5_free_data_contents(context, &enc_factor.ciphertext); + krb5_free_data_contents(context, &clpub); + zapfree(clpriv.data, clpriv.length); + zapfree(wbytes.data, wbytes.length); + if (der_factor != NULL) { + zapfree(der_factor->data, der_factor->length); + free(der_factor); + } + return ret; +} + +static krb5_error_code +process_encdata(krb5_context context, reqstate *st, krb5_enc_data *enc, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_prompter_fct prompter, void *prompter_data, + const krb5_data *der_prev_req, const krb5_data *der_req, + krb5_pa_data ***pa_out) +{ + /* Not expected if we haven't sent a response yet. */ + if (st->spakeresult.length == 0) + return KRB5KDC_ERR_PREAUTH_FAILED; + + /* + * When second factor support is implemented, we should process encdata + * messages according to the factor type. We should make sure to re-derive + * K'[0] and replace the reply key again, in case the request has changed. + * We should use der_prev_req to derive K'[n] to decrypt factor from the + * KDC. We should use der_req to derive K'[n+1] for the next message to + * send to the KDC. + */ + return KRB5_PLUGIN_OP_NOTSUPP; +} + +static krb5_error_code +spake_process(krb5_context context, krb5_clpreauth_moddata moddata, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *req, krb5_data *der_req, krb5_data *der_prev_req, + krb5_pa_data *pa_in, krb5_prompter_fct prompter, + void *prompter_data, krb5_pa_data ***pa_out) +{ + krb5_error_code ret; + groupstate *gstate = (groupstate *)moddata; + reqstate *st = (reqstate *)modreq; + krb5_pa_spake *msg; + krb5_data in_data; + krb5_keyblock *as_key; + + if (st == NULL) + return ENOMEM; + + if (pa_in->length == 0) { + /* Not expected if we already sent a support message. */ + if (st->support != NULL) + return KRB5KDC_ERR_PREAUTH_FAILED; + return send_support(context, gstate, st, pa_out); + } + + /* We need the initial reply key to process any non-trivial message. */ + if (st->initial_key == NULL) { + ret = cb->get_as_key(context, rock, &as_key); + if (ret) + return ret; + ret = krb5_copy_keyblock(context, as_key, &st->initial_key); + if (ret) + return ret; + } + + in_data = make_data(pa_in->contents, pa_in->length); + ret = decode_krb5_pa_spake(&in_data, &msg); + if (ret) + return ret; + + if (msg->choice == SPAKE_MSGTYPE_CHALLENGE) { + ret = process_challenge(context, gstate, st, &msg->u.challenge, + &in_data, cb, rock, prompter, prompter_data, + der_req, pa_out); + } else if (msg->choice == SPAKE_MSGTYPE_ENCDATA) { + ret = process_encdata(context, st, &msg->u.encdata, cb, rock, prompter, + prompter_data, der_prev_req, der_req, pa_out); + } else { + /* Unexpected message type */ + ret = KRB5KDC_ERR_PREAUTH_FAILED; + } + + k5_free_pa_spake(context, msg); + return ret; +} + +krb5_error_code +clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +krb5_error_code +clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_clpreauth_vtable vt; + static krb5_preauthtype pa_types[] = { KRB5_PADATA_SPAKE, 0 }; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_clpreauth_vtable)vtable; + vt->name = "spake"; + vt->pa_type_list = pa_types; + vt->init = spake_init; + vt->fini = spake_fini; + vt->request_init = spake_request_init; + vt->request_fini = spake_request_fini; + vt->process = spake_process; + vt->prep_questions = spake_prep_questions; + return 0; +} diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c new file mode 100644 index 000000000..c1723ebaf --- /dev/null +++ b/src/plugins/preauth/spake/spake_kdc.c @@ -0,0 +1,590 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/spake_kdc.c - SPAKE kdcpreauth module */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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 "k5-int.h" +#include "k5-input.h" +#include "k5-spake.h" + +#include "groups.h" +#include "trace.h" +#include "iana.h" +#include "util.h" + +#include + +/* + * The SPAKE kdcpreauth module uses a secure cookie containing the following + * concatenated fields (all integer fields are big-endian): + * + * version (16-bit unsigned integer) + * stage (16-bit unsigned integer) + * group (32-bit signed integer) + * SPAKE value (32-bit unsigned length, followed by data) + * Transcript hash (32-bit unsigned length, followed by data) + * Zero or more instances of: + * second-factor number (32-bit signed integer) + * second-factor data (32-bit unsigned length, followed by data) + * + * The only currently supported version is 1. stage is 0 if the cookie was + * sent with a challenge message. stage is n>0 if the cookie was sent with an + * encdata message encrypted in K'[2n]. group indicates the group number used + * in the SPAKE challenge. The SPAKE value is the KDC private key for a + * stage-0 cookie, represented in the scalar marshalling form of the group; for + * other cookies, the SPAKE value is the SPAKE result K, represented in the + * group element marshalling form. The transcript hash is the intermediate + * hash after updating with the support and challenge messages for a stage-0 + * cookie, or the final hash for other cookies. For a stage 0 cookie, there + * may be any number of second-factor records, including none (no record is + * generated for SF-NONE); for other cookies, there must be exactly one + * second-factor record corresponding to the factor type chosen by the client. + */ + +/* From a k5input structure representing the remainder of a secure cookie + * plaintext, parse a four-byte length and data. */ +static void +parse_data(struct k5input *in, krb5_data *out) +{ + out->length = k5_input_get_uint32_be(in); + out->data = (char *)k5_input_get_bytes(in, out->length); +} + +/* Parse a received cookie into its components. The pointers stored in the + * krb5_data outputs are aliases into cookie and should not be freed. */ +static krb5_error_code +parse_cookie(const krb5_data *cookie, int *stage_out, int32_t *group_out, + krb5_data *spake_out, krb5_data *thash_out, + krb5_data *factors_out) +{ + struct k5input in; + int version, stage; + int32_t group; + krb5_data thash, spake, factors; + + *spake_out = *thash_out = *factors_out = empty_data(); + k5_input_init(&in, cookie->data, cookie->length); + + /* Parse and check the version, and read the other integer fields. */ + version = k5_input_get_uint16_be(&in); + if (version != 1) + return KRB5KDC_ERR_PREAUTH_FAILED; + stage = k5_input_get_uint16_be(&in); + group = k5_input_get_uint32_be(&in); + + /* Parse the data fields. The factor data is anything remaining after the + * transcript hash. */ + parse_data(&in, &spake); + parse_data(&in, &thash); + if (in.status) + return in.status; + factors = make_data((char *)in.ptr, in.len); + + *stage_out = stage; + *group_out = group; + *spake_out = spake; + *thash_out = thash; + *factors_out = factors; + return 0; +} + +/* Marshal data into buf as a four-byte length followed by the contents. */ +static void +marshal_data(struct k5buf *buf, const krb5_data *data) +{ + uint8_t lenbuf[4]; + + store_32_be(data->length, lenbuf); + k5_buf_add_len(buf, lenbuf, 4); + k5_buf_add_len(buf, data->data, data->length); +} + +/* Marshal components into a cookie. */ +static krb5_error_code +make_cookie(int stage, int32_t group, const krb5_data *spake, + const krb5_data *thash, krb5_data *cookie_out) +{ + struct k5buf buf; + uint8_t intbuf[4]; + + *cookie_out = empty_data(); + k5_buf_init_dynamic_zap(&buf); + + /* Marshal the version, stage, and group. */ + store_16_be(1, intbuf); + k5_buf_add_len(&buf, intbuf, 2); + store_16_be(stage, intbuf); + k5_buf_add_len(&buf, intbuf, 2); + store_32_be(group, intbuf); + k5_buf_add_len(&buf, intbuf, 4); + + /* Marshal the data fields. */ + marshal_data(&buf, spake); + marshal_data(&buf, thash); + + /* When second factor support is implemented, we should add factor data + * here. */ + + if (buf.data == NULL) + return ENOMEM; + *cookie_out = make_data(buf.data, buf.len); + return 0; +} + +/* Add authentication indicators if any are configured for SPAKE. */ +static krb5_error_code +add_indicators(krb5_context context, const krb5_data *realm, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock) +{ + krb5_error_code ret; + const char *keys[4]; + char *realmstr, **indicators, **ind; + + realmstr = k5memdup0(realm->data, realm->length, &ret); + if (realmstr == NULL) + return ret; + keys[0] = KRB5_CONF_REALMS; + keys[1] = realmstr; + keys[2] = KRB5_CONF_SPAKE_PREAUTH_INDICATOR; + keys[3] = NULL; + ret = profile_get_values(context->profile, keys, &indicators); + free(realmstr); + if (ret == PROF_NO_RELATION) + return 0; + if (ret) + return ret; + + for (ind = indicators; *ind != NULL && !ret; ind++) + ret = cb->add_auth_indicator(context, rock, *ind); + + profile_free_list(indicators); + return ret; +} + +/* Initialize a SPAKE module data object. */ +static krb5_error_code +spake_init(krb5_context context, krb5_kdcpreauth_moddata *moddata_out, + const char **realmnames) +{ + krb5_error_code ret; + groupstate *gstate; + + ret = group_init_state(context, TRUE, &gstate); + if (ret) + return ret; + *moddata_out = (krb5_kdcpreauth_moddata)gstate; + return 0; +} + +/* Release a SPAKE module data object. */ +static void +spake_fini(krb5_context context, krb5_kdcpreauth_moddata moddata) +{ + group_free_state((groupstate *)moddata); +} + +/* + * Generate a SPAKE challenge message for the specified group. Use cb and rock + * to retrieve the initial reply key and to set a stage-0 cookie. Invoke + * either erespond or vrespond with the result. + */ +static void +send_challenge(krb5_context context, groupstate *gstate, int32_t group, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + const krb5_data *support, + krb5_kdcpreauth_edata_respond_fn erespond, + krb5_kdcpreauth_verify_respond_fn vrespond, void *arg) +{ + krb5_error_code ret; + const krb5_keyblock *ikey; + krb5_pa_data **padata = NULL, *pa; + krb5_data kdcpriv = empty_data(), kdcpub = empty_data(), *der_msg = NULL; + krb5_data thash = empty_data(), cookie = empty_data(); + krb5_data wbytes = empty_data(); + krb5_spake_factor f, *flist[2]; + krb5_pa_spake msg; + + ikey = cb->client_keyblock(context, rock); + if (ikey == NULL) { + ret = KRB5KDC_ERR_ETYPE_NOSUPP; + goto cleanup; + } + + ret = derive_wbytes(context, group, ikey, &wbytes); + if (ret) + goto cleanup; + ret = group_keygen(context, gstate, group, &wbytes, &kdcpriv, &kdcpub); + if (ret) + goto cleanup; + + /* Encode the challenge. When second factor support is implemented, we + * should construct a factor list instead of hardcoding SF-NONE. */ + f.type = SPAKE_SF_NONE; + f.data = NULL; + flist[0] = &f; + flist[1] = NULL; + msg.choice = SPAKE_MSGTYPE_CHALLENGE; + msg.u.challenge.group = group; + msg.u.challenge.pubkey = kdcpub; + msg.u.challenge.factors = flist; + ret = encode_krb5_pa_spake(&msg, &der_msg); + if (ret) + goto cleanup; + + /* Initialize and update the transcript hash with the support message (if + * we received one) and challenge message. */ + ret = update_thash(context, gstate, group, &thash, support, der_msg); + if (ret) + goto cleanup; + + /* Save the group, transcript hash, and private key in a stage-0 cookie. + * When second factor support is implemented, also save factor state. */ + ret = make_cookie(0, group, &kdcpriv, &thash, &cookie); + if (ret) + goto cleanup; + ret = cb->set_cookie(context, rock, KRB5_PADATA_SPAKE, &cookie); + if (ret) + goto cleanup; + + ret = convert_to_padata(der_msg, &padata); + der_msg = NULL; + TRACE_SPAKE_SEND_CHALLENGE(context, group); + +cleanup: + zapfree(wbytes.data, wbytes.length); + zapfree(kdcpriv.data, kdcpriv.length); + zapfree(cookie.data, cookie.length); + krb5_free_data_contents(context, &kdcpub); + krb5_free_data_contents(context, &thash); + krb5_free_data(context, der_msg); + + if (erespond != NULL) { + assert(vrespond == NULL); + /* Grab the first pa-data element from the list, if we made one. */ + pa = (padata == NULL) ? NULL : padata[0]; + free(padata); + (*erespond)(arg, ret, pa); + } else { + assert(vrespond != NULL); + if (!ret) + ret = KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED; + (*vrespond)(arg, ret, NULL, padata, NULL); + } +} + +/* Generate the METHOD-DATA entry indicating support for SPAKE. Include an + * optimistic challenge if configured to do so. */ +static void +spake_edata(krb5_context context, krb5_kdc_req *req, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type, + krb5_kdcpreauth_edata_respond_fn respond, void *arg) +{ + const krb5_keyblock *ikey; + groupstate *gstate = (groupstate *)moddata; + krb5_data empty = empty_data(); + int32_t group; + + /* SPAKE requires a client key, which cannot be a single-DES key. */ + ikey = cb->client_keyblock(context, rock); + if (ikey == NULL) { + (*respond)(arg, KRB5KDC_ERR_ETYPE_NOSUPP, NULL); + return; + } + + group = group_optimistic_challenge(gstate); + if (group) { + send_challenge(context, gstate, group, cb, rock, &empty, respond, NULL, + arg); + } else { + /* No optimistic challenge configured; send an empty pa-data value. */ + (*respond)(arg, 0, NULL); + } +} + +/* Choose a group from the client's support message and generate a + * challenge. */ +static void +verify_support(krb5_context context, groupstate *gstate, + krb5_spake_support *support, const krb5_data *der_msg, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_verify_respond_fn respond, void *arg) +{ + krb5_error_code ret; + int32_t i, group; + + for (i = 0; i < support->ngroups; i++) { + if (group_is_permitted(gstate, support->groups[i])) + break; + } + if (i == support->ngroups) { + TRACE_SPAKE_REJECT_SUPPORT(context); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto error; + } + group = support->groups[i]; + TRACE_SPAKE_RECEIVE_SUPPORT(context, group); + + send_challenge(context, gstate, group, cb, rock, der_msg, NULL, respond, + arg); + return; + +error: + (*respond)(arg, ret, NULL, NULL, NULL); +} + +/* + * From the client's response message, compute the SPAKE result and decrypt the + * factor reply. On success, either mark the reply as pre-authenticated and + * set a reply key in the pre-request module data, or generate an additional + * factor challenge and ask for another round of pre-authentication. + */ +static void +verify_response(krb5_context context, groupstate *gstate, + krb5_spake_response *resp, const krb5_data *realm, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_enc_tkt_part *enc_tkt_reply, + krb5_kdcpreauth_verify_respond_fn respond, void *arg) +{ + krb5_error_code ret; + const krb5_keyblock *ikey; + krb5_keyblock *k1 = NULL, *reply_key = NULL; + krb5_data cookie, thash_in, kdcpriv, factors, *der_req; + krb5_data thash = empty_data(), der_factor = empty_data(); + krb5_data wbytes = empty_data(), spakeresult = empty_data(); + krb5_spake_factor *factor = NULL; + int stage; + int32_t group; + + ikey = cb->client_keyblock(context, rock); + if (ikey == NULL) { + ret = KRB5KDC_ERR_ETYPE_NOSUPP; + goto cleanup; + } + + /* Fetch the stage-0 cookie and parse it. (All of the krb5_data results + * are aliases into memory owned by rock). */ + if (!cb->get_cookie(context, rock, KRB5_PADATA_SPAKE, &cookie)) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto cleanup; + } + ret = parse_cookie(&cookie, &stage, &group, &kdcpriv, &thash_in, &factors); + if (ret) + goto cleanup; + if (stage != 0) { + /* The received cookie wasn't sent with a challenge. */ + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto cleanup; + } + TRACE_SPAKE_RECEIVE_RESPONSE(context, &resp->pubkey); + + /* Update the transcript hash with the client public key. */ + ret = krb5int_copy_data_contents(context, &thash_in, &thash); + if (ret) + goto cleanup; + ret = update_thash(context, gstate, group, &thash, &resp->pubkey, NULL); + if (ret) + goto cleanup; + TRACE_SPAKE_KDC_THASH(context, &thash); + + ret = derive_wbytes(context, group, ikey, &wbytes); + if (ret) + goto cleanup; + ret = group_result(context, gstate, group, &wbytes, &kdcpriv, + &resp->pubkey, &spakeresult); + if (ret) + goto cleanup; + + /* Decrypt the response factor field using K'[1]. If the decryption + * integrity check fails, the client probably used the wrong password. */ + der_req = cb->request_body(context, rock); + ret = derive_key(context, gstate, group, ikey, &wbytes, &spakeresult, + &thash, der_req, 1, &k1); + if (ret) + goto cleanup; + ret = alloc_data(&der_factor, resp->factor.ciphertext.length); + if (ret) + goto cleanup; + ret = krb5_c_decrypt(context, k1, KRB5_KEYUSAGE_SPAKE, NULL, &resp->factor, + &der_factor); + if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) + ret = KRB5KDC_ERR_PREAUTH_FAILED; + if (ret) + goto cleanup; + ret = decode_krb5_spake_factor(&der_factor, &factor); + if (ret) + goto cleanup; + + /* + * When second factor support is implemented, we should verify the factor + * data here, and possibly generate an encdata message for another hop. + * This function may need to be split at this point to allow for + * asynchronous verification of the second-factor value. We might also + * need to collect authentication indicators from the second-factor module; + * alternatively the module could have access to cb and rock so that it can + * add indicators itself. + */ + if (factor->type != SPAKE_SF_NONE) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto cleanup; + } + + ret = add_indicators(context, realm, cb, rock); + if (ret) + goto cleanup; + + enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; + + ret = derive_key(context, gstate, group, ikey, &wbytes, &spakeresult, + &thash, der_req, 0, &reply_key); + +cleanup: + zapfree(wbytes.data, wbytes.length); + zapfree(der_factor.data, der_factor.length); + zapfree(spakeresult.data, spakeresult.length); + krb5_free_data_contents(context, &thash); + krb5_free_keyblock(context, k1); + k5_free_spake_factor(context, factor); + (*respond)(arg, ret, (krb5_kdcpreauth_modreq)reply_key, NULL, NULL); +} + +/* + * Decrypt and validate an additional second-factor reply. On success, either + * mark the reply as pre-authenticated and set a reply key in the pre-request + * module data, or generate an additional factor challenge and ask for another + * round of pre-authentication. + */ +static void +verify_encdata(krb5_context context, krb5_enc_data *enc, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_enc_tkt_part *enc_tkt_reply, + krb5_kdcpreauth_verify_respond_fn respond, void *arg) +{ + /* + * When second factor support is implemented, we should process encdata + * message according to the factor type recorded in the cookie. If the + * second factor exchange finishes successfully, we should set + * TKT_FLG_PRE_AUTH, set the reply key to K'[0], and add any auth + * indicators from configuration (with a call to add_indicators()) or the + * second factor module (unless the module has access to cb and rock and + * can add indicators itself). + */ + (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, NULL); +} + +/* + * Respond to a client padata message, either by generating a SPAKE challenge, + * generating an additional second-factor challenge, or marking the reply as + * pre-authenticated and setting an additional reply key in the pre-request + * module data. + */ +static void +spake_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request, + krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_moddata moddata, + krb5_kdcpreauth_verify_respond_fn respond, void *arg) +{ + krb5_error_code ret; + krb5_pa_spake *pa_spake = NULL; + krb5_data in_data = make_data(data->contents, data->length); + groupstate *gstate = (groupstate *)moddata; + + ret = decode_krb5_pa_spake(&in_data, &pa_spake); + if (ret) { + (*respond)(arg, ret, NULL, NULL, NULL); + } else if (pa_spake->choice == SPAKE_MSGTYPE_SUPPORT) { + verify_support(context, gstate, &pa_spake->u.support, &in_data, cb, + rock, respond, arg); + } else if (pa_spake->choice == SPAKE_MSGTYPE_RESPONSE) { + verify_response(context, gstate, &pa_spake->u.response, + &request->server->realm, cb, rock, enc_tkt_reply, + respond, arg); + } else if (pa_spake->choice == SPAKE_MSGTYPE_ENCDATA) { + verify_encdata(context, &pa_spake->u.encdata, cb, rock, enc_tkt_reply, + respond, arg); + } else { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + k5_setmsg(context, ret, _("Unknown SPAKE request type")); + (*respond)(arg, ret, NULL, NULL, NULL); + } + + k5_free_pa_spake(context, pa_spake); +} + +/* If a key was set in the per-request module data, replace the reply key. Do + * not generate any pa-data to include with the KDC reply. */ +static krb5_error_code +spake_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt, + krb5_kdc_req *request, krb5_kdc_rep *reply, + krb5_keyblock *encrypting_key, krb5_pa_data **send_pa_out, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq) +{ + krb5_keyblock *reply_key = (krb5_keyblock *)modreq; + + if (reply_key == NULL) + return 0; + krb5_free_keyblock_contents(context, encrypting_key); + return krb5_copy_keyblock_contents(context, reply_key, encrypting_key); +} + +/* Release a per-request module data object. */ +static void +spake_free_modreq(krb5_context context, krb5_kdcpreauth_moddata moddata, + krb5_kdcpreauth_modreq modreq) +{ + krb5_free_keyblock(context, (krb5_keyblock *)modreq); +} + +krb5_error_code +kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +krb5_error_code +kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_kdcpreauth_vtable vt; + static krb5_preauthtype pa_types[] = { KRB5_PADATA_SPAKE, 0 }; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_kdcpreauth_vtable)vtable; + vt->name = "spake"; + vt->pa_type_list = pa_types; + vt->init = spake_init; + vt->fini = spake_fini; + vt->edata = spake_edata; + vt->verify = spake_verify; + vt->return_padata = spake_return; + vt->free_modreq = spake_free_modreq; + return 0; +} diff --git a/src/plugins/preauth/spake/t_krb5.conf b/src/plugins/preauth/spake/t_krb5.conf new file mode 100644 index 000000000..65fdaec63 --- /dev/null +++ b/src/plugins/preauth/spake/t_krb5.conf @@ -0,0 +1,2 @@ +[libdefaults] + spake_preauth_groups = edwards25519 diff --git a/src/plugins/preauth/spake/t_vectors.c b/src/plugins/preauth/spake/t_vectors.c new file mode 100644 index 000000000..2279202d3 --- /dev/null +++ b/src/plugins/preauth/spake/t_vectors.c @@ -0,0 +1,476 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/t_vectors.c - SPAKE test vector verification */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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 "k5-int.h" +#include "k5-hex.h" +#include "groups.h" +#include "iana.h" +#include "util.h" +#include + +struct test { + krb5_enctype enctype; + int32_t group; + const char *ikey; + const char *w; + const char *x; + const char *y; + const char *T; + const char *S; + const char *K; + const char *support; + const char *challenge; + const char *thash; + const char *body; + const char *K0; + const char *K1; + const char *K2; + const char *K3; +} tests[] = { + { ENCTYPE_DES3_CBC_SHA1, SPAKE_GROUP_EDWARDS25519, + /* initial key, w, x, y, T, S, K */ + "850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E", + "686D84730CB8679AE95416C6567C6A63F2C9CEF124F7A3371AE81E11CAD42A37", + "201012D07BFD48DDFA33C4AAC4FB1E229FB0D043CFE65EBFB14399091C71A723", + "500B294797B8B042ACA1BEDC0F5931A4F52C537B3608B2D05CC8A2372F439F25", + "18F511E750C97B592ACD30DB7D9E5FCA660389102E6BF610C1BFBED4616C8362", + "5D10705E0D1E43D5DBF30240CCFBDE4A0230C70D4C79147AB0B317EDAD2F8AE7", + "25BDE0D875F0FEB5755F45BA5E857889D916ECF7476F116AA31DC3E037EC4292", + /* support, challenge, thash, body */ + "A0093007A0053003020101", + "A1363034A003020101A122042018F511E750C97B592ACD30DB7D9E5FCA660389" + "102E6BF610C1BFBED4616C8362A20930073005A003020101", + "EAAA08807D0616026FF51C849EFBF35BA0CE3C5300E7D486DA46351B13D4605B", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020110", + /* K'[0], K'[1], K'[2], K'[3] */ + "BAF12FAE7CD958CBF1A29BFBC71F89CE49E03E295D89DAFD", + "64F73DD9C41908206BCEC1F719026B574F9D13463D7A2520", + "0454520B086B152C455829E6BAEFF78A61DFE9E3D04A895D", + "4A92260B25E3EF94C125D5C24C3E5BCED5B37976E67F25C4", + }, + + { ENCTYPE_ARCFOUR_HMAC, SPAKE_GROUP_EDWARDS25519, + /* initial key, w, x, y, T, S, K */ + "8846F7EAEE8FB117AD06BDD830B7586C", + "7C86659D29CF2B2EA93BFE79C3CEFB8850E82215B3EA6FCD896561D48048F49C", + "C8A62E7B626F44CAD807B2D695450697E020D230A738C5CD5691CC781DCE8754", + "18FE7C1512708C7FD06DB270361F04593775BC634CEAF45347E5C11C38AAE017", + "7DB465F1C08C64983A19F560BCE966FE5306C4B447F70A5BCA14612A92DA1D63", + "38F8D4568090148EBC9FD17C241B4CC2769505A7CA6F3F7104417B72B5B5CF54", + "03E75EDD2CD7E7677642DD68736E91700953AC55DC650E3C2A1B3B4ACDB800F8", + /* support, challenge, thash, body */ + "A0093007A0053003020101", + "A1363034A003020101A12204207DB465F1C08C64983A19F560BCE966FE5306C4" + "B447F70A5BCA14612A92DA1D63A20930073005A003020101", + "F4B208458017DE6EF7F6A307D47D87DB6C2AF1D291B726860F68BC08BFEF440A", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020117", + /* K'[0], K'[1], K'[2], K'[3] */ + "770B720C82384CBB693E85411EEDECBA", + "621DEEC88E2865837C4D3462BB50A1D5", + "1CC8F6333B9FA3B42662FD9914FBD5BB", + "EDB4032B7FC3806D5211A534DCBC390C", + }, + + { ENCTYPE_AES128_CTS_HMAC_SHA1_96, SPAKE_GROUP_EDWARDS25519, + /* initial key, w, x, y, T, S, K */ + "FCA822951813FB252154C883F5EE1CF4", + "0D591B197B667E083C2F5F98AC891D3C9F99E710E464E62F1FB7C9B67936F3EB", + "50BE049A5A570FA1459FB9F666E6FD80602E4E87790A0E567F12438A2C96C138", + "B877AFE8612B406D96BE85BD9F19D423E95BE96C0E1E0B5824127195C3ED5917", + "9E9311D985C1355E022D7C3C694AD8D6F7AD6D647B68A90B0FE46992818002DA", + "FBE08F7F96CD5D4139E7C9ECCB95E79B8ACE41E270A60198C007DF18525B628E", + "C2F7F99997C585E6B686CEB62DB42F17CC70932DEF3BB4CF009E36F22EA5473D", + /* support, challenge, thash, body */ + "A0093007A0053003020101", + "A1363034A003020101A12204209E9311D985C1355E022D7C3C694AD8D6F7AD6D" + "647B68A90B0FE46992818002DAA20930073005A003020101", + "951285F107C87F0169B9C918A1F51F60CB1A75B9F8BB799A99F53D03ADD94B5F", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020111", + /* K'[0], K'[1], K'[2], K'[3] */ + "548022D58A7C47EAE8C49DCCF6BAA407", + "B2C9BA0E13FC8AB3A9D96B51B601CF4A", + "69F0EE5FDB6C237E7FCD38D9F87DF1BD", + "78F91E2240B5EE528A5CC8D7CBEBFBA5", + }, + { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_EDWARDS25519, + /* initial key, w, x, y, T, S, K */ + "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1", + "E902341590A1B4BB4D606A1C643CCCB3F2108F1B6AA97B381012B9400C9E3F4E", + "88C6C0A4F0241EF217C9788F02C32D00B72E4310748CD8FB5F94717607E6417D", + "88B859DF58EF5C69BACDFE681C582754EAAB09A74DC29CFF50B328613C232F55", + "6F301AACAE1220E91BE42868C163C5009AEEA1E9D9E28AFCFC339CDA5E7105B5", + "9E2CC32908FC46273279EC75354B4AEAFA70C3D99A4D507175ED70D80B255DDA", + "CF57F58F6E60169D2ECC8F20BB923A8E4C16E5BC95B9E64B5DC870DA7026321B", + /* support, challenge, thash, body */ + "A0093007A0053003020101", + "A1363034A003020101A12204206F301AACAE1220E91BE42868C163C5009AEEA1" + "E9D9E28AFCFC339CDA5E7105B5A20930073005A003020101", + "1C605649D4658B58CBE79A5FAF227ACC16C355C58B7DADE022F90C158FE5ED8E", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020112", + /* K'[0], K'[1], K'[2], K'[3] */ + "A9BFA71C95C575756F922871524B65288B3F695573CCC0633E87449568210C23", + "1865A9EE1EF0640EC28AC007391CAC624C42639C714767A974E99AA10003015F", + "E57781513FEFDB978E374E156B0DA0C1A08148F5EB26B8E157AC3C077E28BF49", + "008E6487293C3CC9FABBBCDD8B392D6DCB88222317FD7FE52D12FBC44FA047F1", + }, + +#ifdef SPAKE_OPENSSL + { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_P256, + /* initial key, w, x, y, T, S, K */ + "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1", + "EB2984AF18703F94DD5288B8596CD36988D0D4E83BFB2B44DE14D0E95E2090BD", + "935DDD725129FB7C6288E1A5CC45782198A6416D1775336D71EACD0549A3E80E", + "E07405EB215663ABC1F254B8ADC0DA7A16FEBAA011AF923D79FDEF7C42930B33", + "024F62078CEB53840D02612195494D0D0D88DE21FEEB81187C71CBF3D01E71788D", + "021D07DC31266FC7CFD904CE2632111A169B7EC730E5F74A7E79700F86638E13C8", + "0268489D7A9983F2FDE69C6E6A1307E9D252259264F5F2DFC32F58CCA19671E79B", + /* support, challenge, thash, body */ + "A0093007A0053003020102", + "A1373035A003020102A1230421024F62078CEB53840D02612195494D0D0D88DE" + "21FEEB81187C71CBF3D01E71788DA20930073005A003020101", + "20AD3C1A9A90FC037D1963A1C4BFB15AB4484D7B6CF07B12D24984F14652DE60", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020112", + /* K'[0], K'[1], K'[2], K'[3] */ + "7D3B906F7BE49932DB22CD3463F032D06C9C078BE4B1D076D201FC6E61EF531E", + "17D74E36F8993841FBB7FEB12FA4F011243D3AE4D2ACE55B39379294BBC4DB2C", + "D192C9044081A2AA6A97A6C69E2724E8E5671C2C9CE073DD439CDBAF96D7DAB0", + "41E5BAD6B67F12C53CE0E2720DD6A9887F877BF9463C2D5209C74C36F8D776B7", + }, + + { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_P384, + /* initial key, w, x, y, T, S, K */ + "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1", + "0304CFC55151C6BBE889653DB96DBFE0BA4ACAFC024C1E8840CB3A486F6D80C1" + "6E1B8974016AA4B7FA43042A9B3825B1", + "F323CA74D344749096FD35D0ADF20806E521460637176E84D977E9933C49D76F" + "CFC6E62585940927468FF53D864A7A50", + "5B7C709ACB175A5AFB82860DEABCA8D0B341FACDFF0AC0F1A425799AA905D750" + "7E1EA9C573581A81467437419466E472", + "02A1524603EF14F184696F854229D3397507A66C63F841BA748451056BE07879" + "AC298912387B1C5CDFF6381C264701BE57", + "020D5ADFDB92BC377041CF5837412574C5D13E0F4739208A4F0C859A0A302BC6" + "A533440A245B9D97A0D34AF5016A20053D", + "0264AA8C61DA9600DFB0BEB5E46550D63740E4EF29E73F1A30D543EB43C25499" + "037AD16538586552761B093CF0E37C703A", + /* support, challenge, thash, body */ + "A0093007A0053003020103", + "A1473045A003020103A133043102A1524603EF14F184696F854229D3397507A6" + "6C63F841BA748451056BE07879AC298912387B1C5CDFF6381C264701BE57A209" + "30073005A003020101", + "5AC0D99EF9E5A73998797FE64F074673E3952DEC4C7D1AACCE8B75F64D2B0276" + "A901CB8539B4E8ED69E4DB0CE805B47B", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020112", + /* K'[0], K'[1], K'[2], K'[3] */ + "B917D37C16DD1D8567FBE379F64E1EE36CA3FD127AA4E60F97E4AFA3D9E56D91", + "93D40079DAB229B9C79366829F4E7E7282E6A4B943AC7BAC69922D516673F49A", + "BFC4F16F12F683E71589F9A888E232875EF293AC9793DB6C919567CD7B94BCD4", + "3630E2B5B99938E7506733141E8EC344166F6407E5FC2EF107C156E764D1BC20", + }, + + { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_P521, + /* initial key, w, x, y, T, S, K */ + "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1", + "DE3A095A2B2386EFF3EB15B735398DA1CAF95BC8425665D82370AFF58B0471F3" + "4A57BCCDDF1EBF0A2965B58A93EE5B45E85D1A5435D1C8C83662999722D54283" + "1F9A", + "017C38701A14B490B6081DFC83524562BE7FBB42E0B20426465E3E37952D30BC" + "AB0ED857010255D44936A1515607964A870C7C879B741D878F9F9CDF5A865306" + "F3F5", + "003E2E2950656FA231E959ACDD984D125E7FA59CEC98126CBC8F3888447911EB" + "CD49428A1C22D5FDB76A19FBEB1D9EDFA3DA6CF55B158B53031D05D51433ADE9" + "B2B4", + "02017D3DE19A3EC53D0174905665EF37947D142535102CD9809C0DFBD0DFE007" + "353D54CF406CE2A59950F2BB540DF6FBE75F8BBBEF811C9BA06CC275ADBD9675" + "6696EC", + "02004D142D87477841F6BA053C8F651F3395AD264B7405CA5911FB9A55ABD454" + "FEF658A5F9ED97D1EFAC68764E9092FA15B9E0050880D78E95FD03ABF5931791" + "6822B5", + "03007C303F62F09282CC849490805BD4457A6793A832CBEB55DF427DB6A31E99" + "B055D5DC99756D24D47B70AD8B6015B0FB8742A718462ED423B90FA3FE631AC1" + "3FA916", + /* support, challenge, thash, body */ + "A0093007A0053003020104", + "A1593057A003020104A145044302017D3DE19A3EC53D0174905665EF37947D14" + "2535102CD9809C0DFBD0DFE007353D54CF406CE2A59950F2BB540DF6FBE75F8B" + "BBEF811C9BA06CC275ADBD96756696ECA20930073005A003020101", + "8D6A89AE4D80CC4E47B6F4E48EA3E57919CC69598D0D3DC7C8BD49B6F1DB1409" + "CA0312944CD964E213ABA98537041102237CFF5B331E5347A0673869B412302E", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020112", + /* K'[0], K'[1], K'[2], K'[3] */ + "1EB3D10BEE8FAB483ADCD3EB38F3EBF1F4FEB8DB96ECC035F563CF2E1115D276", + "482B92781CE57F49176E4C94153CC622FE247A7DBE931D1478315F856F085890", + "A2C215126DD3DF280AAB5A27E1E0FB7E594192CBFF8D6D8E1B6F1818D9BB8FAC", + "CC06603DE984324013A01F888DE6D43B410A4DA2DEA53509F30E433C352FB668", + }, +#endif /* SPAKE_OPENSSL */ + + /* Successful optimistic challenge (no support message in transcript) */ + { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_EDWARDS25519, + /* initial key, w, x, y, T, S, K */ + "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1", + "E902341590A1B4BB4D606A1C643CCCB3F2108F1B6AA97B381012B9400C9E3F4E", + "70937207344CAFBC53C8A55070E399C584CBAFCE00B836980DD4E7E74FAD2A64", + "785D6801A2490DF028903AC6449B105F2FF0DB895B252953CDC2076649526103", + "83523B35F1565006CBFC4F159885467C2FB9BC6FE23D36CB1DA43D199F1A3118", + "2A8F70F46CEE9030700037B77F22CEC7970DCC238E3E066D9D726BAF183992C6", + "D3C5E4266AA6D1B2873A97CE8AF91C7E4D7A7AC456ACCED7908D34C561AD8FA6", + /* support, challenge, thash, body */ + NULL, + "A1363034A003020101A122042083523B35F1565006CBFC4F159885467C2FB9BC" + "6FE23D36CB1DA43D199F1A3118A20930073005A003020101", + "26F07F9F8965307434D11EA855461D41E0CBABCC0A1BAB48ECEE0C6C1A4292B7", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020112", + /* K'[0], K'[1], K'[2], K'[3] */ + "4569EC08B5DE5C3CC19D941725913ACE8D74524B521A341DC746ACD5C3784D92", + "0D96CE1A4AC0F2E280A0CFC31742B06461D83D04AE45433DB2D80478DD882A4C", + "58018C19315A1BA5D5BB9813B58029F0AEC18A6F9CA59E0847DE1C60BC25945C", + "ED7E9BFFD68C54D86FB19CD3C03F317F88A71AD9A5E94C28581D93FC4EC72B6A", + }, + +#ifdef SPAKE_OPENSSL + /* Rejected optimistic challenge (no support message in transcript), + * falling back from edwards25519 to P-521 */ + { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_P521, + /* initial key, w, x, y, T, S, K */ + "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1", + "DE3A095A2B2386EFF3EB15B735398DA1CAF95BC8425665D82370AFF58B0471F3" + "4A57BCCDDF1EBF0A2965B58A93EE5B45E85D1A5435D1C8C83662999722D54283" + "1F9A", + "01687B59051BF40048D7C31D5A973D792FA12284B7A447E7F5938B5885CA0BB2" + "C3F0BD30291A55FEA08E143E2E04BDD7D19B753C7C99032F06CAB0D9C2AA8F83" + "7EF7", + "01DED675EBF74FE30C9A53710F577E9CF84F09F6048FE245A4600004884CC167" + "733F9A9E43108FB83BABE8754CD37CBD7025E28BC9FF870F084C7244F536285E" + "25B4", + "02014CB2E5B592ECE5990F0EF30D308C061DE1598BC4272B4A6599BED466FD15" + "21693642ABCF4DBE36CE1A2D13967DE45F6C4F8D0FA8E14428BF03FB96EF5F1E" + "D3E645", + "02016C64995E804416F748FD5FA3AA678CBC7CBB596A4F523132DC8AF7CE84E5" + "41F484A2C74808C6B21DCF7775BAEFA6753398425BECC7B838B210AC5DAA0CB0" + "B710E2", + "0200997F4848AE2E7A98C23D14AC662030743AB37FCCC2A45F1C721114F40BCC" + "80FE6EC6ABA49868F8AEA1AA994D50E81B86D3E4D3C1130C8695B68907C673D9" + "E5886A", + /* support, challenge, thash, body */ + "A0093007A0053003020104", + "A1593057A003020104A145044302014CB2E5B592ECE5990F0EF30D308C061DE1" + "598BC4272B4A6599BED466FD1521693642ABCF4DBE36CE1A2D13967DE45F6C4F" + "8D0FA8E14428BF03FB96EF5F1ED3E645A20930073005A003020101", + "D0EFED5E3E2C39C26034756D92A66FEC3082AD793D0197F3F89AD36026F146A3" + "996E548AA3FC49E2E82F8CAC5D132C505AA475B39E7BE79CDED22C26C41AA777", + "3075A00703050000000000A1143012A003020101A10B30091B07726165627572" + "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018" + "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730" + "303130313030303030305AA703020100A8053003020112", + /* K'[0], K'[1], K'[2], K'[3] */ + "631FCC8596E7F40E59045950D72AA0B7BAC2810A07B767050E983841CF3A2D4C", + "881464920117074DBC67155A8F3341D1121EF65F78EA0380BFA81A134C1C47B1", + "377B72AC3AF2CAAD582D73AE4682FD56B531EE56706200DD6C38C42B8219837A", + "35AD8E4D580ED3F0D15AD928329773C081BD19F9A56363F3A5F77C7E66108C26", + }, +#endif /* SPAKE_OPENSSL */ +}; + +static krb5_context ctx; + +static void +check(krb5_error_code code) +{ + const char *errmsg; + + if (code) { + errmsg = krb5_get_error_message(ctx, code); + assert(errmsg != NULL); + abort(); + } +} + +static void +check_key_equal(const krb5_keyblock *kb1, const krb5_keyblock *kb2) +{ + assert(kb1->enctype == kb2->enctype); + assert(kb1->length == kb2->length); + assert(memcmp(kb1->contents, kb2->contents, kb1->length) == 0); +} + +static krb5_data * +decode_data(const char *s) +{ + uint8_t *bytes; + size_t len; + krb5_data *d; + + if (k5_hex_decode(s, &bytes, &len) != 0) + abort(); + d = malloc(sizeof(*d)); + assert(d != NULL); + *d = make_data(bytes, len); + return d; +} + +static krb5_keyblock * +decode_keyblock(krb5_enctype enctype, const char *s) +{ + uint8_t *bytes; + size_t len; + krb5_keyblock *kb; + + if (k5_hex_decode(s, &bytes, &len) != 0) + abort(); + kb = malloc(sizeof(*kb)); + kb->magic = KV5M_KEYBLOCK; + kb->enctype = enctype; + kb->length = len; + kb->contents = bytes; + return kb; +} + +static void +run_test(const struct test *t) +{ + groupstate *gstate; + krb5_keyblock *ikey, *K0, *K1, *K2, *K3, *kb; + krb5_data *w, *x, *y, *T, *S, *K, *support, *challenge, *thash; + krb5_data *body, wbytes, result, hash, empty = empty_data(); + + /* Decode hex strings into keyblocks and byte strings. */ + ikey = decode_keyblock(t->enctype, t->ikey); + w = decode_data(t->w); + x = decode_data(t->x); + y = decode_data(t->y); + T = decode_data(t->T); + S = decode_data(t->S); + K = decode_data(t->K); + support = (t->support != NULL) ? decode_data(t->support) : NULL; + challenge = decode_data(t->challenge); + thash = decode_data(t->thash); + body = decode_data(t->body); + K0 = decode_keyblock(t->enctype, t->K0); + K1 = decode_keyblock(t->enctype, t->K1); + K2 = decode_keyblock(t->enctype, t->K2); + K3 = decode_keyblock(t->enctype, t->K3); + + check(derive_wbytes(ctx, t->group, ikey, &wbytes)); + assert(data_eq(*w, wbytes)); + + /* Verify KDC-side result computation. */ + check(group_init_state(ctx, TRUE, &gstate)); + check(group_result(ctx, gstate, t->group, &wbytes, x, S, &result)); + assert(data_eq(*K, result)); + krb5_free_data_contents(ctx, &result); + group_free_state(gstate); + + /* Verify client-side result computation. */ + check(group_init_state(ctx, FALSE, &gstate)); + check(group_result(ctx, gstate, t->group, &wbytes, y, T, &result)); + assert(data_eq(*K, result)); + krb5_free_data_contents(ctx, &result); + + /* Verify transcript hash. */ + hash = empty_data(); + check(update_thash(ctx, gstate, t->group, &hash, support, challenge)); + check(update_thash(ctx, gstate, t->group, &hash, S, &empty)); + assert(data_eq(*thash, hash)); + krb5_free_data_contents(ctx, &hash); + + /* Verify derived keys. */ + check(derive_key(ctx, gstate, t->group, ikey, &wbytes, K, thash, body, 0, + &kb)); + check_key_equal(K0, kb); + krb5_free_keyblock(ctx, kb); + check(derive_key(ctx, gstate, t->group, ikey, &wbytes, K, thash, body, 1, + &kb)); + check_key_equal(K1, kb); + krb5_free_keyblock(ctx, kb); + check(derive_key(ctx, gstate, t->group, ikey, &wbytes, K, thash, body, 2, + &kb)); + check_key_equal(K2, kb); + krb5_free_keyblock(ctx, kb); + check(derive_key(ctx, gstate, t->group, ikey, &wbytes, K, thash, body, 3, + &kb)); + check_key_equal(K3, kb); + krb5_free_keyblock(ctx, kb); + + group_free_state(gstate); + krb5_free_data_contents(ctx, &wbytes); + krb5_free_keyblock(ctx, ikey); + krb5_free_data(ctx, w); + krb5_free_data(ctx, x); + krb5_free_data(ctx, y); + krb5_free_data(ctx, T); + krb5_free_data(ctx, S); + krb5_free_data(ctx, K); + krb5_free_data(ctx, support); + krb5_free_data(ctx, challenge); + krb5_free_data(ctx, thash); + krb5_free_data(ctx, body); + krb5_free_keyblock(ctx, K0); + krb5_free_keyblock(ctx, K1); + krb5_free_keyblock(ctx, K2); + krb5_free_keyblock(ctx, K3); +} + +int +main() +{ + size_t i; + + check(krb5_init_context(&ctx)); + for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) + run_test(&tests[i]); + krb5_free_context(ctx); + return 0; +} diff --git a/src/plugins/preauth/spake/trace.h b/src/plugins/preauth/spake/trace.h new file mode 100644 index 000000000..9dd964260 --- /dev/null +++ b/src/plugins/preauth/spake/trace.h @@ -0,0 +1,74 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/internal.h - SPAKE internal function declarations */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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. + */ + +#ifndef TRACE_H +#define TRACE_H + +#include "k5-int.h" + +/* + * Possible improvements at the cost of more code: + * - Groups could be displayed by name instead of number + * - We could display the group list when tracing support messages + */ + +#define TRACE_SPAKE_CLIENT_THASH(c, thash) \ + TRACE(c, "SPAKE final transcript hash: {hexdata}", thash) +#define TRACE_SPAKE_DERIVE_KEY(c, n, kb) \ + TRACE(c, "SPAKE derived K'[{int}] = {keyblock}", n, kb) +#define TRACE_SPAKE_KDC_THASH(c, thash) \ + TRACE(c, "SPAKE final transcript hash: {hexdata}", thash) +#define TRACE_SPAKE_KEYGEN(c, pubkey) \ + TRACE(c, "SPAKE key generated with pubkey {hexdata}", pubkey) +#define TRACE_SPAKE_RECEIVE_CHALLENGE(c, group, pubkey) \ + TRACE(c, "SPAKE challenge received with group {int}, pubkey {hexdata}", \ + group, pubkey) +#define TRACE_SPAKE_RECEIVE_RESPONSE(c, pubkey) \ + TRACE(c, "SPAKE response received with pubkey {hexdata}", pubkey) +#define TRACE_SPAKE_RECEIVE_SUPPORT(c, group) \ + TRACE(c, "SPAKE support message received, selected group {int}", group) +#define TRACE_SPAKE_REJECT_CHALLENGE(c, group) \ + TRACE(c, "SPAKE challenge with group {int} rejected", (int)group) +#define TRACE_SPAKE_REJECT_SUPPORT(c) \ + TRACE(c, "SPAKE support message rejected") +#define TRACE_SPAKE_RESULT(c, result) \ + TRACE(c, "SPAKE algorithm result: {hexdata}", result) +#define TRACE_SPAKE_SEND_CHALLENGE(c, group) \ + TRACE(c, "Sending SPAKE challenge with group {int}", group) +#define TRACE_SPAKE_SEND_RESPONSE(c) \ + TRACE(c, "Sending SPAKE response") +#define TRACE_SPAKE_SEND_SUPPORT(c) \ + TRACE(c, "Sending SPAKE support message") +#define TRACE_SPAKE_UNKNOWN_GROUP(c, name) \ + TRACE(c, "Unrecognized SPAKE group name: {string}", name) + +#endif /* TRACE_H */ diff --git a/src/plugins/preauth/spake/util.c b/src/plugins/preauth/spake/util.c new file mode 100644 index 000000000..cbdbbd7ac --- /dev/null +++ b/src/plugins/preauth/spake/util.c @@ -0,0 +1,211 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/util.c - Utility functions for SPAKE preauth module */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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 "k5-int.h" +#include "trace.h" +#include "util.h" +#include "groups.h" + +/* Use data to construct a single-element pa-data list of type + * KRB5_PADATA_SPAKE. Claim data's memory on success or failure. */ +krb5_error_code +convert_to_padata(krb5_data *data, krb5_pa_data ***pa_out) +{ + krb5_pa_data *pa = NULL, **list = NULL; + + list = calloc(2, sizeof(*list)); + if (list == NULL) + goto fail; + pa = calloc(1, sizeof(*pa)); + if (pa == NULL) + goto fail; + pa->magic = KV5M_PA_DATA; + pa->pa_type = KRB5_PADATA_SPAKE; + pa->length = data->length; + pa->contents = (uint8_t *)data->data; + list[0] = pa; + list[1] = NULL; + *pa_out = list; + free(data); + return 0; + +fail: + free(list); + free(pa); + free(data->data); + free(data); + return ENOMEM; +} + +/* + * Update the transcript hash thash with its current value and the + * concatenation of data1 and data2, using the hash function for group. Either + * data1 or data2 may be NULL to omit it. Allocate thash if it is empty. + */ +krb5_error_code +update_thash(krb5_context context, groupstate *gstate, int32_t group, + krb5_data *thash, const krb5_data *data1, const krb5_data *data2) +{ + krb5_error_code ret; + size_t hashlen; + krb5_data dlist[3]; + + if (thash->length == 0) { + /* Initialize the transcript hash to all zeros. */ + ret = group_hash_len(group, &hashlen); + if (ret) + return ret; + ret = alloc_data(thash, hashlen); + if (ret) + return ret; + } + + /* Set up the data array and hash it with the group's hash function. */ + dlist[0] = *thash; + dlist[1] = (data1 != NULL) ? *data1 : empty_data(); + dlist[2] = (data2 != NULL) ? *data2 : empty_data(); + return group_hash(context, gstate, group, dlist, 3, + (uint8_t *)thash->data); +} + +/* Derive a byte vector for the SPAKE w multiplier input from ikey. Place + * result in allocated storage in *wbytes_out. */ +krb5_error_code +derive_wbytes(krb5_context context, int32_t group, const krb5_keyblock *ikey, + krb5_data *wbytes_out) +{ + krb5_error_code ret; + const char prefix[] = "SPAKEsecret"; + size_t mult_len, prefix_len = sizeof(prefix) - 1; + krb5_data prf_input = empty_data(), wbytes = empty_data(); + + *wbytes_out = empty_data(); + + /* Allocate space for a multiplier. */ + ret = group_mult_len(group, &mult_len); + if (ret) + goto cleanup; + ret = alloc_data(&wbytes, mult_len); + if (ret) + goto cleanup; + + /* Compose the PRF input string. */ + ret = alloc_data(&prf_input, prefix_len + 4); + if (ret) + goto cleanup; + memcpy(prf_input.data, prefix, prefix_len); + store_32_be(group, prf_input.data + prefix_len); + + /* Derive the SPAKE input from the initial reply key with PRF+. */ + ret = krb5_c_prfplus(context, ikey, &prf_input, &wbytes); + if (ret) + goto cleanup; + + *wbytes_out = wbytes; + wbytes = empty_data(); + +cleanup: + free(prf_input.data); + zapfree(wbytes.data, wbytes.length); + return ret; +} + +/* + * Derive K'[n] from the group number, the initial key enctype, the initial + * multiplier, the SPAKE result, the transcript hash, and the encoded + * KDC-REQ-BODY. Place the result in allocated storage in *out. + */ +krb5_error_code +derive_key(krb5_context context, groupstate *gstate, int32_t group, + const krb5_keyblock *ikey, const krb5_data *wbytes, + const krb5_data *spakeresult, const krb5_data *thash, + const krb5_data *der_req, uint32_t n, krb5_keyblock **out) +{ + krb5_error_code ret; + krb5_data dlist[9], seed = empty_data(), d; + uint8_t groupnbuf[4], etypenbuf[4], nbuf[4], bcount; + size_t hashlen, seedlen, keylen, nblocks, i; + size_t ndata = sizeof(dlist) / sizeof(*dlist); + krb5_keyblock *hkey = NULL; + + *out = NULL; + + store_32_be(group, groupnbuf); + store_32_be(n, nbuf); + store_32_be(ikey->enctype, etypenbuf); + dlist[0] = string2data("SPAKEkey"); + dlist[1] = make_data(groupnbuf, sizeof(groupnbuf)); + dlist[2] = make_data(etypenbuf, sizeof(etypenbuf)); + dlist[3] = *wbytes; + dlist[4] = *spakeresult; + dlist[5] = *thash; + dlist[6] = *der_req; + dlist[7] = make_data(nbuf, sizeof(nbuf)); + dlist[8] = make_data(&bcount, 1); + + /* Count the number of hash blocks required (should be 1 for all current + * scenarios) and allocate space. */ + ret = group_hash_len(group, &hashlen); + if (ret) + goto cleanup; + ret = krb5_c_keylengths(context, ikey->enctype, &seedlen, &keylen); + if (ret) + goto cleanup; + nblocks = (seedlen + hashlen - 1) / hashlen; + ret = alloc_data(&seed, nblocks * hashlen); + if (ret) + goto cleanup; + + /* Compute and concatenate hash blocks to fill the seed buffer. */ + for (i = 0; i < nblocks; i++) { + bcount = i + 1; + ret = group_hash(context, gstate, group, dlist, ndata, + (uint8_t *)seed.data + i * hashlen); + if (ret) + goto cleanup; + } + + ret = krb5_init_keyblock(context, ikey->enctype, keylen, &hkey); + if (ret) + goto cleanup; + d = make_data(seed.data, seedlen); + ret = krb5_c_random_to_key(context, ikey->enctype, &d, hkey); + if (ret) + goto cleanup; + + ret = krb5_c_fx_cf2_simple(context, ikey, "SPAKE", hkey, "keyderiv", out); + +cleanup: + zapfree(seed.data, seed.length); + krb5_free_keyblock(context, hkey); + return ret; +} diff --git a/src/plugins/preauth/spake/util.h b/src/plugins/preauth/spake/util.h new file mode 100644 index 000000000..3ab2bead1 --- /dev/null +++ b/src/plugins/preauth/spake/util.h @@ -0,0 +1,56 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/preauth/spake/internal.h - SPAKE internal function declarations */ +/* + * Copyright (C) 2015 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 + * COPYRIGHT HOLDER OR 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. + */ + +#ifndef UTIL_H +#define UTIL_H + +#include "k5-int.h" +#include "groups.h" + +krb5_error_code convert_to_padata(krb5_data *data, krb5_pa_data ***pa_out); + +krb5_error_code update_thash(krb5_context context, groupstate *gstate, + int32_t group, krb5_data *thash, + const krb5_data *data1, const krb5_data *data2); + +krb5_error_code derive_wbytes(krb5_context context, int32_t group, + const krb5_keyblock *ikey, + krb5_data *wbytes_out); + +krb5_error_code derive_key(krb5_context context, groupstate *gstate, + int32_t group, const krb5_keyblock *ikey, + const krb5_data *wbytes, + const krb5_data *spakeresult, + const krb5_data *thash, const krb5_data *der_req, + uint32_t n, krb5_keyblock **out); + +#endif /* UTIL_H */ diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in index 67d3e8200..aed23e570 100644 --- a/src/tests/Makefile.in +++ b/src/tests/Makefile.in @@ -130,6 +130,7 @@ check-pytests: unlockiter $(RUNPYTEST) $(srcdir)/t_changepw.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_pkinit.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_otp.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_spake.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_localauth.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_kadm5_hook.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_kadm5_auth.py $(PYTESTFLAGS) diff --git a/src/tests/t_spake.py b/src/tests/t_spake.py new file mode 100644 index 000000000..a81a238b4 --- /dev/null +++ b/src/tests/t_spake.py @@ -0,0 +1,151 @@ +#!/usr/bin/python +from k5test import * + +# The name and number of each supported SPAKE group. +builtin_groups = ((1, 'edwards25519'),) +openssl_groups = ((2, 'P-256'), (3, 'P-384'), (4, 'P-521')) +if runenv.have_spake_openssl == 'yes': + groups = builtin_groups + openssl_groups +else: + groups = builtin_groups + +for gnum, gname in groups: + output('*** Testing group %s\n' % gname) + conf = {'libdefaults': {'spake_preauth_groups': gname}} + for realm in multipass_realms(create_user=False, create_host=False, + krb5_conf=conf): + realm.run([kadminl, 'addprinc', '+preauth', '-pw', 'pw', 'user']) + + # Test a basic SPAKE preauth scenario with no optimizations. + msgs = ('Sending unauthenticated request', + '/Additional pre-authentication required', + 'Selected etype info:', + 'Sending SPAKE support message', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + '/More preauthentication data is required', + 'Continuing preauth mech PA-SPAKE (151)', + 'SPAKE challenge received with group ' + str(gnum), + 'Sending SPAKE response', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + 'AS key determined by preauth:', + 'Decrypted AS reply') + realm.kinit('user', 'pw', expected_trace=msgs) + + # Test an unsuccessful authentication. (The client will try + # again with encrypted timestamp, which isn't really desired, + # but check for that as long as it is expected.) + msgs = ('/Additional pre-authentication required', + 'Selected etype info:', + 'Sending SPAKE support message', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + '/More preauthentication data is required', + 'Continuing preauth mech PA-SPAKE (151)', + 'SPAKE challenge received with group ' + str(gnum), + 'Sending SPAKE response', + '/Preauthentication failed', + 'Encrypted timestamp ', + 'for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)', + '/Preauthentication failed') + realm.kinit('user', 'wrongpw', expected_code=1, expected_trace=msgs) + +conf = {'libdefaults': {'spake_preauth_groups': 'edwards25519'}} +kdcconf = {'realms': {'$realm': {'spake_preauth_indicator': 'indspake'}}} +realm = K5Realm(create_user=False, krb5_conf=conf, kdc_conf=kdcconf) +realm.run([kadminl, 'addprinc', '+preauth', '-pw', 'pw', 'user']) + +# Test with FAST. +msgs = ('Using FAST due to armor ccache negotiation', + 'FAST armor key:', + 'Sending unauthenticated request', + '/Additional pre-authentication required', + 'Decoding FAST response', + 'Selected etype info:', + 'Sending SPAKE support message', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + '/More preauthentication data is required', + 'Continuing preauth mech PA-SPAKE (151)', + 'SPAKE challenge received with group 1', + 'Sending SPAKE response', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + 'AS key determined by preauth:', + 'FAST reply key:') +realm.kinit(realm.host_princ, flags=['-k']) +realm.kinit('user', 'pw', flags=['-T', realm.ccache], expected_trace=msgs) + +# Test optimistic client preauth (151 is PA-SPAKE). +msgs = ('Attempting optimistic preauth', + 'Processing preauth types: PA-SPAKE (151)', + 'Sending SPAKE support message', + 'for next request: PA-SPAKE (151)', + '/More preauthentication data is required', + 'Selected etype info:', + 'SPAKE challenge received with group 1', + 'Sending SPAKE response', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + 'AS key determined by preauth:', + 'Decrypted AS reply') +realm.run(['./icred', '-o', '151', 'user', 'pw'], expected_trace=msgs) + +# Test KDC optimistic challenge (accepted by client). +oconf = {'kdcdefaults': {'spake_preauth_kdc_challenge': 'edwards25519'}} +oenv = realm.special_env('ochal', True, krb5_conf=oconf) +realm.stop_kdc() +realm.start_kdc(env=oenv) +msgs = ('Sending unauthenticated request', + '/Additional pre-authentication required', + 'Selected etype info:', + 'SPAKE challenge received with group 1', + 'Sending SPAKE response', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + 'AS key determined by preauth:', + 'Decrypted AS reply') +realm.kinit('user', 'pw', expected_trace=msgs) + +if runenv.have_spake_openssl != 'yes': + skip_rest('SPAKE fallback tests', 'SPAKE not built using OpenSSL') + +# Test optimistic client preauth falling back to encrypted timestamp +# because the KDC doesn't support any of the client groups. +p256conf={'libdefaults': {'spake_preauth_groups': 'P-256'}} +p256env = realm.special_env('p256', False, krb5_conf=p256conf) +msgs = ('Attempting optimistic preauth', + 'Processing preauth types: PA-SPAKE (151)', + 'Sending SPAKE support message', + 'for next request: PA-SPAKE (151)', + '/Preauthentication failed', + 'Selected etype info:', + 'SPAKE challenge with group 1 rejected', + 'spake (151) (real) returned: -1765328360/Preauthentication failed', + 'Encrypted timestamp ', + 'for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)', + 'AS key determined by preauth:', + 'Decrypted AS reply') +realm.run(['./icred', '-o', '151', 'user', 'pw'], env=p256env, + expected_trace=msgs) + +# Test KDC optimistic challenge (rejected by client). +rconf = {'libdefaults': {'spake_preauth_groups': 'P-384,edwards25519'}, + 'kdcdefaults': {'spake_preauth_kdc_challenge': 'P-384'}} +renv = realm.special_env('ochal', True, krb5_conf=rconf) +realm.stop_kdc() +realm.start_kdc(env=renv) +msgs = ('Sending unauthenticated request', + '/Additional pre-authentication required', + 'Selected etype info:', + 'SPAKE challenge with group 3 rejected', + 'Sending SPAKE support message', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + '/More preauthentication data is required', + 'Continuing preauth mech PA-SPAKE (151)', + 'SPAKE challenge received with group 1', + 'Sending SPAKE response', + 'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)', + 'AS key determined by preauth:', + 'Decrypted AS reply') +realm.kinit('user', 'pw', expected_trace=msgs) + +# Check that the auth indicator for SPAKE is properly included by the KDC. +realm.run([kvno, realm.host_princ]) +realm.run(['./adata', realm.host_princ], expected_msg='+97: [indspake]') + +success('SPAKE pre-authentication tests')