summaryrefslogtreecommitdiff
path: root/crypto/ec
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/ec')
-rw-r--r--crypto/ec/Makefile80
-rw-r--r--crypto/ec/ec.h875
-rw-r--r--crypto/ec/ec2_mult.c37
-rw-r--r--crypto/ec/ec2_oct.c407
-rw-r--r--crypto/ec/ec2_smpl.c297
-rw-r--r--crypto/ec/ec2_smpt.c141
-rw-r--r--crypto/ec/ec_ameth.c660
-rw-r--r--crypto/ec/ec_asn1.c24
-rw-r--r--crypto/ec/ec_curve.c2650
-rw-r--r--crypto/ec/ec_cvt.c28
-rw-r--r--crypto/ec/ec_err.c41
-rw-r--r--crypto/ec/ec_key.c102
-rw-r--r--crypto/ec/ec_lcl.h68
-rw-r--r--crypto/ec/ec_lib.c84
-rw-r--r--crypto/ec/ec_mult.c22
-rw-r--r--crypto/ec/ec_oct.c199
-rw-r--r--crypto/ec/ec_pmeth.c341
-rw-r--r--crypto/ec/eck_prn.c392
-rw-r--r--crypto/ec/ecp_mont.c14
-rw-r--r--crypto/ec/ecp_nist.c39
-rw-r--r--crypto/ec/ecp_nistp224.c1658
-rw-r--r--crypto/ec/ecp_nistp256.c2171
-rw-r--r--crypto/ec/ecp_nistp521.c2025
-rw-r--r--crypto/ec/ecp_nistputil.c197
-rw-r--r--crypto/ec/ecp_oct.c433
-rw-r--r--crypto/ec/ecp_smpl.c379
-rw-r--r--crypto/ec/ectest.c353
27 files changed, 11640 insertions, 2077 deletions
diff --git a/crypto/ec/Makefile b/crypto/ec/Makefile
index b5bbc9faa1a21..f85fc845ca2b3 100644
--- a/crypto/ec/Makefile
+++ b/crypto/ec/Makefile
@@ -19,11 +19,15 @@ APPS=
LIB=$(TOP)/libcrypto.a
LIBSRC= ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c\
ec_err.c ec_curve.c ec_check.c ec_print.c ec_asn1.c ec_key.c\
- ec2_smpl.c ec2_smpt.c ec2_mult.c
+ ec2_smpl.c ec2_mult.c ec_ameth.c ec_pmeth.c eck_prn.c \
+ ecp_nistp224.c ecp_nistp256.c ecp_nistp521.c ecp_nistputil.c \
+ ecp_oct.c ec2_oct.c ec_oct.c
LIBOBJ= ec_lib.o ecp_smpl.o ecp_mont.o ecp_nist.o ec_cvt.o ec_mult.o\
ec_err.o ec_curve.o ec_check.o ec_print.o ec_asn1.o ec_key.o\
- ec2_smpl.o ec2_mult.o
+ ec2_smpl.o ec2_mult.o ec_ameth.o ec_pmeth.o eck_prn.o \
+ ecp_nistp224.o ecp_nistp256.o ecp_nistp521.o ecp_nistputil.o \
+ ecp_oct.o ec2_oct.o ec_oct.o
SRC= $(LIBSRC)
@@ -38,7 +42,7 @@ top:
all: lib
lib: $(LIBOBJ)
- $(ARX) $(LIB) $(LIBOBJ)
+ $(AR) $(LIB) $(LIBOBJ)
$(RANLIB) $(LIB) || echo Never mind.
@touch lib
@@ -87,6 +91,14 @@ ec2_mult.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h
ec2_mult.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
ec2_mult.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
ec2_mult.o: ../../include/openssl/symhacks.h ec2_mult.c ec_lcl.h
+ec2_oct.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
+ec2_oct.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h
+ec2_oct.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
+ec2_oct.o: ../../include/openssl/err.h ../../include/openssl/lhash.h
+ec2_oct.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h
+ec2_oct.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
+ec2_oct.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
+ec2_oct.o: ../../include/openssl/symhacks.h ec2_oct.c ec_lcl.h
ec2_smpl.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
ec2_smpl.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h
ec2_smpl.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
@@ -94,8 +106,22 @@ ec2_smpl.o: ../../include/openssl/err.h ../../include/openssl/lhash.h
ec2_smpl.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h
ec2_smpl.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
ec2_smpl.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
-ec2_smpl.o: ../../include/openssl/symhacks.h ec2_smpl.c ec2_smpt.c ec_lcl.h
-ec2_smpt.o: ec2_smpt.c
+ec2_smpl.o: ../../include/openssl/symhacks.h ec2_smpl.c ec_lcl.h
+ec_ameth.o: ../../e_os.h ../../include/openssl/asn1.h
+ec_ameth.o: ../../include/openssl/bio.h ../../include/openssl/bn.h
+ec_ameth.o: ../../include/openssl/buffer.h ../../include/openssl/cms.h
+ec_ameth.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
+ec_ameth.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h
+ec_ameth.o: ../../include/openssl/ecdsa.h ../../include/openssl/err.h
+ec_ameth.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h
+ec_ameth.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h
+ec_ameth.o: ../../include/openssl/opensslconf.h
+ec_ameth.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
+ec_ameth.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h
+ec_ameth.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ec_ameth.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ec_ameth.o: ../../include/openssl/x509_vfy.h ../asn1/asn1_locl.h ../cryptlib.h
+ec_ameth.o: ec_ameth.c
ec_asn1.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h
ec_asn1.o: ../../include/openssl/bio.h ../../include/openssl/bn.h
ec_asn1.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h
@@ -160,6 +186,28 @@ ec_mult.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h
ec_mult.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
ec_mult.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
ec_mult.o: ../../include/openssl/symhacks.h ec_lcl.h ec_mult.c
+ec_oct.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
+ec_oct.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h
+ec_oct.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
+ec_oct.o: ../../include/openssl/err.h ../../include/openssl/lhash.h
+ec_oct.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h
+ec_oct.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
+ec_oct.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
+ec_oct.o: ../../include/openssl/symhacks.h ec_lcl.h ec_oct.c
+ec_pmeth.o: ../../e_os.h ../../include/openssl/asn1.h
+ec_pmeth.o: ../../include/openssl/asn1t.h ../../include/openssl/bio.h
+ec_pmeth.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h
+ec_pmeth.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
+ec_pmeth.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h
+ec_pmeth.o: ../../include/openssl/err.h ../../include/openssl/evp.h
+ec_pmeth.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
+ec_pmeth.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
+ec_pmeth.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
+ec_pmeth.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h
+ec_pmeth.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+ec_pmeth.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+ec_pmeth.o: ../../include/openssl/x509_vfy.h ../cryptlib.h ../evp/evp_locl.h
+ec_pmeth.o: ec_pmeth.c
ec_print.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
ec_print.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h
ec_print.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
@@ -167,6 +215,16 @@ ec_print.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h
ec_print.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
ec_print.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
ec_print.o: ../../include/openssl/symhacks.h ec_lcl.h ec_print.c
+eck_prn.o: ../../e_os.h ../../include/openssl/asn1.h
+eck_prn.o: ../../include/openssl/bio.h ../../include/openssl/bn.h
+eck_prn.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h
+eck_prn.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
+eck_prn.o: ../../include/openssl/err.h ../../include/openssl/evp.h
+eck_prn.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
+eck_prn.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
+eck_prn.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
+eck_prn.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
+eck_prn.o: ../../include/openssl/symhacks.h ../cryptlib.h eck_prn.c
ecp_mont.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
ecp_mont.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h
ecp_mont.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
@@ -183,6 +241,18 @@ ecp_nist.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h
ecp_nist.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
ecp_nist.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
ecp_nist.o: ../../include/openssl/symhacks.h ec_lcl.h ecp_nist.c
+ecp_nistp224.o: ../../include/openssl/opensslconf.h ecp_nistp224.c
+ecp_nistp256.o: ../../include/openssl/opensslconf.h ecp_nistp256.c
+ecp_nistp521.o: ../../include/openssl/opensslconf.h ecp_nistp521.c
+ecp_nistputil.o: ../../include/openssl/opensslconf.h ecp_nistputil.c
+ecp_oct.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
+ecp_oct.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h
+ecp_oct.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
+ecp_oct.o: ../../include/openssl/err.h ../../include/openssl/lhash.h
+ecp_oct.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h
+ecp_oct.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
+ecp_oct.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h
+ecp_oct.o: ../../include/openssl/symhacks.h ec_lcl.h ecp_oct.c
ecp_smpl.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
ecp_smpl.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h
ecp_smpl.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
diff --git a/crypto/ec/ec.h b/crypto/ec/ec.h
index 8bc2a235b1a75..9d01325af33b9 100644
--- a/crypto/ec/ec.h
+++ b/crypto/ec/ec.h
@@ -2,8 +2,12 @@
/*
* Originally written by Bodo Moeller for the OpenSSL project.
*/
+/**
+ * \file crypto/ec/ec.h Include file for the OpenSSL EC functions
+ * \author Originally written by Bodo Moeller for the OpenSSL project
+ */
/* ====================================================================
- * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -92,15 +96,21 @@ extern "C" {
# endif
#endif
-
+
#ifndef OPENSSL_ECC_MAX_FIELD_BITS
# define OPENSSL_ECC_MAX_FIELD_BITS 661
#endif
+/** Enum for the point conversion form as defined in X9.62 (ECDSA)
+ * for the encoding of a elliptic curve point (x,y) */
typedef enum {
- /* values as defined in X9.62 (ECDSA) and elsewhere */
+ /** the point is encoded as z||x, where the octet z specifies
+ * which solution of the quadratic equation y is */
POINT_CONVERSION_COMPRESSED = 2,
+ /** the point is encoded as z||x||y, where z is the octet 0x02 */
POINT_CONVERSION_UNCOMPRESSED = 4,
+ /** the point is encoded as z||x||y, where the octet z specifies
+ * which solution of the quadratic equation y is */
POINT_CONVERSION_HYBRID = 6
} point_conversion_form_t;
@@ -121,37 +131,148 @@ typedef struct ec_group_st
typedef struct ec_point_st EC_POINT;
-/* EC_METHODs for curves over GF(p).
- * EC_GFp_simple_method provides the basis for the optimized methods.
+/********************************************************************/
+/* EC_METHODs for curves over GF(p) */
+/********************************************************************/
+
+/** Returns the basic GFp ec methods which provides the basis for the
+ * optimized methods.
+ * \return EC_METHOD object
*/
const EC_METHOD *EC_GFp_simple_method(void);
+
+/** Returns GFp methods using montgomery multiplication.
+ * \return EC_METHOD object
+ */
const EC_METHOD *EC_GFp_mont_method(void);
+
+/** Returns GFp methods using optimized methods for NIST recommended curves
+ * \return EC_METHOD object
+ */
const EC_METHOD *EC_GFp_nist_method(void);
-/* EC_METHOD for curves over GF(2^m).
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+/** Returns 64-bit optimized methods for nistp224
+ * \return EC_METHOD object
+ */
+const EC_METHOD *EC_GFp_nistp224_method(void);
+
+/** Returns 64-bit optimized methods for nistp256
+ * \return EC_METHOD object
+ */
+const EC_METHOD *EC_GFp_nistp256_method(void);
+
+/** Returns 64-bit optimized methods for nistp521
+ * \return EC_METHOD object
+ */
+const EC_METHOD *EC_GFp_nistp521_method(void);
+#endif
+
+#ifndef OPENSSL_NO_EC2M
+/********************************************************************/
+/* EC_METHOD for curves over GF(2^m) */
+/********************************************************************/
+
+/** Returns the basic GF2m ec method
+ * \return EC_METHOD object
*/
const EC_METHOD *EC_GF2m_simple_method(void);
+#endif
+
-EC_GROUP *EC_GROUP_new(const EC_METHOD *);
-void EC_GROUP_free(EC_GROUP *);
-void EC_GROUP_clear_free(EC_GROUP *);
-int EC_GROUP_copy(EC_GROUP *, const EC_GROUP *);
-EC_GROUP *EC_GROUP_dup(const EC_GROUP *);
+/********************************************************************/
+/* EC_GROUP functions */
+/********************************************************************/
-const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
-int EC_METHOD_get_field_type(const EC_METHOD *);
+/** Creates a new EC_GROUP object
+ * \param meth EC_METHOD to use
+ * \return newly created EC_GROUP object or NULL in case of an error.
+ */
+EC_GROUP *EC_GROUP_new(const EC_METHOD *meth);
-int EC_GROUP_set_generator(EC_GROUP *, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor);
-const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
-int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *order, BN_CTX *);
-int EC_GROUP_get_cofactor(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *);
+/** Frees a EC_GROUP object
+ * \param group EC_GROUP object to be freed.
+ */
+void EC_GROUP_free(EC_GROUP *group);
-void EC_GROUP_set_curve_name(EC_GROUP *, int nid);
-int EC_GROUP_get_curve_name(const EC_GROUP *);
+/** Clears and frees a EC_GROUP object
+ * \param group EC_GROUP object to be cleared and freed.
+ */
+void EC_GROUP_clear_free(EC_GROUP *group);
-void EC_GROUP_set_asn1_flag(EC_GROUP *, int flag);
-int EC_GROUP_get_asn1_flag(const EC_GROUP *);
+/** Copies EC_GROUP objects. Note: both EC_GROUPs must use the same EC_METHOD.
+ * \param dst destination EC_GROUP object
+ * \param src source EC_GROUP object
+ * \return 1 on success and 0 if an error occurred.
+ */
+int EC_GROUP_copy(EC_GROUP *dst, const EC_GROUP *src);
+
+/** Creates a new EC_GROUP object and copies the copies the content
+ * form src to the newly created EC_KEY object
+ * \param src source EC_GROUP object
+ * \return newly created EC_GROUP object or NULL in case of an error.
+ */
+EC_GROUP *EC_GROUP_dup(const EC_GROUP *src);
+
+/** Returns the EC_METHOD of the EC_GROUP object.
+ * \param group EC_GROUP object
+ * \return EC_METHOD used in this EC_GROUP object.
+ */
+const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group);
+
+/** Returns the field type of the EC_METHOD.
+ * \param meth EC_METHOD object
+ * \return NID of the underlying field type OID.
+ */
+int EC_METHOD_get_field_type(const EC_METHOD *meth);
+
+/** Sets the generator and it's order/cofactor of a EC_GROUP object.
+ * \param group EC_GROUP object
+ * \param generator EC_POINT object with the generator.
+ * \param order the order of the group generated by the generator.
+ * \param cofactor the index of the sub-group generated by the generator
+ * in the group of all points on the elliptic curve.
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor);
+
+/** Returns the generator of a EC_GROUP object.
+ * \param group EC_GROUP object
+ * \return the currently used generator (possibly NULL).
+ */
+const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group);
+
+/** Gets the order of a EC_GROUP
+ * \param group EC_GROUP object
+ * \param order BIGNUM to which the order is copied
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx);
+
+/** Gets the cofactor of a EC_GROUP
+ * \param group EC_GROUP object
+ * \param cofactor BIGNUM to which the cofactor is copied
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx);
+
+/** Sets the name of a EC_GROUP object
+ * \param group EC_GROUP object
+ * \param nid NID of the curve name OID
+ */
+void EC_GROUP_set_curve_name(EC_GROUP *group, int nid);
+
+/** Returns the curve name of a EC_GROUP object
+ * \param group EC_GROUP object
+ * \return NID of the curve name OID or 0 if not set.
+ */
+int EC_GROUP_get_curve_name(const EC_GROUP *group);
+
+void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag);
+int EC_GROUP_get_asn1_flag(const EC_GROUP *group);
void EC_GROUP_set_point_conversion_form(EC_GROUP *, point_conversion_form_t);
point_conversion_form_t EC_GROUP_get_point_conversion_form(const EC_GROUP *);
@@ -160,36 +281,115 @@ unsigned char *EC_GROUP_get0_seed(const EC_GROUP *);
size_t EC_GROUP_get_seed_len(const EC_GROUP *);
size_t EC_GROUP_set_seed(EC_GROUP *, const unsigned char *, size_t len);
-int EC_GROUP_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int EC_GROUP_get_curve_GFp(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
-int EC_GROUP_set_curve_GF2m(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-int EC_GROUP_get_curve_GF2m(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
-
-/* returns the number of bits needed to represent a field element */
-int EC_GROUP_get_degree(const EC_GROUP *);
+/** Sets the parameter of a ec over GFp defined by y^2 = x^3 + a*x + b
+ * \param group EC_GROUP object
+ * \param p BIGNUM with the prime number
+ * \param a BIGNUM with parameter a of the equation
+ * \param b BIGNUM with parameter b of the equation
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+
+/** Gets the parameter of the ec over GFp defined by y^2 = x^3 + a*x + b
+ * \param group EC_GROUP object
+ * \param p BIGNUM for the prime number
+ * \param a BIGNUM for parameter a of the equation
+ * \param b BIGNUM for parameter b of the equation
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx);
+
+#ifndef OPENSSL_NO_EC2M
+/** Sets the parameter of a ec over GF2m defined by y^2 + x*y = x^3 + a*x^2 + b
+ * \param group EC_GROUP object
+ * \param p BIGNUM with the polynomial defining the underlying field
+ * \param a BIGNUM with parameter a of the equation
+ * \param b BIGNUM with parameter b of the equation
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_GROUP_set_curve_GF2m(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+
+/** Gets the parameter of the ec over GF2m defined by y^2 + x*y = x^3 + a*x^2 + b
+ * \param group EC_GROUP object
+ * \param p BIGNUM for the polynomial defining the underlying field
+ * \param a BIGNUM for parameter a of the equation
+ * \param b BIGNUM for parameter b of the equation
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_GROUP_get_curve_GF2m(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx);
+#endif
+/** Returns the number of bits needed to represent a field element
+ * \param group EC_GROUP object
+ * \return number of bits needed to represent a field element
+ */
+int EC_GROUP_get_degree(const EC_GROUP *group);
-/* EC_GROUP_check() returns 1 if 'group' defines a valid group, 0 otherwise */
+/** Checks whether the parameter in the EC_GROUP define a valid ec group
+ * \param group EC_GROUP object
+ * \param ctx BN_CTX object (optional)
+ * \return 1 if group is a valid ec group and 0 otherwise
+ */
int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx);
-/* EC_GROUP_check_discriminant() returns 1 if the discriminant of the
- * elliptic curve is not zero, 0 otherwise */
-int EC_GROUP_check_discriminant(const EC_GROUP *, BN_CTX *);
-/* EC_GROUP_cmp() returns 0 if both groups are equal and 1 otherwise */
-int EC_GROUP_cmp(const EC_GROUP *, const EC_GROUP *, BN_CTX *);
+/** Checks whether the discriminant of the elliptic curve is zero or not
+ * \param group EC_GROUP object
+ * \param ctx BN_CTX object (optional)
+ * \return 1 if the discriminant is not zero and 0 otherwise
+ */
+int EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx);
+
+/** Compares two EC_GROUP objects
+ * \param a first EC_GROUP object
+ * \param b second EC_GROUP object
+ * \param ctx BN_CTX object (optional)
+ * \return 0 if both groups are equal and 1 otherwise
+ */
+int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx);
/* EC_GROUP_new_GF*() calls EC_GROUP_new() and EC_GROUP_set_GF*()
* after choosing an appropriate EC_METHOD */
-EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
-/* EC_GROUP_new_by_curve_name() creates a EC_GROUP structure
- * specified by a curve name (in form of a NID) */
+/** Creates a new EC_GROUP object with the specified parameters defined
+ * over GFp (defined by the equation y^2 = x^3 + a*x + b)
+ * \param p BIGNUM with the prime number
+ * \param a BIGNUM with the parameter a of the equation
+ * \param b BIGNUM with the parameter b of the equation
+ * \param ctx BN_CTX object (optional)
+ * \return newly created EC_GROUP object with the specified parameters
+ */
+EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+#ifndef OPENSSL_NO_EC2M
+/** Creates a new EC_GROUP object with the specified parameters defined
+ * over GF2m (defined by the equation y^2 + x*y = x^3 + a*x^2 + b)
+ * \param p BIGNUM with the polynomial defining the underlying field
+ * \param a BIGNUM with the parameter a of the equation
+ * \param b BIGNUM with the parameter b of the equation
+ * \param ctx BN_CTX object (optional)
+ * \return newly created EC_GROUP object with the specified parameters
+ */
+EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+#endif
+/** Creates a EC_GROUP object with a curve specified by a NID
+ * \param nid NID of the OID of the curve name
+ * \return newly created EC_GROUP object with specified curve or NULL
+ * if an error occurred
+ */
EC_GROUP *EC_GROUP_new_by_curve_name(int nid);
-/* handling of internal curves */
+
+
+/********************************************************************/
+/* handling of internal curves */
+/********************************************************************/
+
typedef struct {
int nid;
const char *comment;
} EC_builtin_curve;
+
/* EC_builtin_curves(EC_builtin_curve *r, size_t size) returns number
* of all available curves or zero if a error occurred.
* In case r ist not zero nitems EC_builtin_curve structures
@@ -197,39 +397,168 @@ typedef struct {
size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
-/* EC_POINT functions */
+/********************************************************************/
+/* EC_POINT functions */
+/********************************************************************/
+
+/** Creates a new EC_POINT object for the specified EC_GROUP
+ * \param group EC_GROUP the underlying EC_GROUP object
+ * \return newly created EC_POINT object or NULL if an error occurred
+ */
+EC_POINT *EC_POINT_new(const EC_GROUP *group);
+
+/** Frees a EC_POINT object
+ * \param point EC_POINT object to be freed
+ */
+void EC_POINT_free(EC_POINT *point);
-EC_POINT *EC_POINT_new(const EC_GROUP *);
-void EC_POINT_free(EC_POINT *);
-void EC_POINT_clear_free(EC_POINT *);
-int EC_POINT_copy(EC_POINT *, const EC_POINT *);
-EC_POINT *EC_POINT_dup(const EC_POINT *, const EC_GROUP *);
+/** Clears and frees a EC_POINT object
+ * \param point EC_POINT object to be cleared and freed
+ */
+void EC_POINT_clear_free(EC_POINT *point);
+
+/** Copies EC_POINT object
+ * \param dst destination EC_POINT object
+ * \param src source EC_POINT object
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_copy(EC_POINT *dst, const EC_POINT *src);
+
+/** Creates a new EC_POINT object and copies the content of the supplied
+ * EC_POINT
+ * \param src source EC_POINT object
+ * \param group underlying the EC_GROUP object
+ * \return newly created EC_POINT object or NULL if an error occurred
+ */
+EC_POINT *EC_POINT_dup(const EC_POINT *src, const EC_GROUP *group);
-const EC_METHOD *EC_POINT_method_of(const EC_POINT *);
-
-int EC_POINT_set_to_infinity(const EC_GROUP *, EC_POINT *);
-int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *);
-int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *, const EC_POINT *,
- BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *);
-int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, const BIGNUM *y, BN_CTX *);
-int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *, const EC_POINT *,
- BIGNUM *x, BIGNUM *y, BN_CTX *);
-int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, int y_bit, BN_CTX *);
-
-int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, const BIGNUM *y, BN_CTX *);
-int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *, const EC_POINT *,
- BIGNUM *x, BIGNUM *y, BN_CTX *);
-int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *, EC_POINT *,
- const BIGNUM *x, int y_bit, BN_CTX *);
-
-size_t EC_POINT_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *);
-int EC_POINT_oct2point(const EC_GROUP *, EC_POINT *,
- const unsigned char *buf, size_t len, BN_CTX *);
+/** Returns the EC_METHOD used in EC_POINT object
+ * \param point EC_POINT object
+ * \return the EC_METHOD used
+ */
+const EC_METHOD *EC_POINT_method_of(const EC_POINT *point);
+
+/** Sets a point to infinity (neutral element)
+ * \param group underlying EC_GROUP object
+ * \param point EC_POINT to set to infinity
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point);
+
+/** Sets the jacobian projective coordinates of a EC_POINT over GFp
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param x BIGNUM with the x-coordinate
+ * \param y BIGNUM with the y-coordinate
+ * \param z BIGNUM with the z-coordinate
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *p,
+ const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx);
+
+/** Gets the jacobian projective coordinates of a EC_POINT over GFp
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param x BIGNUM for the x-coordinate
+ * \param y BIGNUM for the y-coordinate
+ * \param z BIGNUM for the z-coordinate
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
+ const EC_POINT *p, BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx);
+
+/** Sets the affine coordinates of a EC_POINT over GFp
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param x BIGNUM with the x-coordinate
+ * \param y BIGNUM with the y-coordinate
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *p,
+ const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx);
+
+/** Gets the affine coordinates of a EC_POINT over GFp
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param x BIGNUM for the x-coordinate
+ * \param y BIGNUM for the y-coordinate
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
+ const EC_POINT *p, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
+
+/** Sets the x9.62 compressed coordinates of a EC_POINT over GFp
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param x BIGNUM with x-coordinate
+ * \param y_bit integer with the y-Bit (either 0 or 1)
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *p,
+ const BIGNUM *x, int y_bit, BN_CTX *ctx);
+#ifndef OPENSSL_NO_EC2M
+/** Sets the affine coordinates of a EC_POINT over GF2m
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param x BIGNUM with the x-coordinate
+ * \param y BIGNUM with the y-coordinate
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p,
+ const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx);
+
+/** Gets the affine coordinates of a EC_POINT over GF2m
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param x BIGNUM for the x-coordinate
+ * \param y BIGNUM for the y-coordinate
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *group,
+ const EC_POINT *p, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
+
+/** Sets the x9.62 compressed coordinates of a EC_POINT over GF2m
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param x BIGNUM with x-coordinate
+ * \param y_bit integer with the y-Bit (either 0 or 1)
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *group, EC_POINT *p,
+ const BIGNUM *x, int y_bit, BN_CTX *ctx);
+#endif
+/** Encodes a EC_POINT object to a octet string
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param form point conversion form
+ * \param buf memory buffer for the result. If NULL the function returns
+ * required buffer size.
+ * \param len length of the memory buffer
+ * \param ctx BN_CTX object (optional)
+ * \return the length of the encoded octet string or 0 if an error occurred
+ */
+size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *p,
+ point_conversion_form_t form,
+ unsigned char *buf, size_t len, BN_CTX *ctx);
+
+/** Decodes a EC_POINT from a octet string
+ * \param group underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \param buf memory buffer with the encoded ec point
+ * \param len length of the encoded ec point
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *p,
+ const unsigned char *buf, size_t len, BN_CTX *ctx);
/* other interfaces to point2oct/oct2point: */
BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *,
@@ -241,36 +570,114 @@ char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *,
EC_POINT *EC_POINT_hex2point(const EC_GROUP *, const char *,
EC_POINT *, BN_CTX *);
-int EC_POINT_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
-int EC_POINT_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
-int EC_POINT_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
-int EC_POINT_is_at_infinity(const EC_GROUP *, const EC_POINT *);
-int EC_POINT_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
-int EC_POINT_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+/********************************************************************/
+/* functions for doing EC_POINT arithmetic */
+/********************************************************************/
+
+/** Computes the sum of two EC_POINT
+ * \param group underlying EC_GROUP object
+ * \param r EC_POINT object for the result (r = a + b)
+ * \param a EC_POINT object with the first summand
+ * \param b EC_POINT object with the second summand
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx);
+
+/** Computes the double of a EC_POINT
+ * \param group underlying EC_GROUP object
+ * \param r EC_POINT object for the result (r = 2 * a)
+ * \param a EC_POINT object
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx);
+
+/** Computes the inverse of a EC_POINT
+ * \param group underlying EC_GROUP object
+ * \param a EC_POINT object to be inverted (it's used for the result as well)
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx);
+
+/** Checks whether the point is the neutral element of the group
+ * \param group the underlying EC_GROUP object
+ * \param p EC_POINT object
+ * \return 1 if the point is the neutral element and 0 otherwise
+ */
+int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *p);
+
+/** Checks whether the point is on the curve
+ * \param group underlying EC_GROUP object
+ * \param point EC_POINT object to check
+ * \param ctx BN_CTX object (optional)
+ * \return 1 if point if on the curve and 0 otherwise
+ */
+int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx);
+
+/** Compares two EC_POINTs
+ * \param group underlying EC_GROUP object
+ * \param a first EC_POINT object
+ * \param b second EC_POINT object
+ * \param ctx BN_CTX object (optional)
+ * \return 0 if both points are equal and a value != 0 otherwise
+ */
+int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx);
int EC_POINT_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
int EC_POINTs_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
+/** Computes r = generator * n sum_{i=0}^num p[i] * m[i]
+ * \param group underlying EC_GROUP object
+ * \param r EC_POINT object for the result
+ * \param n BIGNUM with the multiplier for the group generator (optional)
+ * \param num number futher summands
+ * \param p array of size num of EC_POINT objects
+ * \param m array of size num of BIGNUM objects
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, size_t num, const EC_POINT *p[], const BIGNUM *m[], BN_CTX *ctx);
+
+/** Computes r = generator * n + q * m
+ * \param group underlying EC_GROUP object
+ * \param r EC_POINT object for the result
+ * \param n BIGNUM with the multiplier for the group generator (optional)
+ * \param q EC_POINT object with the first factor of the second summand
+ * \param m BIGNUM with the second factor of the second summand
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n, const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx);
-int EC_POINTs_mul(const EC_GROUP *, EC_POINT *r, const BIGNUM *, size_t num, const EC_POINT *[], const BIGNUM *[], BN_CTX *);
-int EC_POINT_mul(const EC_GROUP *, EC_POINT *r, const BIGNUM *, const EC_POINT *, const BIGNUM *, BN_CTX *);
-
-/* EC_GROUP_precompute_mult() stores multiples of generator for faster point multiplication */
-int EC_GROUP_precompute_mult(EC_GROUP *, BN_CTX *);
-/* EC_GROUP_have_precompute_mult() reports whether such precomputation has been done */
-int EC_GROUP_have_precompute_mult(const EC_GROUP *);
+/** Stores multiples of generator for faster point multiplication
+ * \param group EC_GROUP object
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occured
+ */
+int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+/** Reports whether a precomputation has been done
+ * \param group EC_GROUP object
+ * \return 1 if a pre-computation has been done and 0 otherwise
+ */
+int EC_GROUP_have_precompute_mult(const EC_GROUP *group);
-/* ASN1 stuff */
+/********************************************************************/
+/* ASN1 stuff */
+/********************************************************************/
/* EC_GROUP_get_basis_type() returns the NID of the basis type
* used to represent the field elements */
int EC_GROUP_get_basis_type(const EC_GROUP *);
+#ifndef OPENSSL_NO_EC2M
int EC_GROUP_get_trinomial_basis(const EC_GROUP *, unsigned int *k);
int EC_GROUP_get_pentanomial_basis(const EC_GROUP *, unsigned int *k1,
unsigned int *k2, unsigned int *k3);
+#endif
#define OPENSSL_EC_NAMED_CURVE 0x001
@@ -293,28 +700,106 @@ int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off);
int ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off);
#endif
-/* the EC_KEY stuff */
+
+/********************************************************************/
+/* EC_KEY functions */
+/********************************************************************/
+
typedef struct ec_key_st EC_KEY;
/* some values for the encoding_flag */
#define EC_PKEY_NO_PARAMETERS 0x001
#define EC_PKEY_NO_PUBKEY 0x002
+/* some values for the flags field */
+#define EC_FLAG_NON_FIPS_ALLOW 0x1
+#define EC_FLAG_FIPS_CHECKED 0x2
+
+/** Creates a new EC_KEY object.
+ * \return EC_KEY object or NULL if an error occurred.
+ */
EC_KEY *EC_KEY_new(void);
+
+int EC_KEY_get_flags(const EC_KEY *key);
+
+void EC_KEY_set_flags(EC_KEY *key, int flags);
+
+void EC_KEY_clear_flags(EC_KEY *key, int flags);
+
+/** Creates a new EC_KEY object using a named curve as underlying
+ * EC_GROUP object.
+ * \param nid NID of the named curve.
+ * \return EC_KEY object or NULL if an error occurred.
+ */
EC_KEY *EC_KEY_new_by_curve_name(int nid);
-void EC_KEY_free(EC_KEY *);
-EC_KEY *EC_KEY_copy(EC_KEY *, const EC_KEY *);
-EC_KEY *EC_KEY_dup(const EC_KEY *);
-
-int EC_KEY_up_ref(EC_KEY *);
-
-const EC_GROUP *EC_KEY_get0_group(const EC_KEY *);
-int EC_KEY_set_group(EC_KEY *, const EC_GROUP *);
-const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *);
-int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *);
-const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *);
-int EC_KEY_set_public_key(EC_KEY *, const EC_POINT *);
-unsigned EC_KEY_get_enc_flags(const EC_KEY *);
+
+/** Frees a EC_KEY object.
+ * \param key EC_KEY object to be freed.
+ */
+void EC_KEY_free(EC_KEY *key);
+
+/** Copies a EC_KEY object.
+ * \param dst destination EC_KEY object
+ * \param src src EC_KEY object
+ * \return dst or NULL if an error occurred.
+ */
+EC_KEY *EC_KEY_copy(EC_KEY *dst, const EC_KEY *src);
+
+/** Creates a new EC_KEY object and copies the content from src to it.
+ * \param src the source EC_KEY object
+ * \return newly created EC_KEY object or NULL if an error occurred.
+ */
+EC_KEY *EC_KEY_dup(const EC_KEY *src);
+
+/** Increases the internal reference count of a EC_KEY object.
+ * \param key EC_KEY object
+ * \return 1 on success and 0 if an error occurred.
+ */
+int EC_KEY_up_ref(EC_KEY *key);
+
+/** Returns the EC_GROUP object of a EC_KEY object
+ * \param key EC_KEY object
+ * \return the EC_GROUP object (possibly NULL).
+ */
+const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
+
+/** Sets the EC_GROUP of a EC_KEY object.
+ * \param key EC_KEY object
+ * \param group EC_GROUP to use in the EC_KEY object (note: the EC_KEY
+ * object will use an own copy of the EC_GROUP).
+ * \return 1 on success and 0 if an error occurred.
+ */
+int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group);
+
+/** Returns the private key of a EC_KEY object.
+ * \param key EC_KEY object
+ * \return a BIGNUM with the private key (possibly NULL).
+ */
+const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key);
+
+/** Sets the private key of a EC_KEY object.
+ * \param key EC_KEY object
+ * \param prv BIGNUM with the private key (note: the EC_KEY object
+ * will use an own copy of the BIGNUM).
+ * \return 1 on success and 0 if an error occurred.
+ */
+int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv);
+
+/** Returns the public key of a EC_KEY object.
+ * \param key the EC_KEY object
+ * \return a EC_POINT object with the public key (possibly NULL)
+ */
+const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key);
+
+/** Sets the public key of a EC_KEY object.
+ * \param key EC_KEY object
+ * \param pub EC_POINT object with the public key (note: the EC_KEY object
+ * will use an own copy of the EC_POINT object).
+ * \return 1 on success and 0 if an error occurred.
+ */
+int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);
+
+unsigned EC_KEY_get_enc_flags(const EC_KEY *key);
void EC_KEY_set_enc_flags(EC_KEY *, unsigned int);
point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *);
void EC_KEY_set_conv_form(EC_KEY *, point_conversion_form_t);
@@ -325,31 +810,135 @@ void EC_KEY_insert_key_method_data(EC_KEY *, void *data,
void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
/* wrapper functions for the underlying EC_GROUP object */
void EC_KEY_set_asn1_flag(EC_KEY *, int);
-int EC_KEY_precompute_mult(EC_KEY *, BN_CTX *ctx);
-
-/* EC_KEY_generate_key() creates a ec private (public) key */
-int EC_KEY_generate_key(EC_KEY *);
-/* EC_KEY_check_key() */
-int EC_KEY_check_key(const EC_KEY *);
-
-/* de- and encoding functions for SEC1 ECPrivateKey */
-EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len);
-int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out);
-/* de- and encoding functions for EC parameters */
-EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len);
-int i2d_ECParameters(EC_KEY *a, unsigned char **out);
-/* de- and encoding functions for EC public key
- * (octet string, not DER -- hence 'o2i' and 'i2o') */
-EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len);
-int i2o_ECPublicKey(EC_KEY *a, unsigned char **out);
+
+/** Creates a table of pre-computed multiples of the generator to
+ * accelerate further EC_KEY operations.
+ * \param key EC_KEY object
+ * \param ctx BN_CTX object (optional)
+ * \return 1 on success and 0 if an error occurred.
+ */
+int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx);
+
+/** Creates a new ec private (and optional a new public) key.
+ * \param key EC_KEY object
+ * \return 1 on success and 0 if an error occurred.
+ */
+int EC_KEY_generate_key(EC_KEY *key);
+
+/** Verifies that a private and/or public key is valid.
+ * \param key the EC_KEY object
+ * \return 1 on success and 0 otherwise.
+ */
+int EC_KEY_check_key(const EC_KEY *key);
+
+/** Sets a public key from affine coordindates performing
+ * neccessary NIST PKV tests.
+ * \param key the EC_KEY object
+ * \param x public key x coordinate
+ * \param y public key y coordinate
+ * \return 1 on success and 0 otherwise.
+ */
+int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y);
+
+
+/********************************************************************/
+/* de- and encoding functions for SEC1 ECPrivateKey */
+/********************************************************************/
+
+/** Decodes a private key from a memory buffer.
+ * \param key a pointer to a EC_KEY object which should be used (or NULL)
+ * \param in pointer to memory with the DER encoded private key
+ * \param len length of the DER encoded private key
+ * \return the decoded private key or NULL if an error occurred.
+ */
+EC_KEY *d2i_ECPrivateKey(EC_KEY **key, const unsigned char **in, long len);
+
+/** Encodes a private key object and stores the result in a buffer.
+ * \param key the EC_KEY object to encode
+ * \param out the buffer for the result (if NULL the function returns number
+ * of bytes needed).
+ * \return 1 on success and 0 if an error occurred.
+ */
+int i2d_ECPrivateKey(EC_KEY *key, unsigned char **out);
+
+
+/********************************************************************/
+/* de- and encoding functions for EC parameters */
+/********************************************************************/
+
+/** Decodes ec parameter from a memory buffer.
+ * \param key a pointer to a EC_KEY object which should be used (or NULL)
+ * \param in pointer to memory with the DER encoded ec parameters
+ * \param len length of the DER encoded ec parameters
+ * \return a EC_KEY object with the decoded parameters or NULL if an error
+ * occurred.
+ */
+EC_KEY *d2i_ECParameters(EC_KEY **key, const unsigned char **in, long len);
+
+/** Encodes ec parameter and stores the result in a buffer.
+ * \param key the EC_KEY object with ec paramters to encode
+ * \param out the buffer for the result (if NULL the function returns number
+ * of bytes needed).
+ * \return 1 on success and 0 if an error occurred.
+ */
+int i2d_ECParameters(EC_KEY *key, unsigned char **out);
+
+
+/********************************************************************/
+/* de- and encoding functions for EC public key */
+/* (octet string, not DER -- hence 'o2i' and 'i2o') */
+/********************************************************************/
+
+/** Decodes a ec public key from a octet string.
+ * \param key a pointer to a EC_KEY object which should be used
+ * \param in memory buffer with the encoded public key
+ * \param len length of the encoded public key
+ * \return EC_KEY object with decoded public key or NULL if an error
+ * occurred.
+ */
+EC_KEY *o2i_ECPublicKey(EC_KEY **key, const unsigned char **in, long len);
+
+/** Encodes a ec public key in an octet string.
+ * \param key the EC_KEY object with the public key
+ * \param out the buffer for the result (if NULL the function returns number
+ * of bytes needed).
+ * \return 1 on success and 0 if an error occurred
+ */
+int i2o_ECPublicKey(EC_KEY *key, unsigned char **out);
#ifndef OPENSSL_NO_BIO
-int ECParameters_print(BIO *bp, const EC_KEY *x);
-int EC_KEY_print(BIO *bp, const EC_KEY *x, int off);
+/** Prints out the ec parameters on human readable form.
+ * \param bp BIO object to which the information is printed
+ * \param key EC_KEY object
+ * \return 1 on success and 0 if an error occurred
+ */
+int ECParameters_print(BIO *bp, const EC_KEY *key);
+
+/** Prints out the contents of a EC_KEY object
+ * \param bp BIO object to which the information is printed
+ * \param key EC_KEY object
+ * \param off line offset
+ * \return 1 on success and 0 if an error occurred
+ */
+int EC_KEY_print(BIO *bp, const EC_KEY *key, int off);
+
#endif
#ifndef OPENSSL_NO_FP_API
-int ECParameters_print_fp(FILE *fp, const EC_KEY *x);
-int EC_KEY_print_fp(FILE *fp, const EC_KEY *x, int off);
+/** Prints out the ec parameters on human readable form.
+ * \param fp file descriptor to which the information is printed
+ * \param key EC_KEY object
+ * \return 1 on success and 0 if an error occurred
+ */
+int ECParameters_print_fp(FILE *fp, const EC_KEY *key);
+
+/** Prints out the contents of a EC_KEY object
+ * \param fp file descriptor to which the information is printed
+ * \param key EC_KEY object
+ * \param off line offset
+ * \return 1 on success and 0 if an error occurred
+ */
+int EC_KEY_print_fp(FILE *fp, const EC_KEY *key, int off);
+
#endif
#define ECParameters_dup(x) ASN1_dup_of(EC_KEY,i2d_ECParameters,d2i_ECParameters,x)
@@ -362,6 +951,13 @@ int EC_KEY_print_fp(FILE *fp, const EC_KEY *x, int off);
# endif
#endif
+#define EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) \
+ EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, EVP_PKEY_OP_PARAMGEN, \
+ EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID, nid, NULL)
+
+
+#define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID (EVP_PKEY_ALG_CTRL + 1)
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -371,10 +967,19 @@ void ERR_load_EC_strings(void);
/* Error codes for the EC functions. */
/* Function codes. */
+#define EC_F_BN_TO_FELEM 224
#define EC_F_COMPUTE_WNAF 143
#define EC_F_D2I_ECPARAMETERS 144
#define EC_F_D2I_ECPKPARAMETERS 145
#define EC_F_D2I_ECPRIVATEKEY 146
+#define EC_F_DO_EC_KEY_PRINT 221
+#define EC_F_ECKEY_PARAM2TYPE 223
+#define EC_F_ECKEY_PARAM_DECODE 212
+#define EC_F_ECKEY_PRIV_DECODE 213
+#define EC_F_ECKEY_PRIV_ENCODE 214
+#define EC_F_ECKEY_PUB_DECODE 215
+#define EC_F_ECKEY_PUB_ENCODE 216
+#define EC_F_ECKEY_TYPE2PARAM 220
#define EC_F_ECPARAMETERS_PRINT 147
#define EC_F_ECPARAMETERS_PRINT_FP 148
#define EC_F_ECPKPARAMETERS_PRINT 149
@@ -405,6 +1010,15 @@ void ERR_load_EC_strings(void);
#define EC_F_EC_GFP_MONT_FIELD_SQR 132
#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE 189
#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE_GFP 135
+#define EC_F_EC_GFP_NISTP224_GROUP_SET_CURVE 225
+#define EC_F_EC_GFP_NISTP224_POINTS_MUL 228
+#define EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES 226
+#define EC_F_EC_GFP_NISTP256_GROUP_SET_CURVE 230
+#define EC_F_EC_GFP_NISTP256_POINTS_MUL 231
+#define EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES 232
+#define EC_F_EC_GFP_NISTP521_GROUP_SET_CURVE 233
+#define EC_F_EC_GFP_NISTP521_POINTS_MUL 234
+#define EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES 235
#define EC_F_EC_GFP_NIST_FIELD_MUL 200
#define EC_F_EC_GFP_NIST_FIELD_SQR 201
#define EC_F_EC_GFP_NIST_GROUP_SET_CURVE 202
@@ -447,8 +1061,8 @@ void ERR_load_EC_strings(void);
#define EC_F_EC_KEY_NEW 182
#define EC_F_EC_KEY_PRINT 180
#define EC_F_EC_KEY_PRINT_FP 181
+#define EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES 229
#define EC_F_EC_POINTS_MAKE_AFFINE 136
-#define EC_F_EC_POINTS_MUL 138
#define EC_F_EC_POINT_ADD 112
#define EC_F_EC_POINT_CMP 113
#define EC_F_EC_POINT_COPY 114
@@ -478,22 +1092,38 @@ void ERR_load_EC_strings(void);
#define EC_F_I2D_ECPKPARAMETERS 191
#define EC_F_I2D_ECPRIVATEKEY 192
#define EC_F_I2O_ECPUBLICKEY 151
+#define EC_F_NISTP224_PRE_COMP_NEW 227
+#define EC_F_NISTP256_PRE_COMP_NEW 236
+#define EC_F_NISTP521_PRE_COMP_NEW 237
#define EC_F_O2I_ECPUBLICKEY 152
+#define EC_F_OLD_EC_PRIV_DECODE 222
+#define EC_F_PKEY_EC_CTRL 197
+#define EC_F_PKEY_EC_CTRL_STR 198
+#define EC_F_PKEY_EC_DERIVE 217
+#define EC_F_PKEY_EC_KEYGEN 199
+#define EC_F_PKEY_EC_PARAMGEN 219
+#define EC_F_PKEY_EC_SIGN 218
/* Reason codes. */
#define EC_R_ASN1_ERROR 115
#define EC_R_ASN1_UNKNOWN_FIELD 116
+#define EC_R_BIGNUM_OUT_OF_RANGE 144
#define EC_R_BUFFER_TOO_SMALL 100
+#define EC_R_COORDINATES_OUT_OF_RANGE 146
#define EC_R_D2I_ECPKPARAMETERS_FAILURE 117
+#define EC_R_DECODE_ERROR 142
#define EC_R_DISCRIMINANT_IS_ZERO 118
#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 119
-#define EC_R_FIELD_TOO_LARGE 138
+#define EC_R_FIELD_TOO_LARGE 143
+#define EC_R_GF2M_NOT_SUPPORTED 147
#define EC_R_GROUP2PKPARAMETERS_FAILURE 120
#define EC_R_I2D_ECPKPARAMETERS_FAILURE 121
#define EC_R_INCOMPATIBLE_OBJECTS 101
#define EC_R_INVALID_ARGUMENT 112
#define EC_R_INVALID_COMPRESSED_POINT 110
#define EC_R_INVALID_COMPRESSION_BIT 109
+#define EC_R_INVALID_CURVE 141
+#define EC_R_INVALID_DIGEST_TYPE 138
#define EC_R_INVALID_ENCODING 102
#define EC_R_INVALID_FIELD 103
#define EC_R_INVALID_FORM 104
@@ -501,6 +1131,7 @@ void ERR_load_EC_strings(void);
#define EC_R_INVALID_PENTANOMIAL_BASIS 132
#define EC_R_INVALID_PRIVATE_KEY 123
#define EC_R_INVALID_TRINOMIAL_BASIS 137
+#define EC_R_KEYS_NOT_SET 140
#define EC_R_MISSING_PARAMETERS 124
#define EC_R_MISSING_PRIVATE_KEY 125
#define EC_R_NOT_A_NIST_PRIME 135
@@ -508,6 +1139,7 @@ void ERR_load_EC_strings(void);
#define EC_R_NOT_IMPLEMENTED 126
#define EC_R_NOT_INITIALIZED 111
#define EC_R_NO_FIELD_MOD 133
+#define EC_R_NO_PARAMETERS_SET 139
#define EC_R_PASSED_NULL_PARAMETER 134
#define EC_R_PKPARAMETERS2GROUP_FAILURE 127
#define EC_R_POINT_AT_INFINITY 106
@@ -518,6 +1150,7 @@ void ERR_load_EC_strings(void);
#define EC_R_UNKNOWN_GROUP 129
#define EC_R_UNKNOWN_ORDER 114
#define EC_R_UNSUPPORTED_FIELD 131
+#define EC_R_WRONG_CURVE_PARAMETERS 145
#define EC_R_WRONG_ORDER 130
#ifdef __cplusplus
diff --git a/crypto/ec/ec2_mult.c b/crypto/ec/ec2_mult.c
index 7dca5e4bcd436..26f4a783fcc1e 100644
--- a/crypto/ec/ec2_mult.c
+++ b/crypto/ec/ec2_mult.c
@@ -71,12 +71,14 @@
#include "ec_lcl.h"
+#ifndef OPENSSL_NO_EC2M
+
/* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery projective
* coordinates.
* Uses algorithm Mdouble in appendix of
* Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over
- * GF(2^m) without precomputation".
+ * GF(2^m) without precomputation" (CHES '99, LNCS 1717).
* modified to not require precomputation of c=b^{2^{m-1}}.
*/
static int gf2m_Mdouble(const EC_GROUP *group, BIGNUM *x, BIGNUM *z, BN_CTX *ctx)
@@ -107,8 +109,8 @@ static int gf2m_Mdouble(const EC_GROUP *group, BIGNUM *x, BIGNUM *z, BN_CTX *ctx
/* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in Montgomery
* projective coordinates.
* Uses algorithm Madd in appendix of
- * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
- * GF(2^m) without precomputation".
+ * Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over
+ * GF(2^m) without precomputation" (CHES '99, LNCS 1717).
*/
static int gf2m_Madd(const EC_GROUP *group, const BIGNUM *x, BIGNUM *x1, BIGNUM *z1,
const BIGNUM *x2, const BIGNUM *z2, BN_CTX *ctx)
@@ -140,8 +142,8 @@ static int gf2m_Madd(const EC_GROUP *group, const BIGNUM *x, BIGNUM *x1, BIGNUM
/* Compute the x, y affine coordinates from the point (x1, z1) (x2, z2)
* using Montgomery point multiplication algorithm Mxy() in appendix of
- * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
- * GF(2^m) without precomputation".
+ * Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over
+ * GF(2^m) without precomputation" (CHES '99, LNCS 1717).
* Returns:
* 0 on error
* 1 if return value should be the point at infinity
@@ -209,15 +211,15 @@ static int gf2m_Mxy(const EC_GROUP *group, const BIGNUM *x, const BIGNUM *y, BIG
/* Computes scalar*point and stores the result in r.
* point can not equal r.
* Uses algorithm 2P of
- * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
- * GF(2^m) without precomputation".
+ * Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over
+ * GF(2^m) without precomputation" (CHES '99, LNCS 1717).
*/
static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
const EC_POINT *point, BN_CTX *ctx)
{
BIGNUM *x1, *x2, *z1, *z2;
- int ret = 0, i, j;
- BN_ULONG mask;
+ int ret = 0, i;
+ BN_ULONG mask,word;
if (r == point)
{
@@ -251,22 +253,24 @@ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r,
if (!BN_GF2m_add(x2, x2, &group->b)) goto err; /* x2 = x^4 + b */
/* find top most bit and go one past it */
- i = scalar->top - 1; j = BN_BITS2 - 1;
+ i = scalar->top - 1;
mask = BN_TBIT;
- while (!(scalar->d[i] & mask)) { mask >>= 1; j--; }
- mask >>= 1; j--;
+ word = scalar->d[i];
+ while (!(word & mask)) mask >>= 1;
+ mask >>= 1;
/* if top most bit was at word break, go to next word */
if (!mask)
{
- i--; j = BN_BITS2 - 1;
+ i--;
mask = BN_TBIT;
}
for (; i >= 0; i--)
{
- for (; j >= 0; j--)
+ word = scalar->d[i];
+ while (mask)
{
- if (scalar->d[i] & mask)
+ if (word & mask)
{
if (!gf2m_Madd(group, &point->X, x1, z1, x2, z2, ctx)) goto err;
if (!gf2m_Mdouble(group, x2, z2, ctx)) goto err;
@@ -278,7 +282,6 @@ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r,
}
mask >>= 1;
}
- j = BN_BITS2 - 1;
mask = BN_TBIT;
}
@@ -383,3 +386,5 @@ int ec_GF2m_have_precompute_mult(const EC_GROUP *group)
{
return ec_wNAF_have_precompute_mult(group);
}
+
+#endif
diff --git a/crypto/ec/ec2_oct.c b/crypto/ec/ec2_oct.c
new file mode 100644
index 0000000000000..f1d75e5ddf66a
--- /dev/null
+++ b/crypto/ec/ec2_oct.c
@@ -0,0 +1,407 @@
+/* crypto/ec/ec2_oct.c */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
+ * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
+ * to the OpenSSL project.
+ *
+ * The ECC Code is licensed pursuant to the OpenSSL open source
+ * license provided below.
+ *
+ * The software is originally written by Sheueling Chang Shantz and
+ * Douglas Stebila of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <openssl/err.h>
+
+#include "ec_lcl.h"
+
+#ifndef OPENSSL_NO_EC2M
+
+/* Calculates and sets the affine coordinates of an EC_POINT from the given
+ * compressed coordinates. Uses algorithm 2.3.4 of SEC 1.
+ * Note that the simple implementation only uses affine coordinates.
+ *
+ * The method is from the following publication:
+ *
+ * Harper, Menezes, Vanstone:
+ * "Public-Key Cryptosystems with Very Small Key Lengths",
+ * EUROCRYPT '92, Springer-Verlag LNCS 658,
+ * published February 1993
+ *
+ * US Patents 6,141,420 and 6,618,483 (Vanstone, Mullin, Agnew) describe
+ * the same method, but claim no priority date earlier than July 29, 1994
+ * (and additionally fail to cite the EUROCRYPT '92 publication as prior art).
+ */
+int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point,
+ const BIGNUM *x_, int y_bit, BN_CTX *ctx)
+ {
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *tmp, *x, *y, *z;
+ int ret = 0, z0;
+
+ /* clear error queue */
+ ERR_clear_error();
+
+ if (ctx == NULL)
+ {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ y_bit = (y_bit != 0) ? 1 : 0;
+
+ BN_CTX_start(ctx);
+ tmp = BN_CTX_get(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ z = BN_CTX_get(ctx);
+ if (z == NULL) goto err;
+
+ if (!BN_GF2m_mod_arr(x, x_, group->poly)) goto err;
+ if (BN_is_zero(x))
+ {
+ if (!BN_GF2m_mod_sqrt_arr(y, &group->b, group->poly, ctx)) goto err;
+ }
+ else
+ {
+ if (!group->meth->field_sqr(group, tmp, x, ctx)) goto err;
+ if (!group->meth->field_div(group, tmp, &group->b, tmp, ctx)) goto err;
+ if (!BN_GF2m_add(tmp, &group->a, tmp)) goto err;
+ if (!BN_GF2m_add(tmp, x, tmp)) goto err;
+ if (!BN_GF2m_mod_solve_quad_arr(z, tmp, group->poly, ctx))
+ {
+ unsigned long err = ERR_peek_last_error();
+
+ if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NO_SOLUTION)
+ {
+ ERR_clear_error();
+ ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
+ }
+ else
+ ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB);
+ goto err;
+ }
+ z0 = (BN_is_odd(z)) ? 1 : 0;
+ if (!group->meth->field_mul(group, y, x, z, ctx)) goto err;
+ if (z0 != y_bit)
+ {
+ if (!BN_GF2m_add(y, y, x)) goto err;
+ }
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err;
+
+ ret = 1;
+
+ err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+ }
+
+
+/* Converts an EC_POINT to an octet string.
+ * If buf is NULL, the encoded length will be returned.
+ * If the length len of buf is smaller than required an error will be returned.
+ */
+size_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
+ unsigned char *buf, size_t len, BN_CTX *ctx)
+ {
+ size_t ret;
+ BN_CTX *new_ctx = NULL;
+ int used_ctx = 0;
+ BIGNUM *x, *y, *yxi;
+ size_t field_len, i, skip;
+
+ if ((form != POINT_CONVERSION_COMPRESSED)
+ && (form != POINT_CONVERSION_UNCOMPRESSED)
+ && (form != POINT_CONVERSION_HYBRID))
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
+ goto err;
+ }
+
+ if (EC_POINT_is_at_infinity(group, point))
+ {
+ /* encodes to a single 0 octet */
+ if (buf != NULL)
+ {
+ if (len < 1)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ buf[0] = 0;
+ }
+ return 1;
+ }
+
+
+ /* ret := required output buffer length */
+ field_len = (EC_GROUP_get_degree(group) + 7) / 8;
+ ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
+
+ /* if 'buf' is NULL, just return required length */
+ if (buf != NULL)
+ {
+ if (len < ret)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
+ goto err;
+ }
+
+ if (ctx == NULL)
+ {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ used_ctx = 1;
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ yxi = BN_CTX_get(ctx);
+ if (yxi == NULL) goto err;
+
+ if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err;
+
+ buf[0] = form;
+ if ((form != POINT_CONVERSION_UNCOMPRESSED) && !BN_is_zero(x))
+ {
+ if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err;
+ if (BN_is_odd(yxi)) buf[0]++;
+ }
+
+ i = 1;
+
+ skip = field_len - BN_num_bytes(x);
+ if (skip > field_len)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ while (skip > 0)
+ {
+ buf[i++] = 0;
+ skip--;
+ }
+ skip = BN_bn2bin(x, buf + i);
+ i += skip;
+ if (i != 1 + field_len)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID)
+ {
+ skip = field_len - BN_num_bytes(y);
+ if (skip > field_len)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ while (skip > 0)
+ {
+ buf[i++] = 0;
+ skip--;
+ }
+ skip = BN_bn2bin(y, buf + i);
+ i += skip;
+ }
+
+ if (i != ret)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (used_ctx)
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+
+ err:
+ if (used_ctx)
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return 0;
+ }
+
+
+/* Converts an octet string representation to an EC_POINT.
+ * Note that the simple implementation only uses affine coordinates.
+ */
+int ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
+ const unsigned char *buf, size_t len, BN_CTX *ctx)
+ {
+ point_conversion_form_t form;
+ int y_bit;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y, *yxi;
+ size_t field_len, enc_len;
+ int ret = 0;
+
+ if (len == 0)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ form = buf[0];
+ y_bit = form & 1;
+ form = form & ~1U;
+ if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
+ && (form != POINT_CONVERSION_UNCOMPRESSED)
+ && (form != POINT_CONVERSION_HYBRID))
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+ if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+
+ if (form == 0)
+ {
+ if (len != 1)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+
+ return EC_POINT_set_to_infinity(group, point);
+ }
+
+ field_len = (EC_GROUP_get_degree(group) + 7) / 8;
+ enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
+
+ if (len != enc_len)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+
+ if (ctx == NULL)
+ {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ yxi = BN_CTX_get(ctx);
+ if (yxi == NULL) goto err;
+
+ if (!BN_bin2bn(buf + 1, field_len, x)) goto err;
+ if (BN_ucmp(x, &group->field) >= 0)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+
+ if (form == POINT_CONVERSION_COMPRESSED)
+ {
+ if (!EC_POINT_set_compressed_coordinates_GF2m(group, point, x, y_bit, ctx)) goto err;
+ }
+ else
+ {
+ if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err;
+ if (BN_ucmp(y, &group->field) >= 0)
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+ if (form == POINT_CONVERSION_HYBRID)
+ {
+ if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err;
+ if (y_bit != BN_is_odd(yxi))
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err;
+ }
+
+ if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */
+ {
+ ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE);
+ goto err;
+ }
+
+ ret = 1;
+
+ err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+ }
+#endif
diff --git a/crypto/ec/ec2_smpl.c b/crypto/ec/ec2_smpl.c
index c06b3b667f0bf..e0e59c7d8299b 100644
--- a/crypto/ec/ec2_smpl.c
+++ b/crypto/ec/ec2_smpl.c
@@ -14,7 +14,7 @@
*
*/
/* ====================================================================
- * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -71,10 +71,20 @@
#include "ec_lcl.h"
+#ifndef OPENSSL_NO_EC2M
+
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
+
const EC_METHOD *EC_GF2m_simple_method(void)
{
+#ifdef OPENSSL_FIPS
+ return fips_ec_gf2m_simple_method();
+#else
static const EC_METHOD ret = {
+ EC_FLAGS_DEFAULT_OCT,
NID_X9_62_characteristic_two_field,
ec_GF2m_simple_group_init,
ec_GF2m_simple_group_finish,
@@ -93,9 +103,7 @@ const EC_METHOD *EC_GF2m_simple_method(void)
0 /* get_Jprojective_coordinates_GFp */,
ec_GF2m_simple_point_set_affine_coordinates,
ec_GF2m_simple_point_get_affine_coordinates,
- ec_GF2m_simple_set_compressed_coordinates,
- ec_GF2m_simple_point2oct,
- ec_GF2m_simple_oct2point,
+ 0,0,0,
ec_GF2m_simple_add,
ec_GF2m_simple_dbl,
ec_GF2m_simple_invert,
@@ -118,6 +126,7 @@ const EC_METHOD *EC_GF2m_simple_method(void)
0 /* field_set_to_one */ };
return &ret;
+#endif
}
@@ -157,6 +166,7 @@ void ec_GF2m_simple_group_clear_finish(EC_GROUP *group)
group->poly[2] = 0;
group->poly[3] = 0;
group->poly[4] = 0;
+ group->poly[5] = -1;
}
@@ -174,10 +184,9 @@ int ec_GF2m_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
dest->poly[2] = src->poly[2];
dest->poly[3] = src->poly[3];
dest->poly[4] = src->poly[4];
- if(bn_wexpand(&dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) == NULL)
- return 0;
- if(bn_wexpand(&dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) == NULL)
- return 0;
+ dest->poly[5] = src->poly[5];
+ if (bn_wexpand(&dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) == NULL) return 0;
+ if (bn_wexpand(&dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) == NULL) return 0;
for (i = dest->a.top; i < dest->a.dmax; i++) dest->a.d[i] = 0;
for (i = dest->b.top; i < dest->b.dmax; i++) dest->b.d[i] = 0;
return 1;
@@ -192,7 +201,7 @@ int ec_GF2m_simple_group_set_curve(EC_GROUP *group,
/* group->field */
if (!BN_copy(&group->field, p)) goto err;
- i = BN_GF2m_poly2arr(&group->field, group->poly, 5);
+ i = BN_GF2m_poly2arr(&group->field, group->poly, 6) - 1;
if ((i != 5) && (i != 3))
{
ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE, EC_R_UNSUPPORTED_FIELD);
@@ -405,274 +414,6 @@ int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_
return ret;
}
-
-/* Include patented algorithms. */
-#include "ec2_smpt.c"
-
-
-/* Converts an EC_POINT to an octet string.
- * If buf is NULL, the encoded length will be returned.
- * If the length len of buf is smaller than required an error will be returned.
- *
- * The point compression section of this function is patented by Certicom Corp.
- * under US Patent 6,141,420. Point compression is disabled by default and can
- * be enabled by defining the preprocessor macro OPENSSL_EC_BIN_PT_COMP at
- * Configure-time.
- */
-size_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *ctx)
- {
- size_t ret;
- BN_CTX *new_ctx = NULL;
- int used_ctx = 0;
- BIGNUM *x, *y, *yxi;
- size_t field_len, i, skip;
-
-#ifndef OPENSSL_EC_BIN_PT_COMP
- if ((form == POINT_CONVERSION_COMPRESSED) || (form == POINT_CONVERSION_HYBRID))
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_DISABLED);
- goto err;
- }
-#endif
-
- if ((form != POINT_CONVERSION_COMPRESSED)
- && (form != POINT_CONVERSION_UNCOMPRESSED)
- && (form != POINT_CONVERSION_HYBRID))
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
- goto err;
- }
-
- if (EC_POINT_is_at_infinity(group, point))
- {
- /* encodes to a single 0 octet */
- if (buf != NULL)
- {
- if (len < 1)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
- return 0;
- }
- buf[0] = 0;
- }
- return 1;
- }
-
-
- /* ret := required output buffer length */
- field_len = (EC_GROUP_get_degree(group) + 7) / 8;
- ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
-
- /* if 'buf' is NULL, just return required length */
- if (buf != NULL)
- {
- if (len < ret)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
- goto err;
- }
-
- if (ctx == NULL)
- {
- ctx = new_ctx = BN_CTX_new();
- if (ctx == NULL)
- return 0;
- }
-
- BN_CTX_start(ctx);
- used_ctx = 1;
- x = BN_CTX_get(ctx);
- y = BN_CTX_get(ctx);
- yxi = BN_CTX_get(ctx);
- if (yxi == NULL) goto err;
-
- if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err;
-
- buf[0] = form;
-#ifdef OPENSSL_EC_BIN_PT_COMP
- if ((form != POINT_CONVERSION_UNCOMPRESSED) && !BN_is_zero(x))
- {
- if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err;
- if (BN_is_odd(yxi)) buf[0]++;
- }
-#endif
-
- i = 1;
-
- skip = field_len - BN_num_bytes(x);
- if (skip > field_len)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- while (skip > 0)
- {
- buf[i++] = 0;
- skip--;
- }
- skip = BN_bn2bin(x, buf + i);
- i += skip;
- if (i != 1 + field_len)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID)
- {
- skip = field_len - BN_num_bytes(y);
- if (skip > field_len)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- while (skip > 0)
- {
- buf[i++] = 0;
- skip--;
- }
- skip = BN_bn2bin(y, buf + i);
- i += skip;
- }
-
- if (i != ret)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- }
-
- if (used_ctx)
- BN_CTX_end(ctx);
- if (new_ctx != NULL)
- BN_CTX_free(new_ctx);
- return ret;
-
- err:
- if (used_ctx)
- BN_CTX_end(ctx);
- if (new_ctx != NULL)
- BN_CTX_free(new_ctx);
- return 0;
- }
-
-
-/* Converts an octet string representation to an EC_POINT.
- * Note that the simple implementation only uses affine coordinates.
- */
-int ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
- const unsigned char *buf, size_t len, BN_CTX *ctx)
- {
- point_conversion_form_t form;
- int y_bit;
- BN_CTX *new_ctx = NULL;
- BIGNUM *x, *y, *yxi;
- size_t field_len, enc_len;
- int ret = 0;
-
- if (len == 0)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
- return 0;
- }
- form = buf[0];
- y_bit = form & 1;
- form = form & ~1U;
- if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
- && (form != POINT_CONVERSION_UNCOMPRESSED)
- && (form != POINT_CONVERSION_HYBRID))
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- return 0;
- }
- if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- return 0;
- }
-
- if (form == 0)
- {
- if (len != 1)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- return 0;
- }
-
- return EC_POINT_set_to_infinity(group, point);
- }
-
- field_len = (EC_GROUP_get_degree(group) + 7) / 8;
- enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
-
- if (len != enc_len)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- return 0;
- }
-
- if (ctx == NULL)
- {
- ctx = new_ctx = BN_CTX_new();
- if (ctx == NULL)
- return 0;
- }
-
- BN_CTX_start(ctx);
- x = BN_CTX_get(ctx);
- y = BN_CTX_get(ctx);
- yxi = BN_CTX_get(ctx);
- if (yxi == NULL) goto err;
-
- if (!BN_bin2bn(buf + 1, field_len, x)) goto err;
- if (BN_ucmp(x, &group->field) >= 0)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- goto err;
- }
-
- if (form == POINT_CONVERSION_COMPRESSED)
- {
- if (!EC_POINT_set_compressed_coordinates_GF2m(group, point, x, y_bit, ctx)) goto err;
- }
- else
- {
- if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err;
- if (BN_ucmp(y, &group->field) >= 0)
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- goto err;
- }
- if (form == POINT_CONVERSION_HYBRID)
- {
- if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err;
- if (y_bit != BN_is_odd(yxi))
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- goto err;
- }
- }
-
- if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err;
- }
-
- if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */
- {
- ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE);
- goto err;
- }
-
- ret = 1;
-
- err:
- BN_CTX_end(ctx);
- if (new_ctx != NULL)
- BN_CTX_free(new_ctx);
- return ret;
- }
-
-
/* Computes a + b and stores the result in r. r could be a or b, a could be b.
* Uses algorithm A.10.2 of IEEE P1363.
*/
@@ -974,3 +715,5 @@ int ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
{
return BN_GF2m_mod_div(r, a, b, &group->field, ctx);
}
+
+#endif
diff --git a/crypto/ec/ec2_smpt.c b/crypto/ec/ec2_smpt.c
deleted file mode 100644
index 72a8d570517f3..0000000000000
--- a/crypto/ec/ec2_smpt.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* crypto/ec/ec2_smpt.c */
-/* This code was originally written by Douglas Stebila
- * <dstebila@student.math.uwaterloo.ca> for the OpenSSL project.
- */
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-
-/* Calaculates and sets the affine coordinates of an EC_POINT from the given
- * compressed coordinates. Uses algorithm 2.3.4 of SEC 1.
- * Note that the simple implementation only uses affine coordinates.
- *
- * This algorithm is patented by Certicom Corp. under US Patent 6,141,420
- * (for licensing information, contact licensing@certicom.com).
- * This function is disabled by default and can be enabled by defining the
- * preprocessor macro OPENSSL_EC_BIN_PT_COMP at Configure-time.
- */
-int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point,
- const BIGNUM *x_, int y_bit, BN_CTX *ctx)
- {
-#ifndef OPENSSL_EC_BIN_PT_COMP
- ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_DISABLED);
- return 0;
-#else
- BN_CTX *new_ctx = NULL;
- BIGNUM *tmp, *x, *y, *z;
- int ret = 0, z0;
-
- /* clear error queue */
- ERR_clear_error();
-
- if (ctx == NULL)
- {
- ctx = new_ctx = BN_CTX_new();
- if (ctx == NULL)
- return 0;
- }
-
- y_bit = (y_bit != 0) ? 1 : 0;
-
- BN_CTX_start(ctx);
- tmp = BN_CTX_get(ctx);
- x = BN_CTX_get(ctx);
- y = BN_CTX_get(ctx);
- z = BN_CTX_get(ctx);
- if (z == NULL) goto err;
-
- if (!BN_GF2m_mod_arr(x, x_, group->poly)) goto err;
- if (BN_is_zero(x))
- {
- if (!BN_GF2m_mod_sqrt_arr(y, &group->b, group->poly, ctx)) goto err;
- }
- else
- {
- if (!group->meth->field_sqr(group, tmp, x, ctx)) goto err;
- if (!group->meth->field_div(group, tmp, &group->b, tmp, ctx)) goto err;
- if (!BN_GF2m_add(tmp, &group->a, tmp)) goto err;
- if (!BN_GF2m_add(tmp, x, tmp)) goto err;
- if (!BN_GF2m_mod_solve_quad_arr(z, tmp, group->poly, ctx))
- {
- unsigned long err = ERR_peek_last_error();
-
- if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NO_SOLUTION)
- {
- ERR_clear_error();
- ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
- }
- else
- ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB);
- goto err;
- }
- z0 = (BN_is_odd(z)) ? 1 : 0;
- if (!group->meth->field_mul(group, y, x, z, ctx)) goto err;
- if (z0 != y_bit)
- {
- if (!BN_GF2m_add(y, y, x)) goto err;
- }
- }
-
- if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err;
-
- ret = 1;
-
- err:
- BN_CTX_end(ctx);
- if (new_ctx != NULL)
- BN_CTX_free(new_ctx);
- return ret;
-#endif
- }
diff --git a/crypto/ec/ec_ameth.c b/crypto/ec/ec_ameth.c
new file mode 100644
index 0000000000000..83909c185359a
--- /dev/null
+++ b/crypto/ec/ec_ameth.c
@@ -0,0 +1,660 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/x509.h>
+#include <openssl/ec.h>
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_CMS
+#include <openssl/cms.h>
+#endif
+#include "asn1_locl.h"
+
+static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key)
+ {
+ const EC_GROUP *group;
+ int nid;
+ if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL)
+ {
+ ECerr(EC_F_ECKEY_PARAM2TYPE, EC_R_MISSING_PARAMETERS);
+ return 0;
+ }
+ if (EC_GROUP_get_asn1_flag(group)
+ && (nid = EC_GROUP_get_curve_name(group)))
+ /* we have a 'named curve' => just set the OID */
+ {
+ *ppval = OBJ_nid2obj(nid);
+ *pptype = V_ASN1_OBJECT;
+ }
+ else /* explicit parameters */
+ {
+ ASN1_STRING *pstr = NULL;
+ pstr = ASN1_STRING_new();
+ if (!pstr)
+ return 0;
+ pstr->length = i2d_ECParameters(ec_key, &pstr->data);
+ if (pstr->length < 0)
+ {
+ ASN1_STRING_free(pstr);
+ ECerr(EC_F_ECKEY_PARAM2TYPE, ERR_R_EC_LIB);
+ return 0;
+ }
+ *ppval = pstr;
+ *pptype = V_ASN1_SEQUENCE;
+ }
+ return 1;
+ }
+
+static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
+ {
+ EC_KEY *ec_key = pkey->pkey.ec;
+ void *pval = NULL;
+ int ptype;
+ unsigned char *penc = NULL, *p;
+ int penclen;
+
+ if (!eckey_param2type(&ptype, &pval, ec_key))
+ {
+ ECerr(EC_F_ECKEY_PUB_ENCODE, ERR_R_EC_LIB);
+ return 0;
+ }
+ penclen = i2o_ECPublicKey(ec_key, NULL);
+ if (penclen <= 0)
+ goto err;
+ penc = OPENSSL_malloc(penclen);
+ if (!penc)
+ goto err;
+ p = penc;
+ penclen = i2o_ECPublicKey(ec_key, &p);
+ if (penclen <= 0)
+ goto err;
+ if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC),
+ ptype, pval, penc, penclen))
+ return 1;
+ err:
+ if (ptype == V_ASN1_OBJECT)
+ ASN1_OBJECT_free(pval);
+ else
+ ASN1_STRING_free(pval);
+ if (penc)
+ OPENSSL_free(penc);
+ return 0;
+ }
+
+static EC_KEY *eckey_type2param(int ptype, void *pval)
+ {
+ EC_KEY *eckey = NULL;
+ if (ptype == V_ASN1_SEQUENCE)
+ {
+ ASN1_STRING *pstr = pval;
+ const unsigned char *pm = NULL;
+ int pmlen;
+ pm = pstr->data;
+ pmlen = pstr->length;
+ if (!(eckey = d2i_ECParameters(NULL, &pm, pmlen)))
+ {
+ ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR);
+ goto ecerr;
+ }
+ }
+ else if (ptype == V_ASN1_OBJECT)
+ {
+ ASN1_OBJECT *poid = pval;
+ EC_GROUP *group;
+
+ /* type == V_ASN1_OBJECT => the parameters are given
+ * by an asn1 OID
+ */
+ if ((eckey = EC_KEY_new()) == NULL)
+ {
+ ECerr(EC_F_ECKEY_TYPE2PARAM, ERR_R_MALLOC_FAILURE);
+ goto ecerr;
+ }
+ group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(poid));
+ if (group == NULL)
+ goto ecerr;
+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_set_group(eckey, group) == 0)
+ goto ecerr;
+ EC_GROUP_free(group);
+ }
+ else
+ {
+ ECerr(EC_F_ECKEY_TYPE2PARAM, EC_R_DECODE_ERROR);
+ goto ecerr;
+ }
+
+ return eckey;
+
+ ecerr:
+ if (eckey)
+ EC_KEY_free(eckey);
+ return NULL;
+ }
+
+static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
+ {
+ const unsigned char *p = NULL;
+ void *pval;
+ int ptype, pklen;
+ EC_KEY *eckey = NULL;
+ X509_ALGOR *palg;
+
+ if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
+ return 0;
+ X509_ALGOR_get0(NULL, &ptype, &pval, palg);
+
+ eckey = eckey_type2param(ptype, pval);
+
+ if (!eckey)
+ {
+ ECerr(EC_F_ECKEY_PUB_DECODE, ERR_R_EC_LIB);
+ return 0;
+ }
+
+ /* We have parameters now set public key */
+ if (!o2i_ECPublicKey(&eckey, &p, pklen))
+ {
+ ECerr(EC_F_ECKEY_PUB_DECODE, EC_R_DECODE_ERROR);
+ goto ecerr;
+ }
+
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+
+ ecerr:
+ if (eckey)
+ EC_KEY_free(eckey);
+ return 0;
+ }
+
+static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
+ {
+ int r;
+ const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec);
+ const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec),
+ *pb = EC_KEY_get0_public_key(b->pkey.ec);
+ r = EC_POINT_cmp(group, pa, pb, NULL);
+ if (r == 0)
+ return 1;
+ if (r == 1)
+ return 0;
+ return -2;
+ }
+
+static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
+ {
+ const unsigned char *p = NULL;
+ void *pval;
+ int ptype, pklen;
+ EC_KEY *eckey = NULL;
+ X509_ALGOR *palg;
+
+ if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8))
+ return 0;
+ X509_ALGOR_get0(NULL, &ptype, &pval, palg);
+
+ eckey = eckey_type2param(ptype, pval);
+
+ if (!eckey)
+ goto ecliberr;
+
+ /* We have parameters now set private key */
+ if (!d2i_ECPrivateKey(&eckey, &p, pklen))
+ {
+ ECerr(EC_F_ECKEY_PRIV_DECODE, EC_R_DECODE_ERROR);
+ goto ecerr;
+ }
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(eckey) == NULL)
+ {
+ const BIGNUM *priv_key;
+ const EC_GROUP *group;
+ EC_POINT *pub_key;
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ group = EC_KEY_get0_group(eckey);
+ pub_key = EC_POINT_new(group);
+ if (pub_key == NULL)
+ {
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ goto ecliberr;
+ }
+ if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group)))
+ {
+ EC_POINT_free(pub_key);
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ goto ecliberr;
+ }
+ priv_key = EC_KEY_get0_private_key(eckey);
+ if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL))
+ {
+ EC_POINT_free(pub_key);
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ goto ecliberr;
+ }
+ if (EC_KEY_set_public_key(eckey, pub_key) == 0)
+ {
+ EC_POINT_free(pub_key);
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ goto ecliberr;
+ }
+ EC_POINT_free(pub_key);
+ }
+
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+
+ ecliberr:
+ ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB);
+ ecerr:
+ if (eckey)
+ EC_KEY_free(eckey);
+ return 0;
+ }
+
+static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
+{
+ EC_KEY *ec_key;
+ unsigned char *ep, *p;
+ int eplen, ptype;
+ void *pval;
+ unsigned int tmp_flags, old_flags;
+
+ ec_key = pkey->pkey.ec;
+
+ if (!eckey_param2type(&ptype, &pval, ec_key))
+ {
+ ECerr(EC_F_ECKEY_PRIV_ENCODE, EC_R_DECODE_ERROR);
+ return 0;
+ }
+
+ /* set the private key */
+
+ /* do not include the parameters in the SEC1 private key
+ * see PKCS#11 12.11 */
+ old_flags = EC_KEY_get_enc_flags(ec_key);
+ tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS;
+ EC_KEY_set_enc_flags(ec_key, tmp_flags);
+ eplen = i2d_ECPrivateKey(ec_key, NULL);
+ if (!eplen)
+ {
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+ ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
+ return 0;
+ }
+ ep = (unsigned char *) OPENSSL_malloc(eplen);
+ if (!ep)
+ {
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+ ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ p = ep;
+ if (!i2d_ECPrivateKey(ec_key, &p))
+ {
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+ OPENSSL_free(ep);
+ ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
+ }
+ /* restore old encoding flags */
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+
+ if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), 0,
+ ptype, pval, ep, eplen))
+ return 0;
+
+ return 1;
+}
+
+static int int_ec_size(const EVP_PKEY *pkey)
+ {
+ return ECDSA_size(pkey->pkey.ec);
+ }
+
+static int ec_bits(const EVP_PKEY *pkey)
+ {
+ BIGNUM *order = BN_new();
+ const EC_GROUP *group;
+ int ret;
+
+ if (!order)
+ {
+ ERR_clear_error();
+ return 0;
+ }
+ group = EC_KEY_get0_group(pkey->pkey.ec);
+ if (!EC_GROUP_get_order(group, order, NULL))
+ {
+ ERR_clear_error();
+ return 0;
+ }
+
+ ret = BN_num_bits(order);
+ BN_free(order);
+ return ret;
+ }
+
+static int ec_missing_parameters(const EVP_PKEY *pkey)
+ {
+ if (EC_KEY_get0_group(pkey->pkey.ec) == NULL)
+ return 1;
+ return 0;
+ }
+
+static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
+ {
+ EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec));
+ if (group == NULL)
+ return 0;
+ if (EC_KEY_set_group(to->pkey.ec, group) == 0)
+ return 0;
+ EC_GROUP_free(group);
+ return 1;
+ }
+
+static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
+ {
+ const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec),
+ *group_b = EC_KEY_get0_group(b->pkey.ec);
+ if (EC_GROUP_cmp(group_a, group_b, NULL))
+ return 0;
+ else
+ return 1;
+ }
+
+static void int_ec_free(EVP_PKEY *pkey)
+ {
+ EC_KEY_free(pkey->pkey.ec);
+ }
+
+static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype)
+ {
+ unsigned char *buffer=NULL;
+ const char *ecstr;
+ size_t buf_len=0, i;
+ int ret=0, reason=ERR_R_BIO_LIB;
+ BIGNUM *pub_key=NULL, *order=NULL;
+ BN_CTX *ctx=NULL;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ const BIGNUM *priv_key;
+
+ if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL)
+ {
+ reason = ERR_R_PASSED_NULL_PARAMETER;
+ goto err;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL)
+ {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+
+ if (ktype > 0)
+ {
+ public_key = EC_KEY_get0_public_key(x);
+ if ((pub_key = EC_POINT_point2bn(group, public_key,
+ EC_KEY_get_conv_form(x), NULL, ctx)) == NULL)
+ {
+ reason = ERR_R_EC_LIB;
+ goto err;
+ }
+ if (pub_key)
+ buf_len = (size_t)BN_num_bytes(pub_key);
+ }
+
+ if (ktype == 2)
+ {
+ priv_key = EC_KEY_get0_private_key(x);
+ if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len)
+ buf_len = i;
+ }
+ else
+ priv_key = NULL;
+
+ if (ktype > 0)
+ {
+ buf_len += 10;
+ if ((buffer = OPENSSL_malloc(buf_len)) == NULL)
+ {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ }
+ if (ktype == 2)
+ ecstr = "Private-Key";
+ else if (ktype == 1)
+ ecstr = "Public-Key";
+ else
+ ecstr = "ECDSA-Parameters";
+
+ if (!BIO_indent(bp, off, 128))
+ goto err;
+ if ((order = BN_new()) == NULL)
+ goto err;
+ if (!EC_GROUP_get_order(group, order, NULL))
+ goto err;
+ if (BIO_printf(bp, "%s: (%d bit)\n", ecstr,
+ BN_num_bits(order)) <= 0) goto err;
+
+ if ((priv_key != NULL) && !ASN1_bn_print(bp, "priv:", priv_key,
+ buffer, off))
+ goto err;
+ if ((pub_key != NULL) && !ASN1_bn_print(bp, "pub: ", pub_key,
+ buffer, off))
+ goto err;
+ if (!ECPKParameters_print(bp, group, off))
+ goto err;
+ ret=1;
+err:
+ if (!ret)
+ ECerr(EC_F_DO_EC_KEY_PRINT, reason);
+ if (pub_key)
+ BN_free(pub_key);
+ if (order)
+ BN_free(order);
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (buffer != NULL)
+ OPENSSL_free(buffer);
+ return(ret);
+ }
+
+static int eckey_param_decode(EVP_PKEY *pkey,
+ const unsigned char **pder, int derlen)
+ {
+ EC_KEY *eckey;
+ if (!(eckey = d2i_ECParameters(NULL, pder, derlen)))
+ {
+ ECerr(EC_F_ECKEY_PARAM_DECODE, ERR_R_EC_LIB);
+ return 0;
+ }
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+ }
+
+static int eckey_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
+ {
+ return i2d_ECParameters(pkey->pkey.ec, pder);
+ }
+
+static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx)
+ {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0);
+ }
+
+static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx)
+ {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1);
+ }
+
+
+static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx)
+ {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2);
+ }
+
+static int old_ec_priv_decode(EVP_PKEY *pkey,
+ const unsigned char **pder, int derlen)
+ {
+ EC_KEY *ec;
+ if (!(ec = d2i_ECPrivateKey (NULL, pder, derlen)))
+ {
+ ECerr(EC_F_OLD_EC_PRIV_DECODE, EC_R_DECODE_ERROR);
+ return 0;
+ }
+ EVP_PKEY_assign_EC_KEY(pkey, ec);
+ return 1;
+ }
+
+static int old_ec_priv_encode(const EVP_PKEY *pkey, unsigned char **pder)
+ {
+ return i2d_ECPrivateKey(pkey->pkey.ec, pder);
+ }
+
+static int ec_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
+ {
+ switch (op)
+ {
+ case ASN1_PKEY_CTRL_PKCS7_SIGN:
+ if (arg1 == 0)
+ {
+ int snid, hnid;
+ X509_ALGOR *alg1, *alg2;
+ PKCS7_SIGNER_INFO_get0_algs(arg2, NULL, &alg1, &alg2);
+ if (alg1 == NULL || alg1->algorithm == NULL)
+ return -1;
+ hnid = OBJ_obj2nid(alg1->algorithm);
+ if (hnid == NID_undef)
+ return -1;
+ if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
+ return -1;
+ X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
+ }
+ return 1;
+#ifndef OPENSSL_NO_CMS
+ case ASN1_PKEY_CTRL_CMS_SIGN:
+ if (arg1 == 0)
+ {
+ int snid, hnid;
+ X509_ALGOR *alg1, *alg2;
+ CMS_SignerInfo_get0_algs(arg2, NULL, NULL,
+ &alg1, &alg2);
+ if (alg1 == NULL || alg1->algorithm == NULL)
+ return -1;
+ hnid = OBJ_obj2nid(alg1->algorithm);
+ if (hnid == NID_undef)
+ return -1;
+ if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey)))
+ return -1;
+ X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0);
+ }
+ return 1;
+#endif
+
+ case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+ *(int *)arg2 = NID_sha1;
+ return 2;
+
+ default:
+ return -2;
+
+ }
+
+ }
+
+const EVP_PKEY_ASN1_METHOD eckey_asn1_meth =
+ {
+ EVP_PKEY_EC,
+ EVP_PKEY_EC,
+ 0,
+ "EC",
+ "OpenSSL EC algorithm",
+
+ eckey_pub_decode,
+ eckey_pub_encode,
+ eckey_pub_cmp,
+ eckey_pub_print,
+
+ eckey_priv_decode,
+ eckey_priv_encode,
+ eckey_priv_print,
+
+ int_ec_size,
+ ec_bits,
+
+ eckey_param_decode,
+ eckey_param_encode,
+ ec_missing_parameters,
+ ec_copy_parameters,
+ ec_cmp_parameters,
+ eckey_param_print,
+ 0,
+
+ int_ec_free,
+ ec_pkey_ctrl,
+ old_ec_priv_decode,
+ old_ec_priv_encode
+ };
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index ae555398594b8..175eec53428ba 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -83,7 +83,7 @@ int EC_GROUP_get_basis_type(const EC_GROUP *group)
/* everything else is currently not supported */
return 0;
}
-
+#ifndef OPENSSL_NO_EC2M
int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k)
{
if (group == NULL)
@@ -101,7 +101,6 @@ int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k)
return 1;
}
-
int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1,
unsigned int *k2, unsigned int *k3)
{
@@ -124,7 +123,7 @@ int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1,
return 1;
}
-
+#endif
/* some structures needed for the asn1 encoding */
@@ -340,6 +339,12 @@ static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
}
}
else /* nid == NID_X9_62_characteristic_two_field */
+#ifdef OPENSSL_NO_EC2M
+ {
+ ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_GF2M_NOT_SUPPORTED);
+ goto err;
+ }
+#else
{
int field_type;
X9_62_CHARACTERISTIC_TWO *char_two;
@@ -419,6 +424,7 @@ static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
}
}
}
+#endif
ok = 1;
@@ -456,6 +462,7 @@ static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve)
goto err;
}
}
+#ifndef OPENSSL_NO_EC2M
else /* nid == NID_X9_62_characteristic_two_field */
{
if (!EC_GROUP_get_curve_GF2m(group, NULL, tmp_1, tmp_2, NULL))
@@ -464,7 +471,7 @@ static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve)
goto err;
}
}
-
+#endif
len_1 = (size_t)BN_num_bytes(tmp_1);
len_2 = (size_t)BN_num_bytes(tmp_2);
@@ -775,8 +782,13 @@ static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *params)
/* get the field parameters */
tmp = OBJ_obj2nid(params->fieldID->fieldType);
-
if (tmp == NID_X9_62_characteristic_two_field)
+#ifdef OPENSSL_NO_EC2M
+ {
+ ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_GF2M_NOT_SUPPORTED);
+ goto err;
+ }
+#else
{
X9_62_CHARACTERISTIC_TWO *char_two;
@@ -862,6 +874,7 @@ static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *params)
/* create the EC_GROUP structure */
ret = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
}
+#endif
else if (tmp == NID_X9_62_prime_field)
{
/* we have a curve over a prime field */
@@ -1065,6 +1078,7 @@ EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len)
if ((group = ec_asn1_pkparameters2group(params)) == NULL)
{
ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_PKPARAMETERS2GROUP_FAILURE);
+ ECPKPARAMETERS_free(params);
return NULL;
}
diff --git a/crypto/ec/ec_curve.c b/crypto/ec/ec_curve.c
index beac20969b753..c72fb2697ca28 100644
--- a/crypto/ec/ec_curve.c
+++ b/crypto/ec/ec_curve.c
@@ -3,7 +3,7 @@
* Written by Nils Larsch for the OpenSSL project.
*/
/* ====================================================================
- * Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2010 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -72,927 +72,1694 @@
#include "ec_lcl.h"
#include <openssl/err.h>
#include <openssl/obj_mac.h>
+#include <openssl/opensslconf.h>
-typedef struct ec_curve_data_st {
- int field_type; /* either NID_X9_62_prime_field or
+typedef struct {
+ int field_type, /* either NID_X9_62_prime_field or
* NID_X9_62_characteristic_two_field */
- const char *p; /* either a prime number or a polynomial */
- const char *a;
- const char *b;
- const char *x; /* the x coordinate of the generator */
- const char *y; /* the y coordinate of the generator */
- const char *order; /* the order of the group generated by the
- * generator */
- const BN_ULONG cofactor;/* the cofactor */
- const unsigned char *seed;/* the seed (optional) */
- size_t seed_len;
- const char *comment; /* a short description of the curve */
+ seed_len,
+ param_len;
+ unsigned int cofactor; /* promoted to BN_ULONG */
} EC_CURVE_DATA;
/* the nist prime curves */
-static const unsigned char _EC_NIST_PRIME_192_SEED[] = {
- 0x30,0x45,0xAE,0x6F,0xC8,0x42,0x2F,0x64,0xED,0x57,
- 0x95,0x28,0xD3,0x81,0x20,0xEA,0xE1,0x21,0x96,0xD5};
-static const EC_CURVE_DATA _EC_NIST_PRIME_192 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
- "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
- "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
- "07192b95ffc8da78631011ed6b24cdd573f977a11e794811",
- "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",1,
- _EC_NIST_PRIME_192_SEED, 20,
- "NIST/X9.62/SECG curve over a 192 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+24*6]; }
+ _EC_NIST_PRIME_192 = {
+ { NID_X9_62_prime_field,20,24,1 },
+ { 0x30,0x45,0xAE,0x6F,0xC8,0x42,0x2F,0x64,0xED,0x57, /* seed */
+ 0x95,0x28,0xD3,0x81,0x20,0xEA,0xE1,0x21,0x96,0xD5,
+
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFC,
+ 0x64,0x21,0x05,0x19,0xE5,0x9C,0x80,0xE7,0x0F,0xA7, /* b */
+ 0xE9,0xAB,0x72,0x24,0x30,0x49,0xFE,0xB8,0xDE,0xEC,
+ 0xC1,0x46,0xB9,0xB1,
+ 0x18,0x8D,0xA8,0x0E,0xB0,0x30,0x90,0xF6,0x7C,0xBF, /* x */
+ 0x20,0xEB,0x43,0xA1,0x88,0x00,0xF4,0xFF,0x0A,0xFD,
+ 0x82,0xFF,0x10,0x12,
+ 0x07,0x19,0x2b,0x95,0xff,0xc8,0xda,0x78,0x63,0x10, /* y */
+ 0x11,0xed,0x6b,0x24,0xcd,0xd5,0x73,0xf9,0x77,0xa1,
+ 0x1e,0x79,0x48,0x11,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0x99,0xDE,0xF8,0x36,0x14,0x6B,0xC9,0xB1,
+ 0xB4,0xD2,0x28,0x31 }
};
-static const unsigned char _EC_NIST_PRIME_224_SEED[] = {
- 0xBD,0x71,0x34,0x47,0x99,0xD5,0xC7,0xFC,0xDC,0x45,
- 0xB5,0x9F,0xA3,0xB9,0xAB,0x8F,0x6A,0x94,0x8B,0xC5};
-static const EC_CURVE_DATA _EC_NIST_PRIME_224 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",
- "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
- "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
- "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",1,
- _EC_NIST_PRIME_224_SEED, 20,
- "NIST/SECG curve over a 224 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+28*6]; }
+ _EC_NIST_PRIME_224 = {
+ { NID_X9_62_prime_field,20,28,1 },
+ { 0xBD,0x71,0x34,0x47,0x99,0xD5,0xC7,0xFC,0xDC,0x45, /* seed */
+ 0xB5,0x9F,0xA3,0xB9,0xAB,0x8F,0x6A,0x94,0x8B,0xC5,
+
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+ 0xB4,0x05,0x0A,0x85,0x0C,0x04,0xB3,0xAB,0xF5,0x41, /* b */
+ 0x32,0x56,0x50,0x44,0xB0,0xB7,0xD7,0xBF,0xD8,0xBA,
+ 0x27,0x0B,0x39,0x43,0x23,0x55,0xFF,0xB4,
+ 0xB7,0x0E,0x0C,0xBD,0x6B,0xB4,0xBF,0x7F,0x32,0x13, /* x */
+ 0x90,0xB9,0x4A,0x03,0xC1,0xD3,0x56,0xC2,0x11,0x22,
+ 0x34,0x32,0x80,0xD6,0x11,0x5C,0x1D,0x21,
+ 0xbd,0x37,0x63,0x88,0xb5,0xf7,0x23,0xfb,0x4c,0x22, /* y */
+ 0xdf,0xe6,0xcd,0x43,0x75,0xa0,0x5a,0x07,0x47,0x64,
+ 0x44,0xd5,0x81,0x99,0x85,0x00,0x7e,0x34,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0x16,0xA2,0xE0,0xB8,0xF0,0x3E,
+ 0x13,0xDD,0x29,0x45,0x5C,0x5C,0x2A,0x3D }
};
-static const unsigned char _EC_NIST_PRIME_384_SEED[] = {
- 0xA3,0x35,0x92,0x6A,0xA3,0x19,0xA2,0x7A,0x1D,0x00,
- 0x89,0x6A,0x67,0x73,0xA4,0x82,0x7A,0xCD,0xAC,0x73};
-static const EC_CURVE_DATA _EC_NIST_PRIME_384 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFF"
- "FFF0000000000000000FFFFFFFF",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFF"
- "FFF0000000000000000FFFFFFFC",
- "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC6563"
- "98D8A2ED19D2A85C8EDD3EC2AEF",
- "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F"
- "25DBF55296C3A545E3872760AB7",
- "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b"
- "1ce1d7e819d7a431d7c90ea0e5f",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0"
- "DB248B0A77AECEC196ACCC52973",1,
- _EC_NIST_PRIME_384_SEED, 20,
- "NIST/SECG curve over a 384 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+48*6]; }
+ _EC_NIST_PRIME_384 = {
+ { NID_X9_62_prime_field,20,48,1 },
+ { 0xA3,0x35,0x92,0x6A,0xA3,0x19,0xA2,0x7A,0x1D,0x00, /* seed */
+ 0x89,0x6A,0x67,0x73,0xA4,0x82,0x7A,0xCD,0xAC,0x73,
+
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFC,
+ 0xB3,0x31,0x2F,0xA7,0xE2,0x3E,0xE7,0xE4,0x98,0x8E, /* b */
+ 0x05,0x6B,0xE3,0xF8,0x2D,0x19,0x18,0x1D,0x9C,0x6E,
+ 0xFE,0x81,0x41,0x12,0x03,0x14,0x08,0x8F,0x50,0x13,
+ 0x87,0x5A,0xC6,0x56,0x39,0x8D,0x8A,0x2E,0xD1,0x9D,
+ 0x2A,0x85,0xC8,0xED,0xD3,0xEC,0x2A,0xEF,
+ 0xAA,0x87,0xCA,0x22,0xBE,0x8B,0x05,0x37,0x8E,0xB1, /* x */
+ 0xC7,0x1E,0xF3,0x20,0xAD,0x74,0x6E,0x1D,0x3B,0x62,
+ 0x8B,0xA7,0x9B,0x98,0x59,0xF7,0x41,0xE0,0x82,0x54,
+ 0x2A,0x38,0x55,0x02,0xF2,0x5D,0xBF,0x55,0x29,0x6C,
+ 0x3A,0x54,0x5E,0x38,0x72,0x76,0x0A,0xB7,
+ 0x36,0x17,0xde,0x4a,0x96,0x26,0x2c,0x6f,0x5d,0x9e, /* y */
+ 0x98,0xbf,0x92,0x92,0xdc,0x29,0xf8,0xf4,0x1d,0xbd,
+ 0x28,0x9a,0x14,0x7c,0xe9,0xda,0x31,0x13,0xb5,0xf0,
+ 0xb8,0xc0,0x0a,0x60,0xb1,0xce,0x1d,0x7e,0x81,0x9d,
+ 0x7a,0x43,0x1d,0x7c,0x90,0xea,0x0e,0x5f,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xC7,0x63,0x4D,0x81,0xF4,0x37,
+ 0x2D,0xDF,0x58,0x1A,0x0D,0xB2,0x48,0xB0,0xA7,0x7A,
+ 0xEC,0xEC,0x19,0x6A,0xCC,0xC5,0x29,0x73 }
};
-static const unsigned char _EC_NIST_PRIME_521_SEED[] = {
- 0xD0,0x9E,0x88,0x00,0x29,0x1C,0xB8,0x53,0x96,0xCC,
- 0x67,0x17,0x39,0x32,0x84,0xAA,0xA0,0xDA,0x64,0xBA};
-static const EC_CURVE_DATA _EC_NIST_PRIME_521 = {
- NID_X9_62_prime_field,
- "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
- "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
- "051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156"
- "193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
- "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14"
- "B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
- "011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c9"
- "7ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
- "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51"
- "868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",1,
- _EC_NIST_PRIME_521_SEED, 20,
- "NIST/SECG curve over a 521 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+66*6]; }
+ _EC_NIST_PRIME_521 = {
+ { NID_X9_62_prime_field,20,66,1 },
+ { 0xD0,0x9E,0x88,0x00,0x29,0x1C,0xB8,0x53,0x96,0xCC, /* seed */
+ 0x67,0x17,0x39,0x32,0x84,0xAA,0xA0,0xDA,0x64,0xBA,
+
+ 0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,
+ 0x00,0x51,0x95,0x3E,0xB9,0x61,0x8E,0x1C,0x9A,0x1F, /* b */
+ 0x92,0x9A,0x21,0xA0,0xB6,0x85,0x40,0xEE,0xA2,0xDA,
+ 0x72,0x5B,0x99,0xB3,0x15,0xF3,0xB8,0xB4,0x89,0x91,
+ 0x8E,0xF1,0x09,0xE1,0x56,0x19,0x39,0x51,0xEC,0x7E,
+ 0x93,0x7B,0x16,0x52,0xC0,0xBD,0x3B,0xB1,0xBF,0x07,
+ 0x35,0x73,0xDF,0x88,0x3D,0x2C,0x34,0xF1,0xEF,0x45,
+ 0x1F,0xD4,0x6B,0x50,0x3F,0x00,
+ 0x00,0xC6,0x85,0x8E,0x06,0xB7,0x04,0x04,0xE9,0xCD, /* x */
+ 0x9E,0x3E,0xCB,0x66,0x23,0x95,0xB4,0x42,0x9C,0x64,
+ 0x81,0x39,0x05,0x3F,0xB5,0x21,0xF8,0x28,0xAF,0x60,
+ 0x6B,0x4D,0x3D,0xBA,0xA1,0x4B,0x5E,0x77,0xEF,0xE7,
+ 0x59,0x28,0xFE,0x1D,0xC1,0x27,0xA2,0xFF,0xA8,0xDE,
+ 0x33,0x48,0xB3,0xC1,0x85,0x6A,0x42,0x9B,0xF9,0x7E,
+ 0x7E,0x31,0xC2,0xE5,0xBD,0x66,
+ 0x01,0x18,0x39,0x29,0x6a,0x78,0x9a,0x3b,0xc0,0x04, /* y */
+ 0x5c,0x8a,0x5f,0xb4,0x2c,0x7d,0x1b,0xd9,0x98,0xf5,
+ 0x44,0x49,0x57,0x9b,0x44,0x68,0x17,0xaf,0xbd,0x17,
+ 0x27,0x3e,0x66,0x2c,0x97,0xee,0x72,0x99,0x5e,0xf4,
+ 0x26,0x40,0xc5,0x50,0xb9,0x01,0x3f,0xad,0x07,0x61,
+ 0x35,0x3c,0x70,0x86,0xa2,0x72,0xc2,0x40,0x88,0xbe,
+ 0x94,0x76,0x9f,0xd1,0x66,0x50,
+ 0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFA,0x51,0x86,0x87,0x83,0xBF,0x2F,
+ 0x96,0x6B,0x7F,0xCC,0x01,0x48,0xF7,0x09,0xA5,0xD0,
+ 0x3B,0xB5,0xC9,0xB8,0x89,0x9C,0x47,0xAE,0xBB,0x6F,
+ 0xB7,0x1E,0x91,0x38,0x64,0x09 }
};
+
/* the x9.62 prime curves (minus the nist prime curves) */
-static const unsigned char _EC_X9_62_PRIME_192V2_SEED[] = {
- 0x31,0xA9,0x2E,0xE2,0x02,0x9F,0xD1,0x0D,0x90,0x1B,
- 0x11,0x3E,0x99,0x07,0x10,0xF0,0xD2,0x1A,0xC6,0xB6};
-static const EC_CURVE_DATA _EC_X9_62_PRIME_192V2 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
- "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953",
- "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A",
- "6574d11d69b6ec7a672bb82a083df2f2b0847de970b2de15",
- "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31",1,
- _EC_X9_62_PRIME_192V2_SEED, 20,
- "X9.62 curve over a 192 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+24*6]; }
+ _EC_X9_62_PRIME_192V2 = {
+ { NID_X9_62_prime_field,20,24,1 },
+ { 0x31,0xA9,0x2E,0xE2,0x02,0x9F,0xD1,0x0D,0x90,0x1B, /* seed */
+ 0x11,0x3E,0x99,0x07,0x10,0xF0,0xD2,0x1A,0xC6,0xB6,
+
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFC,
+ 0xCC,0x22,0xD6,0xDF,0xB9,0x5C,0x6B,0x25,0xE4,0x9C, /* b */
+ 0x0D,0x63,0x64,0xA4,0xE5,0x98,0x0C,0x39,0x3A,0xA2,
+ 0x16,0x68,0xD9,0x53,
+ 0xEE,0xA2,0xBA,0xE7,0xE1,0x49,0x78,0x42,0xF2,0xDE, /* x */
+ 0x77,0x69,0xCF,0xE9,0xC9,0x89,0xC0,0x72,0xAD,0x69,
+ 0x6F,0x48,0x03,0x4A,
+ 0x65,0x74,0xd1,0x1d,0x69,0xb6,0xec,0x7a,0x67,0x2b, /* y */
+ 0xb8,0x2a,0x08,0x3d,0xf2,0xf2,0xb0,0x84,0x7d,0xe9,
+ 0x70,0xb2,0xde,0x15,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFE,0x5F,0xB1,0xA7,0x24,0xDC,0x80,0x41,0x86,
+ 0x48,0xD8,0xDD,0x31 }
};
-static const unsigned char _EC_X9_62_PRIME_192V3_SEED[] = {
- 0xC4,0x69,0x68,0x44,0x35,0xDE,0xB3,0x78,0xC4,0xB6,
- 0x5C,0xA9,0x59,0x1E,0x2A,0x57,0x63,0x05,0x9A,0x2E};
-static const EC_CURVE_DATA _EC_X9_62_PRIME_192V3 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
- "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916",
- "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896",
- "38a90f22637337334b49dcb66a6dc8f9978aca7648a943b0",
- "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13",1,
- _EC_X9_62_PRIME_192V3_SEED, 20,
- "X9.62 curve over a 192 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+24*6]; }
+ _EC_X9_62_PRIME_192V3 = {
+ { NID_X9_62_prime_field,20,24,1 },
+ { 0xC4,0x69,0x68,0x44,0x35,0xDE,0xB3,0x78,0xC4,0xB6, /* seed */
+ 0x5C,0xA9,0x59,0x1E,0x2A,0x57,0x63,0x05,0x9A,0x2E,
+
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFC,
+ 0x22,0x12,0x3D,0xC2,0x39,0x5A,0x05,0xCA,0xA7,0x42, /* b */
+ 0x3D,0xAE,0xCC,0xC9,0x47,0x60,0xA7,0xD4,0x62,0x25,
+ 0x6B,0xD5,0x69,0x16,
+ 0x7D,0x29,0x77,0x81,0x00,0xC6,0x5A,0x1D,0xA1,0x78, /* x */
+ 0x37,0x16,0x58,0x8D,0xCE,0x2B,0x8B,0x4A,0xEE,0x8E,
+ 0x22,0x8F,0x18,0x96,
+ 0x38,0xa9,0x0f,0x22,0x63,0x73,0x37,0x33,0x4b,0x49, /* y */
+ 0xdc,0xb6,0x6a,0x6d,0xc8,0xf9,0x97,0x8a,0xca,0x76,
+ 0x48,0xa9,0x43,0xb0,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0x7A,0x62,0xD0,0x31,0xC8,0x3F,0x42,0x94,
+ 0xF6,0x40,0xEC,0x13 }
};
-static const unsigned char _EC_X9_62_PRIME_239V1_SEED[] = {
- 0xE4,0x3B,0xB4,0x60,0xF0,0xB8,0x0C,0xC0,0xC0,0xB0,
- 0x75,0x79,0x8E,0x94,0x80,0x60,0xF8,0x32,0x1B,0x7D};
-static const EC_CURVE_DATA _EC_X9_62_PRIME_239V1 = {
- NID_X9_62_prime_field,
- "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
- "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
- "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A",
- "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF",
- "7debe8e4e90a5dae6e4054ca530ba04654b36818ce226b39fccb7b02f1ae",
- "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B",1,
- _EC_X9_62_PRIME_239V1_SEED, 20,
- "X9.62 curve over a 239 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+30*6]; }
+ _EC_X9_62_PRIME_239V1 = {
+ { NID_X9_62_prime_field,20,30,1 },
+ { 0xE4,0x3B,0xB4,0x60,0xF0,0xB8,0x0C,0xC0,0xC0,0xB0, /* seed */
+ 0x75,0x79,0x8E,0x94,0x80,0x60,0xF8,0x32,0x1B,0x7D,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,
+ 0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,
+ 0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFC,
+
+ 0x6B,0x01,0x6C,0x3B,0xDC,0xF1,0x89,0x41,0xD0,0xD6, /* b */
+ 0x54,0x92,0x14,0x75,0xCA,0x71,0xA9,0xDB,0x2F,0xB2,
+ 0x7D,0x1D,0x37,0x79,0x61,0x85,0xC2,0x94,0x2C,0x0A,
+
+ 0x0F,0xFA,0x96,0x3C,0xDC,0xA8,0x81,0x6C,0xCC,0x33, /* x */
+ 0xB8,0x64,0x2B,0xED,0xF9,0x05,0xC3,0xD3,0x58,0x57,
+ 0x3D,0x3F,0x27,0xFB,0xBD,0x3B,0x3C,0xB9,0xAA,0xAF,
+
+ 0x7d,0xeb,0xe8,0xe4,0xe9,0x0a,0x5d,0xae,0x6e,0x40, /* y */
+ 0x54,0xca,0x53,0x0b,0xa0,0x46,0x54,0xb3,0x68,0x18,
+ 0xce,0x22,0x6b,0x39,0xfc,0xcb,0x7b,0x02,0xf1,0xae,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0x7F,0xFF,0xFF,0x9E,0x5E,0x9A,0x9F,0x5D,
+ 0x90,0x71,0xFB,0xD1,0x52,0x26,0x88,0x90,0x9D,0x0B }
};
-static const unsigned char _EC_X9_62_PRIME_239V2_SEED[] = {
- 0xE8,0xB4,0x01,0x16,0x04,0x09,0x53,0x03,0xCA,0x3B,
- 0x80,0x99,0x98,0x2B,0xE0,0x9F,0xCB,0x9A,0xE6,0x16};
-static const EC_CURVE_DATA _EC_X9_62_PRIME_239V2 = {
- NID_X9_62_prime_field,
- "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
- "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
- "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C",
- "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7",
- "5b0125e4dbea0ec7206da0fc01d9b081329fb555de6ef460237dff8be4ba",
- "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063",1,
- _EC_X9_62_PRIME_239V2_SEED, 20,
- "X9.62 curve over a 239 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+30*6]; }
+ _EC_X9_62_PRIME_239V2 = {
+ { NID_X9_62_prime_field,20,30,1 },
+ { 0xE8,0xB4,0x01,0x16,0x04,0x09,0x53,0x03,0xCA,0x3B, /* seed */
+ 0x80,0x99,0x98,0x2B,0xE0,0x9F,0xCB,0x9A,0xE6,0x16,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,
+ 0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,
+ 0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFC,
+
+ 0x61,0x7F,0xAB,0x68,0x32,0x57,0x6C,0xBB,0xFE,0xD5, /* b */
+ 0x0D,0x99,0xF0,0x24,0x9C,0x3F,0xEE,0x58,0xB9,0x4B,
+ 0xA0,0x03,0x8C,0x7A,0xE8,0x4C,0x8C,0x83,0x2F,0x2C,
+
+ 0x38,0xAF,0x09,0xD9,0x87,0x27,0x70,0x51,0x20,0xC9, /* x */
+ 0x21,0xBB,0x5E,0x9E,0x26,0x29,0x6A,0x3C,0xDC,0xF2,
+ 0xF3,0x57,0x57,0xA0,0xEA,0xFD,0x87,0xB8,0x30,0xE7,
+
+ 0x5b,0x01,0x25,0xe4,0xdb,0xea,0x0e,0xc7,0x20,0x6d, /* y */
+ 0xa0,0xfc,0x01,0xd9,0xb0,0x81,0x32,0x9f,0xb5,0x55,
+ 0xde,0x6e,0xf4,0x60,0x23,0x7d,0xff,0x8b,0xe4,0xba,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0x80,0x00,0x00,0xCF,0xA7,0xE8,0x59,0x43,
+ 0x77,0xD4,0x14,0xC0,0x38,0x21,0xBC,0x58,0x20,0x63 }
};
-static const unsigned char _EC_X9_62_PRIME_239V3_SEED[] = {
- 0x7D,0x73,0x74,0x16,0x8F,0xFE,0x34,0x71,0xB6,0x0A,
- 0x85,0x76,0x86,0xA1,0x94,0x75,0xD3,0xBF,0xA2,0xFF};
-static const EC_CURVE_DATA _EC_X9_62_PRIME_239V3 = {
- NID_X9_62_prime_field,
- "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
- "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
- "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E",
- "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A",
- "1607e6898f390c06bc1d552bad226f3b6fcfe48b6e818499af18e3ed6cf3",
- "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551",1,
- _EC_X9_62_PRIME_239V3_SEED, 20,
- "X9.62 curve over a 239 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+30*6]; }
+ _EC_X9_62_PRIME_239V3 = {
+ { NID_X9_62_prime_field,20,30,1 },
+ { 0x7D,0x73,0x74,0x16,0x8F,0xFE,0x34,0x71,0xB6,0x0A, /* seed */
+ 0x85,0x76,0x86,0xA1,0x94,0x75,0xD3,0xBF,0xA2,0xFF,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,
+ 0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,
+ 0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFC,
+
+ 0x25,0x57,0x05,0xFA,0x2A,0x30,0x66,0x54,0xB1,0xF4, /* b */
+ 0xCB,0x03,0xD6,0xA7,0x50,0xA3,0x0C,0x25,0x01,0x02,
+ 0xD4,0x98,0x87,0x17,0xD9,0xBA,0x15,0xAB,0x6D,0x3E,
+
+ 0x67,0x68,0xAE,0x8E,0x18,0xBB,0x92,0xCF,0xCF,0x00, /* x */
+ 0x5C,0x94,0x9A,0xA2,0xC6,0xD9,0x48,0x53,0xD0,0xE6,
+ 0x60,0xBB,0xF8,0x54,0xB1,0xC9,0x50,0x5F,0xE9,0x5A,
+
+ 0x16,0x07,0xe6,0x89,0x8f,0x39,0x0c,0x06,0xbc,0x1d, /* y */
+ 0x55,0x2b,0xad,0x22,0x6f,0x3b,0x6f,0xcf,0xe4,0x8b,
+ 0x6e,0x81,0x84,0x99,0xaf,0x18,0xe3,0xed,0x6c,0xf3,
+
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0x7F,0xFF,0xFF,0x97,0x5D,0xEB,0x41,0xB3,
+ 0xA6,0x05,0x7C,0x3C,0x43,0x21,0x46,0x52,0x65,0x51 }
};
-static const unsigned char _EC_X9_62_PRIME_256V1_SEED[] = {
- 0xC4,0x9D,0x36,0x08,0x86,0xE7,0x04,0x93,0x6A,0x66,
- 0x78,0xE1,0x13,0x9D,0x26,0xB7,0x81,0x9F,0x7E,0x90};
-static const EC_CURVE_DATA _EC_X9_62_PRIME_256V1 = {
- NID_X9_62_prime_field,
- "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
- "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
- "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
- "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
- "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
- "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",1,
- _EC_X9_62_PRIME_256V1_SEED, 20,
- "X9.62/SECG curve over a 256 bit prime field"
+
+static const struct { EC_CURVE_DATA h; unsigned char data[20+32*6]; }
+ _EC_X9_62_PRIME_256V1 = {
+ { NID_X9_62_prime_field,20,32,1 },
+ { 0xC4,0x9D,0x36,0x08,0x86,0xE7,0x04,0x93,0x6A,0x66, /* seed */
+ 0x78,0xE1,0x13,0x9D,0x26,0xB7,0x81,0x9F,0x7E,0x90,
+
+ 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFC,
+ 0x5A,0xC6,0x35,0xD8,0xAA,0x3A,0x93,0xE7,0xB3,0xEB, /* b */
+ 0xBD,0x55,0x76,0x98,0x86,0xBC,0x65,0x1D,0x06,0xB0,
+ 0xCC,0x53,0xB0,0xF6,0x3B,0xCE,0x3C,0x3E,0x27,0xD2,
+ 0x60,0x4B,
+ 0x6B,0x17,0xD1,0xF2,0xE1,0x2C,0x42,0x47,0xF8,0xBC, /* x */
+ 0xE6,0xE5,0x63,0xA4,0x40,0xF2,0x77,0x03,0x7D,0x81,
+ 0x2D,0xEB,0x33,0xA0,0xF4,0xA1,0x39,0x45,0xD8,0x98,
+ 0xC2,0x96,
+ 0x4f,0xe3,0x42,0xe2,0xfe,0x1a,0x7f,0x9b,0x8e,0xe7, /* y */
+ 0xeb,0x4a,0x7c,0x0f,0x9e,0x16,0x2b,0xce,0x33,0x57,
+ 0x6b,0x31,0x5e,0xce,0xcb,0xb6,0x40,0x68,0x37,0xbf,
+ 0x51,0xf5,
+ 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBC,0xE6,0xFA,0xAD,
+ 0xA7,0x17,0x9E,0x84,0xF3,0xB9,0xCA,0xC2,0xFC,0x63,
+ 0x25,0x51 }
};
+
/* the secg prime curves (minus the nist and x9.62 prime curves) */
-static const unsigned char _EC_SECG_PRIME_112R1_SEED[] = {
- 0x00,0xF5,0x0B,0x02,0x8E,0x4D,0x69,0x6E,0x67,0x68,
- 0x75,0x61,0x51,0x75,0x29,0x04,0x72,0x78,0x3F,0xB1};
-static const EC_CURVE_DATA _EC_SECG_PRIME_112R1 = {
- NID_X9_62_prime_field,
- "DB7C2ABF62E35E668076BEAD208B",
- "DB7C2ABF62E35E668076BEAD2088",
- "659EF8BA043916EEDE8911702B22",
- "09487239995A5EE76B55F9C2F098",
- "a89ce5af8724c0a23e0e0ff77500",
- "DB7C2ABF62E35E7628DFAC6561C5",1,
- _EC_SECG_PRIME_112R1_SEED, 20,
- "SECG/WTLS curve over a 112 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+14*6]; }
+ _EC_SECG_PRIME_112R1 = {
+ { NID_X9_62_prime_field,20,14,1 },
+ { 0x00,0xF5,0x0B,0x02,0x8E,0x4D,0x69,0x6E,0x67,0x68, /* seed */
+ 0x75,0x61,0x51,0x75,0x29,0x04,0x72,0x78,0x3F,0xB1,
+
+ 0xDB,0x7C,0x2A,0xBF,0x62,0xE3,0x5E,0x66,0x80,0x76, /* p */
+ 0xBE,0xAD,0x20,0x8B,
+ 0xDB,0x7C,0x2A,0xBF,0x62,0xE3,0x5E,0x66,0x80,0x76, /* a */
+ 0xBE,0xAD,0x20,0x88,
+ 0x65,0x9E,0xF8,0xBA,0x04,0x39,0x16,0xEE,0xDE,0x89, /* b */
+ 0x11,0x70,0x2B,0x22,
+ 0x09,0x48,0x72,0x39,0x99,0x5A,0x5E,0xE7,0x6B,0x55, /* x */
+ 0xF9,0xC2,0xF0,0x98,
+ 0xa8,0x9c,0xe5,0xaf,0x87,0x24,0xc0,0xa2,0x3e,0x0e, /* y */
+ 0x0f,0xf7,0x75,0x00,
+ 0xDB,0x7C,0x2A,0xBF,0x62,0xE3,0x5E,0x76,0x28,0xDF, /* order */
+ 0xAC,0x65,0x61,0xC5 }
};
-static const unsigned char _EC_SECG_PRIME_112R2_SEED[] = {
- 0x00,0x27,0x57,0xA1,0x11,0x4D,0x69,0x6E,0x67,0x68,
- 0x75,0x61,0x51,0x75,0x53,0x16,0xC0,0x5E,0x0B,0xD4};
-static const EC_CURVE_DATA _EC_SECG_PRIME_112R2 = {
- NID_X9_62_prime_field,
- "DB7C2ABF62E35E668076BEAD208B",
- "6127C24C05F38A0AAAF65C0EF02C",
- "51DEF1815DB5ED74FCC34C85D709",
- "4BA30AB5E892B4E1649DD0928643",
- "adcd46f5882e3747def36e956e97",
- "36DF0AAFD8B8D7597CA10520D04B",4,
- _EC_SECG_PRIME_112R2_SEED, 20,
- "SECG curve over a 112 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+14*6]; }
+ _EC_SECG_PRIME_112R2 = {
+ { NID_X9_62_prime_field,20,14,4 },
+ { 0x00,0x27,0x57,0xA1,0x11,0x4D,0x69,0x6E,0x67,0x68, /* seed */
+ 0x75,0x61,0x51,0x75,0x53,0x16,0xC0,0x5E,0x0B,0xD4,
+
+ 0xDB,0x7C,0x2A,0xBF,0x62,0xE3,0x5E,0x66,0x80,0x76, /* p */
+ 0xBE,0xAD,0x20,0x8B,
+ 0x61,0x27,0xC2,0x4C,0x05,0xF3,0x8A,0x0A,0xAA,0xF6, /* a */
+ 0x5C,0x0E,0xF0,0x2C,
+ 0x51,0xDE,0xF1,0x81,0x5D,0xB5,0xED,0x74,0xFC,0xC3, /* b */
+ 0x4C,0x85,0xD7,0x09,
+ 0x4B,0xA3,0x0A,0xB5,0xE8,0x92,0xB4,0xE1,0x64,0x9D, /* x */
+ 0xD0,0x92,0x86,0x43,
+ 0xad,0xcd,0x46,0xf5,0x88,0x2e,0x37,0x47,0xde,0xf3, /* y */
+ 0x6e,0x95,0x6e,0x97,
+ 0x36,0xDF,0x0A,0xAF,0xD8,0xB8,0xD7,0x59,0x7C,0xA1, /* order */
+ 0x05,0x20,0xD0,0x4B }
};
-static const unsigned char _EC_SECG_PRIME_128R1_SEED[] = {
- 0x00,0x0E,0x0D,0x4D,0x69,0x6E,0x67,0x68,0x75,0x61,
- 0x51,0x75,0x0C,0xC0,0x3A,0x44,0x73,0xD0,0x36,0x79};
-static const EC_CURVE_DATA _EC_SECG_PRIME_128R1 = {
- NID_X9_62_prime_field,
- "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
- "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC",
- "E87579C11079F43DD824993C2CEE5ED3",
- "161FF7528B899B2D0C28607CA52C5B86",
- "cf5ac8395bafeb13c02da292dded7a83",
- "FFFFFFFE0000000075A30D1B9038A115",1,
- _EC_SECG_PRIME_128R1_SEED, 20,
- "SECG curve over a 128 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+16*6]; }
+ _EC_SECG_PRIME_128R1 = {
+ { NID_X9_62_prime_field,20,16,1 },
+ { 0x00,0x0E,0x0D,0x4D,0x69,0x6E,0x67,0x68,0x75,0x61, /* seed */
+ 0x51,0x75,0x0C,0xC0,0x3A,0x44,0x73,0xD0,0x36,0x79,
+
+ 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,
+ 0xE8,0x75,0x79,0xC1,0x10,0x79,0xF4,0x3D,0xD8,0x24, /* b */
+ 0x99,0x3C,0x2C,0xEE,0x5E,0xD3,
+ 0x16,0x1F,0xF7,0x52,0x8B,0x89,0x9B,0x2D,0x0C,0x28, /* x */
+ 0x60,0x7C,0xA5,0x2C,0x5B,0x86,
+ 0xcf,0x5a,0xc8,0x39,0x5b,0xaf,0xeb,0x13,0xc0,0x2d, /* y */
+ 0xa2,0x92,0xdd,0xed,0x7a,0x83,
+ 0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x75,0xA3, /* order */
+ 0x0D,0x1B,0x90,0x38,0xA1,0x15 }
};
-static const unsigned char _EC_SECG_PRIME_128R2_SEED[] = {
- 0x00,0x4D,0x69,0x6E,0x67,0x68,0x75,0x61,0x51,0x75,
- 0x12,0xD8,0xF0,0x34,0x31,0xFC,0xE6,0x3B,0x88,0xF4};
-static const EC_CURVE_DATA _EC_SECG_PRIME_128R2 = {
- NID_X9_62_prime_field,
- "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
- "D6031998D1B3BBFEBF59CC9BBFF9AEE1",
- "5EEEFCA380D02919DC2C6558BB6D8A5D",
- "7B6AA5D85E572983E6FB32A7CDEBC140",
- "27b6916a894d3aee7106fe805fc34b44",
- "3FFFFFFF7FFFFFFFBE0024720613B5A3",4,
- _EC_SECG_PRIME_128R2_SEED, 20,
- "SECG curve over a 128 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+16*6]; }
+ _EC_SECG_PRIME_128R2 = {
+ { NID_X9_62_prime_field,20,16,4 },
+ { 0x00,0x4D,0x69,0x6E,0x67,0x68,0x75,0x61,0x51,0x75, /* seed */
+ 0x12,0xD8,0xF0,0x34,0x31,0xFC,0xE6,0x3B,0x88,0xF4,
+
+ 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xD6,0x03,0x19,0x98,0xD1,0xB3,0xBB,0xFE,0xBF,0x59, /* a */
+ 0xCC,0x9B,0xBF,0xF9,0xAE,0xE1,
+ 0x5E,0xEE,0xFC,0xA3,0x80,0xD0,0x29,0x19,0xDC,0x2C, /* b */
+ 0x65,0x58,0xBB,0x6D,0x8A,0x5D,
+ 0x7B,0x6A,0xA5,0xD8,0x5E,0x57,0x29,0x83,0xE6,0xFB, /* x */
+ 0x32,0xA7,0xCD,0xEB,0xC1,0x40,
+ 0x27,0xb6,0x91,0x6a,0x89,0x4d,0x3a,0xee,0x71,0x06, /* y */
+ 0xfe,0x80,0x5f,0xc3,0x4b,0x44,
+ 0x3F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xBE,0x00, /* order */
+ 0x24,0x72,0x06,0x13,0xB5,0xA3 }
};
-static const EC_CURVE_DATA _EC_SECG_PRIME_160K1 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73",
- "0",
- "7",
- "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB",
- "938cf935318fdced6bc28286531733c3f03c4fee",
- "0100000000000000000001B8FA16DFAB9ACA16B6B3",1,
- NULL, 0,
- "SECG curve over a 160 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+21*6]; }
+ _EC_SECG_PRIME_160K1 = {
+ { NID_X9_62_prime_field,0,21,1 },
+ { /* no seed */
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xAC,
+ 0x73,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x07,
+ 0x00,0x3B,0x4C,0x38,0x2C,0xE3,0x7A,0xA1,0x92,0xA4, /* x */
+ 0x01,0x9E,0x76,0x30,0x36,0xF4,0xF5,0xDD,0x4D,0x7E,
+ 0xBB,
+ 0x00,0x93,0x8c,0xf9,0x35,0x31,0x8f,0xdc,0xed,0x6b, /* y */
+ 0xc2,0x82,0x86,0x53,0x17,0x33,0xc3,0xf0,0x3c,0x4f,
+ 0xee,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x01,0xB8,0xFA,0x16,0xDF,0xAB,0x9A,0xCA,0x16,0xB6,
+ 0xB3 }
};
-static const unsigned char _EC_SECG_PRIME_160R1_SEED[] = {
- 0x10,0x53,0xCD,0xE4,0x2C,0x14,0xD6,0x96,0xE6,0x76,
- 0x87,0x56,0x15,0x17,0x53,0x3B,0xF3,0xF8,0x33,0x45};
-static const EC_CURVE_DATA _EC_SECG_PRIME_160R1 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
- "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
- "4A96B5688EF573284664698968C38BB913CBFC82",
- "23a628553168947d59dcc912042351377ac5fb32",
- "0100000000000000000001F4C8F927AED3CA752257",1,
- _EC_SECG_PRIME_160R1_SEED, 20,
- "SECG curve over a 160 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+21*6]; }
+ _EC_SECG_PRIME_160R1 = {
+ { NID_X9_62_prime_field,20,21,1 },
+ { 0x10,0x53,0xCD,0xE4,0x2C,0x14,0xD6,0x96,0xE6,0x76, /* seed */
+ 0x87,0x56,0x15,0x17,0x53,0x3B,0xF3,0xF8,0x33,0x45,
+
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,
+ 0xFF,
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,
+ 0xFC,
+ 0x00,0x1C,0x97,0xBE,0xFC,0x54,0xBD,0x7A,0x8B,0x65, /* b */
+ 0xAC,0xF8,0x9F,0x81,0xD4,0xD4,0xAD,0xC5,0x65,0xFA,
+ 0x45,
+ 0x00,0x4A,0x96,0xB5,0x68,0x8E,0xF5,0x73,0x28,0x46, /* x */
+ 0x64,0x69,0x89,0x68,0xC3,0x8B,0xB9,0x13,0xCB,0xFC,
+ 0x82,
+ 0x00,0x23,0xa6,0x28,0x55,0x31,0x68,0x94,0x7d,0x59, /* y */
+ 0xdc,0xc9,0x12,0x04,0x23,0x51,0x37,0x7a,0xc5,0xfb,
+ 0x32,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x01,0xF4,0xC8,0xF9,0x27,0xAE,0xD3,0xCA,0x75,0x22,
+ 0x57 }
};
-static const unsigned char _EC_SECG_PRIME_160R2_SEED[] = {
- 0xB9,0x9B,0x99,0xB0,0x99,0xB3,0x23,0xE0,0x27,0x09,
- 0xA4,0xD6,0x96,0xE6,0x76,0x87,0x56,0x15,0x17,0x51};
-static const EC_CURVE_DATA _EC_SECG_PRIME_160R2 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70",
- "B4E134D3FB59EB8BAB57274904664D5AF50388BA",
- "52DCB034293A117E1F4FF11B30F7199D3144CE6D",
- "feaffef2e331f296e071fa0df9982cfea7d43f2e",
- "0100000000000000000000351EE786A818F3A1A16B",1,
- _EC_SECG_PRIME_160R2_SEED, 20,
- "SECG/WTLS curve over a 160 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+21*6]; }
+ _EC_SECG_PRIME_160R2 = {
+ { NID_X9_62_prime_field,20,21,1 },
+ { 0xB9,0x9B,0x99,0xB0,0x99,0xB3,0x23,0xE0,0x27,0x09, /* seed */
+ 0xA4,0xD6,0x96,0xE6,0x76,0x87,0x56,0x15,0x17,0x51,
+
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xAC,
+ 0x73,
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xAC,
+ 0x70,
+ 0x00,0xB4,0xE1,0x34,0xD3,0xFB,0x59,0xEB,0x8B,0xAB, /* b */
+ 0x57,0x27,0x49,0x04,0x66,0x4D,0x5A,0xF5,0x03,0x88,
+ 0xBA,
+ 0x00,0x52,0xDC,0xB0,0x34,0x29,0x3A,0x11,0x7E,0x1F, /* x */
+ 0x4F,0xF1,0x1B,0x30,0xF7,0x19,0x9D,0x31,0x44,0xCE,
+ 0x6D,
+ 0x00,0xfe,0xaf,0xfe,0xf2,0xe3,0x31,0xf2,0x96,0xe0, /* y */
+ 0x71,0xfa,0x0d,0xf9,0x98,0x2c,0xfe,0xa7,0xd4,0x3f,
+ 0x2e,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x35,0x1E,0xE7,0x86,0xA8,0x18,0xF3,0xA1,0xA1,
+ 0x6B }
};
-static const EC_CURVE_DATA _EC_SECG_PRIME_192K1 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37",
- "0",
- "3",
- "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D",
- "9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9d",
- "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D",1,
- NULL, 20,
- "SECG curve over a 192 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+24*6]; }
+ _EC_SECG_PRIME_192K1 = {
+ { NID_X9_62_prime_field,0,24,1 },
+ { /* no seed */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+ 0xFF,0xFF,0xEE,0x37,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x03,
+ 0xDB,0x4F,0xF1,0x0E,0xC0,0x57,0xE9,0xAE,0x26,0xB0, /* x */
+ 0x7D,0x02,0x80,0xB7,0xF4,0x34,0x1D,0xA5,0xD1,0xB1,
+ 0xEA,0xE0,0x6C,0x7D,
+ 0x9b,0x2f,0x2f,0x6d,0x9c,0x56,0x28,0xa7,0x84,0x41, /* y */
+ 0x63,0xd0,0x15,0xbe,0x86,0x34,0x40,0x82,0xaa,0x88,
+ 0xd9,0x5e,0x2f,0x9d,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFE,0x26,0xF2,0xFC,0x17,0x0F,0x69,0x46,0x6A,
+ 0x74,0xDE,0xFD,0x8D }
};
-static const EC_CURVE_DATA _EC_SECG_PRIME_224K1 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D",
- "0",
- "5",
- "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C",
- "7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5",
- "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7",1,
- NULL, 20,
- "SECG curve over a 224 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+29*6]; }
+ _EC_SECG_PRIME_224K1 = {
+ { NID_X9_62_prime_field,0,29,1 },
+ { /* no seed */
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xE5,0x6D,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,
+ 0x00,0xA1,0x45,0x5B,0x33,0x4D,0xF0,0x99,0xDF,0x30, /* x */
+ 0xFC,0x28,0xA1,0x69,0xA4,0x67,0xE9,0xE4,0x70,0x75,
+ 0xA9,0x0F,0x7E,0x65,0x0E,0xB6,0xB7,0xA4,0x5C,
+ 0x00,0x7e,0x08,0x9f,0xed,0x7f,0xba,0x34,0x42,0x82, /* y */
+ 0xca,0xfb,0xd6,0xf7,0xe3,0x19,0xf7,0xc0,0xb0,0xbd,
+ 0x59,0xe2,0xca,0x4b,0xdb,0x55,0x6d,0x61,0xa5,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x00,0x00,0x01,0xDC,0xE8,0xD2,0xEC,0x61,
+ 0x84,0xCA,0xF0,0xA9,0x71,0x76,0x9F,0xB1,0xF7 }
};
-static const EC_CURVE_DATA _EC_SECG_PRIME_256K1 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
- "0",
- "7",
- "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
- "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",1,
- NULL, 20,
- "SECG curve over a 256 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+32*6]; }
+ _EC_SECG_PRIME_256K1 = {
+ { NID_X9_62_prime_field,0,32,1 },
+ { /* no seed */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,
+ 0xFC,0x2F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x07,
+ 0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0, /* x */
+ 0x62,0x95,0xCE,0x87,0x0B,0x07,0x02,0x9B,0xFC,0xDB,
+ 0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
+ 0x17,0x98,
+ 0x48,0x3a,0xda,0x77,0x26,0xa3,0xc4,0x65,0x5d,0xa4, /* y */
+ 0xfb,0xfc,0x0e,0x11,0x08,0xa8,0xfd,0x17,0xb4,0x48,
+ 0xa6,0x85,0x54,0x19,0x9c,0x47,0xd0,0x8f,0xfb,0x10,
+ 0xd4,0xb8,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,
+ 0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,0x8C,0xD0,0x36,
+ 0x41,0x41 }
};
/* some wap/wtls curves */
-static const EC_CURVE_DATA _EC_WTLS_8 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFDE7",
- "0",
- "3",
- "1",
- "2",
- "0100000000000001ECEA551AD837E9",1,
- NULL, 20,
- "WTLS curve over a 112 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+15*6]; }
+ _EC_WTLS_8 = {
+ { NID_X9_62_prime_field,0,15,1 },
+ { /* no seed */
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFD,0xE7,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x */
+ 0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y */
+ 0x00,0x00,0x00,0x00,0x02,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xEC,0xEA, /* order */
+ 0x55,0x1A,0xD8,0x37,0xE9 }
};
-static const EC_CURVE_DATA _EC_WTLS_9 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC808F",
- "0",
- "3",
- "1",
- "2",
- "0100000000000000000001CDC98AE0E2DE574ABF33",1,
- NULL, 20,
- "WTLS curve over a 160 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+21*6]; }
+ _EC_WTLS_9 = {
+ { NID_X9_62_prime_field,0,21,1 },
+ { /* no seed */
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0x80,
+ 0x8F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x02,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x01,0xCD,0xC9,0x8A,0xE0,0xE2,0xDE,0x57,0x4A,0xBF,
+ 0x33 }
};
-static const EC_CURVE_DATA _EC_WTLS_12 = {
- NID_X9_62_prime_field,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",
- "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
- "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
- "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", 1,
- NULL, 0,
- "WTLS curvs over a 224 bit prime field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+28*6]; }
+ _EC_WTLS_12 = {
+ { NID_X9_62_prime_field,0,28,1 },
+ { /* no seed */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+ 0xB4,0x05,0x0A,0x85,0x0C,0x04,0xB3,0xAB,0xF5,0x41, /* b */
+ 0x32,0x56,0x50,0x44,0xB0,0xB7,0xD7,0xBF,0xD8,0xBA,
+ 0x27,0x0B,0x39,0x43,0x23,0x55,0xFF,0xB4,
+ 0xB7,0x0E,0x0C,0xBD,0x6B,0xB4,0xBF,0x7F,0x32,0x13, /* x */
+ 0x90,0xB9,0x4A,0x03,0xC1,0xD3,0x56,0xC2,0x11,0x22,
+ 0x34,0x32,0x80,0xD6,0x11,0x5C,0x1D,0x21,
+ 0xbd,0x37,0x63,0x88,0xb5,0xf7,0x23,0xfb,0x4c,0x22, /* y */
+ 0xdf,0xe6,0xcd,0x43,0x75,0xa0,0x5a,0x07,0x47,0x64,
+ 0x44,0xd5,0x81,0x99,0x85,0x00,0x7e,0x34,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0x16,0xA2,0xE0,0xB8,0xF0,0x3E,
+ 0x13,0xDD,0x29,0x45,0x5C,0x5C,0x2A,0x3D }
};
+#ifndef OPENSSL_NO_EC2M
+
/* characteristic two curves */
-static const unsigned char _EC_SECG_CHAR2_113R1_SEED[] = {
- 0x10,0xE7,0x23,0xAB,0x14,0xD6,0x96,0xE6,0x76,0x87,
- 0x56,0x15,0x17,0x56,0xFE,0xBF,0x8F,0xCB,0x49,0xA9};
-static const EC_CURVE_DATA _EC_SECG_CHAR2_113R1 = {
- NID_X9_62_characteristic_two_field,
- "020000000000000000000000000201",
- "003088250CA6E7C7FE649CE85820F7",
- "00E8BEE4D3E2260744188BE0E9C723",
- "009D73616F35F4AB1407D73562C10F",
- "00A52830277958EE84D1315ED31886",
- "0100000000000000D9CCEC8A39E56F", 2,
- _EC_SECG_CHAR2_113R1_SEED, 20,
- "SECG curve over a 113 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+15*6]; }
+ _EC_SECG_CHAR2_113R1 = {
+ { NID_X9_62_characteristic_two_field,20,15,2 },
+ { 0x10,0xE7,0x23,0xAB,0x14,0xD6,0x96,0xE6,0x76,0x87, /* seed */
+ 0x56,0x15,0x17,0x56,0xFE,0xBF,0x8F,0xCB,0x49,0xA9,
+
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x02,0x01,
+ 0x00,0x30,0x88,0x25,0x0C,0xA6,0xE7,0xC7,0xFE,0x64, /* a */
+ 0x9C,0xE8,0x58,0x20,0xF7,
+ 0x00,0xE8,0xBE,0xE4,0xD3,0xE2,0x26,0x07,0x44,0x18, /* b */
+ 0x8B,0xE0,0xE9,0xC7,0x23,
+ 0x00,0x9D,0x73,0x61,0x6F,0x35,0xF4,0xAB,0x14,0x07, /* x */
+ 0xD7,0x35,0x62,0xC1,0x0F,
+ 0x00,0xA5,0x28,0x30,0x27,0x79,0x58,0xEE,0x84,0xD1, /* y */
+ 0x31,0x5E,0xD3,0x18,0x86,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD9,0xCC, /* order */
+ 0xEC,0x8A,0x39,0xE5,0x6F }
};
-static const unsigned char _EC_SECG_CHAR2_113R2_SEED[] = {
- 0x10,0xC0,0xFB,0x15,0x76,0x08,0x60,0xDE,0xF1,0xEE,
- 0xF4,0xD6,0x96,0xE6,0x76,0x87,0x56,0x15,0x17,0x5D};
-static const EC_CURVE_DATA _EC_SECG_CHAR2_113R2 = {
- NID_X9_62_characteristic_two_field,
- "020000000000000000000000000201",
- "00689918DBEC7E5A0DD6DFC0AA55C7",
- "0095E9A9EC9B297BD4BF36E059184F",
- "01A57A6A7B26CA5EF52FCDB8164797",
- "00B3ADC94ED1FE674C06E695BABA1D",
- "010000000000000108789B2496AF93", 2,
- _EC_SECG_CHAR2_113R2_SEED, 20,
- "SECG curve over a 113 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+15*6]; }
+ _EC_SECG_CHAR2_113R2 = {
+ { NID_X9_62_characteristic_two_field,20,15,2 },
+ { 0x10,0xC0,0xFB,0x15,0x76,0x08,0x60,0xDE,0xF1,0xEE, /* seed */
+ 0xF4,0xD6,0x96,0xE6,0x76,0x87,0x56,0x15,0x17,0x5D,
+
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x02,0x01,
+ 0x00,0x68,0x99,0x18,0xDB,0xEC,0x7E,0x5A,0x0D,0xD6, /* a */
+ 0xDF,0xC0,0xAA,0x55,0xC7,
+ 0x00,0x95,0xE9,0xA9,0xEC,0x9B,0x29,0x7B,0xD4,0xBF, /* b */
+ 0x36,0xE0,0x59,0x18,0x4F,
+ 0x01,0xA5,0x7A,0x6A,0x7B,0x26,0xCA,0x5E,0xF5,0x2F, /* x */
+ 0xCD,0xB8,0x16,0x47,0x97,
+ 0x00,0xB3,0xAD,0xC9,0x4E,0xD1,0xFE,0x67,0x4C,0x06, /* y */
+ 0xE6,0x95,0xBA,0xBA,0x1D,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x08,0x78, /* order */
+ 0x9B,0x24,0x96,0xAF,0x93 }
};
-static const unsigned char _EC_SECG_CHAR2_131R1_SEED[] = {
- 0x4D,0x69,0x6E,0x67,0x68,0x75,0x61,0x51,0x75,0x98,
- 0x5B,0xD3,0xAD,0xBA,0xDA,0x21,0xB4,0x3A,0x97,0xE2};
-static const EC_CURVE_DATA _EC_SECG_CHAR2_131R1 = {
- NID_X9_62_characteristic_two_field,
- "080000000000000000000000000000010D",
- "07A11B09A76B562144418FF3FF8C2570B8",
- "0217C05610884B63B9C6C7291678F9D341",
- "0081BAF91FDF9833C40F9C181343638399",
- "078C6E7EA38C001F73C8134B1B4EF9E150",
- "0400000000000000023123953A9464B54D", 2,
- _EC_SECG_CHAR2_131R1_SEED, 20,
- "SECG/WTLS curve over a 131 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+17*6]; }
+ _EC_SECG_CHAR2_131R1 = {
+ { NID_X9_62_characteristic_two_field,20,17,2 },
+ { 0x4D,0x69,0x6E,0x67,0x68,0x75,0x61,0x51,0x75,0x98, /* seed */
+ 0x5B,0xD3,0xAD,0xBA,0xDA,0x21,0xB4,0x3A,0x97,0xE2,
+
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x01,0x0D,
+ 0x07,0xA1,0x1B,0x09,0xA7,0x6B,0x56,0x21,0x44,0x41, /* a */
+ 0x8F,0xF3,0xFF,0x8C,0x25,0x70,0xB8,
+ 0x02,0x17,0xC0,0x56,0x10,0x88,0x4B,0x63,0xB9,0xC6, /* b */
+ 0xC7,0x29,0x16,0x78,0xF9,0xD3,0x41,
+ 0x00,0x81,0xBA,0xF9,0x1F,0xDF,0x98,0x33,0xC4,0x0F, /* x */
+ 0x9C,0x18,0x13,0x43,0x63,0x83,0x99,
+ 0x07,0x8C,0x6E,0x7E,0xA3,0x8C,0x00,0x1F,0x73,0xC8, /* y */
+ 0x13,0x4B,0x1B,0x4E,0xF9,0xE1,0x50,
+ 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x31, /* order */
+ 0x23,0x95,0x3A,0x94,0x64,0xB5,0x4D }
};
-static const unsigned char _EC_SECG_CHAR2_131R2_SEED[] = {
- 0x98,0x5B,0xD3,0xAD,0xBA,0xD4,0xD6,0x96,0xE6,0x76,
- 0x87,0x56,0x15,0x17,0x5A,0x21,0xB4,0x3A,0x97,0xE3};
-static const EC_CURVE_DATA _EC_SECG_CHAR2_131R2 = {
- NID_X9_62_characteristic_two_field,
- "080000000000000000000000000000010D",
- "03E5A88919D7CAFCBF415F07C2176573B2",
- "04B8266A46C55657AC734CE38F018F2192",
- "0356DCD8F2F95031AD652D23951BB366A8",
- "0648F06D867940A5366D9E265DE9EB240F",
- "0400000000000000016954A233049BA98F", 2,
- _EC_SECG_CHAR2_131R2_SEED, 20,
- "SECG curve over a 131 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+17*6]; }
+ _EC_SECG_CHAR2_131R2 = {
+ { NID_X9_62_characteristic_two_field,20,17,2 },
+ { 0x98,0x5B,0xD3,0xAD,0xBA,0xD4,0xD6,0x96,0xE6,0x76, /* seed */
+ 0x87,0x56,0x15,0x17,0x5A,0x21,0xB4,0x3A,0x97,0xE3,
+
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x01,0x0D,
+ 0x03,0xE5,0xA8,0x89,0x19,0xD7,0xCA,0xFC,0xBF,0x41, /* a */
+ 0x5F,0x07,0xC2,0x17,0x65,0x73,0xB2,
+ 0x04,0xB8,0x26,0x6A,0x46,0xC5,0x56,0x57,0xAC,0x73, /* b */
+ 0x4C,0xE3,0x8F,0x01,0x8F,0x21,0x92,
+ 0x03,0x56,0xDC,0xD8,0xF2,0xF9,0x50,0x31,0xAD,0x65, /* x */
+ 0x2D,0x23,0x95,0x1B,0xB3,0x66,0xA8,
+ 0x06,0x48,0xF0,0x6D,0x86,0x79,0x40,0xA5,0x36,0x6D, /* y */
+ 0x9E,0x26,0x5D,0xE9,0xEB,0x24,0x0F,
+ 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x69, /* order */
+ 0x54,0xA2,0x33,0x04,0x9B,0xA9,0x8F }
};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_163K = {
- NID_X9_62_characteristic_two_field,
- "0800000000000000000000000000000000000000C9",
- "1",
- "1",
- "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8",
- "0289070FB05D38FF58321F2E800536D538CCDAA3D9",
- "04000000000000000000020108A2E0CC0D99F8A5EF", 2,
- NULL, 0,
- "NIST/SECG/WTLS curve over a 163 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+21*6]; }
+ _EC_NIST_CHAR2_163K = {
+ { NID_X9_62_characteristic_two_field,0,21,2 },
+ { /* no seed */
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xC9,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,
+ 0x02,0xFE,0x13,0xC0,0x53,0x7B,0xBC,0x11,0xAC,0xAA, /* x */
+ 0x07,0xD7,0x93,0xDE,0x4E,0x6D,0x5E,0x5C,0x94,0xEE,
+ 0xE8,
+ 0x02,0x89,0x07,0x0F,0xB0,0x5D,0x38,0xFF,0x58,0x32, /* y */
+ 0x1F,0x2E,0x80,0x05,0x36,0xD5,0x38,0xCC,0xDA,0xA3,
+ 0xD9,
+ 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x02,0x01,0x08,0xA2,0xE0,0xCC,0x0D,0x99,0xF8,0xA5,
+ 0xEF }
};
-static const unsigned char _EC_SECG_CHAR2_163R1_SEED[] = {
- 0x24,0xB7,0xB1,0x37,0xC8,0xA1,0x4D,0x69,0x6E,0x67,
- 0x68,0x75,0x61,0x51,0x75,0x6F,0xD0,0xDA,0x2E,0x5C};
-static const EC_CURVE_DATA _EC_SECG_CHAR2_163R1 = {
- NID_X9_62_characteristic_two_field,
- "0800000000000000000000000000000000000000C9",
- "07B6882CAAEFA84F9554FF8428BD88E246D2782AE2",
- "0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9",
- "0369979697AB43897789566789567F787A7876A654",
- "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883",
- "03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B", 2,
+static const struct { EC_CURVE_DATA h; unsigned char data[0+21*6]; }
+ _EC_SECG_CHAR2_163R1 = {
+ { NID_X9_62_characteristic_two_field,0,21,2 },
+ { /* no seed */
+#if 0
/* The algorithm used to derive the curve parameters from
* the seed used here is slightly different than the
- * algorithm described in X9.62 .
- */
-#if 0
- _EC_SECG_CHAR2_163R1_SEED, 20,
-#else
- NULL, 0,
+ * algorithm described in X9.62 . */
+ 0x24,0xB7,0xB1,0x37,0xC8,0xA1,0x4D,0x69,0x6E,0x67,
+ 0x68,0x75,0x61,0x51,0x75,0x6F,0xD0,0xDA,0x2E,0x5C,
#endif
- "SECG curve over a 163 bit binary field"
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xC9,
+ 0x07,0xB6,0x88,0x2C,0xAA,0xEF,0xA8,0x4F,0x95,0x54, /* a */
+ 0xFF,0x84,0x28,0xBD,0x88,0xE2,0x46,0xD2,0x78,0x2A,
+ 0xE2,
+ 0x07,0x13,0x61,0x2D,0xCD,0xDC,0xB4,0x0A,0xAB,0x94, /* b */
+ 0x6B,0xDA,0x29,0xCA,0x91,0xF7,0x3A,0xF9,0x58,0xAF,
+ 0xD9,
+ 0x03,0x69,0x97,0x96,0x97,0xAB,0x43,0x89,0x77,0x89, /* x */
+ 0x56,0x67,0x89,0x56,0x7F,0x78,0x7A,0x78,0x76,0xA6,
+ 0x54,
+ 0x00,0x43,0x5E,0xDB,0x42,0xEF,0xAF,0xB2,0x98,0x9D, /* y */
+ 0x51,0xFE,0xFC,0xE3,0xC8,0x09,0x88,0xF4,0x1F,0xF8,
+ 0x83,
+ 0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0x48,0xAA,0xB6,0x89,0xC2,0x9C,0xA7,0x10,0x27,
+ 0x9B }
};
-static const unsigned char _EC_NIST_CHAR2_163B_SEED[] = {
- 0x85,0xE2,0x5B,0xFE,0x5C,0x86,0x22,0x6C,0xDB,0x12,
- 0x01,0x6F,0x75,0x53,0xF9,0xD0,0xE6,0x93,0xA2,0x68};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_163B ={
- NID_X9_62_characteristic_two_field,
- "0800000000000000000000000000000000000000C9",
- "1",
- "020A601907B8C953CA1481EB10512F78744A3205FD",
- "03F0EBA16286A2D57EA0991168D4994637E8343E36",
- "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1",
- "040000000000000000000292FE77E70C12A4234C33", 2,
-/* The seed here was used to created the curve parameters in normal
- * basis representation (and not the polynomial representation used here)
- */
+static const struct { EC_CURVE_DATA h; unsigned char data[0+21*6]; }
+ _EC_NIST_CHAR2_163B = {
+ { NID_X9_62_characteristic_two_field,0,21,2 },
+ { /* no seed */
#if 0
- _EC_NIST_CHAR2_163B_SEED, 20,
-#else
- NULL, 0,
+/* The seed here was used to created the curve parameters in normal
+ * basis representation (and not the polynomial representation used here) */
+ 0x85,0xE2,0x5B,0xFE,0x5C,0x86,0x22,0x6C,0xDB,0x12,
+ 0x01,0x6F,0x75,0x53,0xF9,0xD0,0xE6,0x93,0xA2,0x68,
#endif
- "NIST/SECG curve over a 163 bit binary field"
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xC9,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,
+ 0x02,0x0A,0x60,0x19,0x07,0xB8,0xC9,0x53,0xCA,0x14, /* b */
+ 0x81,0xEB,0x10,0x51,0x2F,0x78,0x74,0x4A,0x32,0x05,
+ 0xFD,
+ 0x03,0xF0,0xEB,0xA1,0x62,0x86,0xA2,0xD5,0x7E,0xA0, /* x */
+ 0x99,0x11,0x68,0xD4,0x99,0x46,0x37,0xE8,0x34,0x3E,
+ 0x36,
+ 0x00,0xD5,0x1F,0xBC,0x6C,0x71,0xA0,0x09,0x4F,0xA2, /* y */
+ 0xCD,0xD5,0x45,0xB1,0x1C,0x5C,0x0C,0x79,0x73,0x24,
+ 0xF1,
+ 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x02,0x92,0xFE,0x77,0xE7,0x0C,0x12,0xA4,0x23,0x4C,
+ 0x33 }
};
-static const unsigned char _EC_SECG_CHAR2_193R1_SEED[] = {
- 0x10,0x3F,0xAE,0xC7,0x4D,0x69,0x6E,0x67,0x68,0x75,
- 0x61,0x51,0x75,0x77,0x7F,0xC5,0xB1,0x91,0xEF,0x30};
-static const EC_CURVE_DATA _EC_SECG_CHAR2_193R1 = {
- NID_X9_62_characteristic_two_field,
- "02000000000000000000000000000000000000000000008001",
- "0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01",
- "00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814",
- "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1",
- "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05",
- "01000000000000000000000000C7F34A778F443ACC920EBA49", 2,
- _EC_SECG_CHAR2_193R1_SEED, 20,
- "SECG curve over a 193 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+25*6]; }
+ _EC_SECG_CHAR2_193R1 = {
+ { NID_X9_62_characteristic_two_field,20,25,2 },
+ { 0x10,0x3F,0xAE,0xC7,0x4D,0x69,0x6E,0x67,0x68,0x75, /* seed */
+ 0x61,0x51,0x75,0x77,0x7F,0xC5,0xB1,0x91,0xEF,0x30,
+
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x01,
+ 0x00,0x17,0x85,0x8F,0xEB,0x7A,0x98,0x97,0x51,0x69, /* a */
+ 0xE1,0x71,0xF7,0x7B,0x40,0x87,0xDE,0x09,0x8A,0xC8,
+ 0xA9,0x11,0xDF,0x7B,0x01,
+ 0x00,0xFD,0xFB,0x49,0xBF,0xE6,0xC3,0xA8,0x9F,0xAC, /* b */
+ 0xAD,0xAA,0x7A,0x1E,0x5B,0xBC,0x7C,0xC1,0xC2,0xE5,
+ 0xD8,0x31,0x47,0x88,0x14,
+ 0x01,0xF4,0x81,0xBC,0x5F,0x0F,0xF8,0x4A,0x74,0xAD, /* x */
+ 0x6C,0xDF,0x6F,0xDE,0xF4,0xBF,0x61,0x79,0x62,0x53,
+ 0x72,0xD8,0xC0,0xC5,0xE1,
+ 0x00,0x25,0xE3,0x99,0xF2,0x90,0x37,0x12,0xCC,0xF3, /* y */
+ 0xEA,0x9E,0x3A,0x1A,0xD1,0x7F,0xB0,0xB3,0x20,0x1B,
+ 0x6A,0xF7,0xCE,0x1B,0x05,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x00,0xC7,0xF3,0x4A,0x77,0x8F,0x44,0x3A,
+ 0xCC,0x92,0x0E,0xBA,0x49 }
};
-static const unsigned char _EC_SECG_CHAR2_193R2_SEED[] = {
- 0x10,0xB7,0xB4,0xD6,0x96,0xE6,0x76,0x87,0x56,0x15,
- 0x17,0x51,0x37,0xC8,0xA1,0x6F,0xD0,0xDA,0x22,0x11};
-static const EC_CURVE_DATA _EC_SECG_CHAR2_193R2 = {
- NID_X9_62_characteristic_two_field,
- "02000000000000000000000000000000000000000000008001",
- "0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B",
- "00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE",
- "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F",
- "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C",
- "010000000000000000000000015AAB561B005413CCD4EE99D5", 2,
- _EC_SECG_CHAR2_193R2_SEED, 20,
- "SECG curve over a 193 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+25*6]; }
+ _EC_SECG_CHAR2_193R2 = {
+ { NID_X9_62_characteristic_two_field,20,25,2 },
+ { 0x10,0xB7,0xB4,0xD6,0x96,0xE6,0x76,0x87,0x56,0x15, /* seed */
+ 0x17,0x51,0x37,0xC8,0xA1,0x6F,0xD0,0xDA,0x22,0x11,
+
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x80,0x01,
+ 0x01,0x63,0xF3,0x5A,0x51,0x37,0xC2,0xCE,0x3E,0xA6, /* a */
+ 0xED,0x86,0x67,0x19,0x0B,0x0B,0xC4,0x3E,0xCD,0x69,
+ 0x97,0x77,0x02,0x70,0x9B,
+ 0x00,0xC9,0xBB,0x9E,0x89,0x27,0xD4,0xD6,0x4C,0x37, /* b */
+ 0x7E,0x2A,0xB2,0x85,0x6A,0x5B,0x16,0xE3,0xEF,0xB7,
+ 0xF6,0x1D,0x43,0x16,0xAE,
+ 0x00,0xD9,0xB6,0x7D,0x19,0x2E,0x03,0x67,0xC8,0x03, /* x */
+ 0xF3,0x9E,0x1A,0x7E,0x82,0xCA,0x14,0xA6,0x51,0x35,
+ 0x0A,0xAE,0x61,0x7E,0x8F,
+ 0x01,0xCE,0x94,0x33,0x56,0x07,0xC3,0x04,0xAC,0x29, /* y */
+ 0xE7,0xDE,0xFB,0xD9,0xCA,0x01,0xF5,0x96,0xF9,0x27,
+ 0x22,0x4C,0xDE,0xCF,0x6C,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x01,0x5A,0xAB,0x56,0x1B,0x00,0x54,0x13,
+ 0xCC,0xD4,0xEE,0x99,0xD5 }
};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_233K = {
- NID_X9_62_characteristic_two_field,
- "020000000000000000000000000000000000000004000000000000000001",
- "0",
- "1",
- "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126",
- "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3",
- "008000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", 4,
- NULL, 0,
- "NIST/SECG/WTLS curve over a 233 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+30*6]; }
+ _EC_NIST_CHAR2_233K = {
+ { NID_X9_62_characteristic_two_field,0,30,4 },
+ { /* no seed */
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+
+ 0x01,0x72,0x32,0xBA,0x85,0x3A,0x7E,0x73,0x1A,0xF1, /* x */
+ 0x29,0xF2,0x2F,0xF4,0x14,0x95,0x63,0xA4,0x19,0xC2,
+ 0x6B,0xF5,0x0A,0x4C,0x9D,0x6E,0xEF,0xAD,0x61,0x26,
+
+ 0x01,0xDB,0x53,0x7D,0xEC,0xE8,0x19,0xB7,0xF7,0x0F, /* y */
+ 0x55,0x5A,0x67,0xC4,0x27,0xA8,0xCD,0x9B,0xF1,0x8A,
+ 0xEB,0x9B,0x56,0xE0,0xC1,0x10,0x56,0xFA,0xE6,0xA3,
+
+ 0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x00,0x00,0x00,0x06,0x9D,0x5B,0xB9,0x15,
+ 0xBC,0xD4,0x6E,0xFB,0x1A,0xD5,0xF1,0x73,0xAB,0xDF }
};
-static const unsigned char _EC_NIST_CHAR2_233B_SEED[] = {
- 0x74,0xD5,0x9F,0xF0,0x7F,0x6B,0x41,0x3D,0x0E,0xA1,
- 0x4B,0x34,0x4B,0x20,0xA2,0xDB,0x04,0x9B,0x50,0xC3};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_233B = {
- NID_X9_62_characteristic_two_field,
- "020000000000000000000000000000000000000004000000000000000001",
- "000000000000000000000000000000000000000000000000000000000001",
- "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD",
- "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B",
- "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052",
- "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", 2,
- _EC_NIST_CHAR2_233B_SEED, 20,
- "NIST/SECG/WTLS curve over a 233 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+30*6]; }
+ _EC_NIST_CHAR2_233B = {
+ { NID_X9_62_characteristic_two_field,20,30,2 },
+ { 0x74,0xD5,0x9F,0xF0,0x7F,0x6B,0x41,0x3D,0x0E,0xA1, /* seed */
+ 0x4B,0x34,0x4B,0x20,0xA2,0xDB,0x04,0x9B,0x50,0xC3,
+
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+
+ 0x00,0x66,0x64,0x7E,0xDE,0x6C,0x33,0x2C,0x7F,0x8C, /* b */
+ 0x09,0x23,0xBB,0x58,0x21,0x3B,0x33,0x3B,0x20,0xE9,
+ 0xCE,0x42,0x81,0xFE,0x11,0x5F,0x7D,0x8F,0x90,0xAD,
+
+ 0x00,0xFA,0xC9,0xDF,0xCB,0xAC,0x83,0x13,0xBB,0x21, /* x */
+ 0x39,0xF1,0xBB,0x75,0x5F,0xEF,0x65,0xBC,0x39,0x1F,
+ 0x8B,0x36,0xF8,0xF8,0xEB,0x73,0x71,0xFD,0x55,0x8B,
+
+ 0x01,0x00,0x6A,0x08,0xA4,0x19,0x03,0x35,0x06,0x78, /* y */
+ 0xE5,0x85,0x28,0xBE,0xBF,0x8A,0x0B,0xEF,0xF8,0x67,
+ 0xA7,0xCA,0x36,0x71,0x6F,0x7E,0x01,0xF8,0x10,0x52,
+
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x00,0x00,0x00,0x13,0xE9,0x74,0xE7,0x2F,
+ 0x8A,0x69,0x22,0x03,0x1D,0x26,0x03,0xCF,0xE0,0xD7 }
};
-static const EC_CURVE_DATA _EC_SECG_CHAR2_239K1 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000004000000000000000000000000000000000000001",
- "0",
- "1",
- "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC",
- "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA",
- "2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5", 4,
- NULL, 0,
- "SECG curve over a 239 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+30*6]; }
+ _EC_SECG_CHAR2_239K1 = {
+ { NID_X9_62_characteristic_two_field,0,30,4 },
+ { /* no seed */
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+
+ 0x29,0xA0,0xB6,0xA8,0x87,0xA9,0x83,0xE9,0x73,0x09, /* x */
+ 0x88,0xA6,0x87,0x27,0xA8,0xB2,0xD1,0x26,0xC4,0x4C,
+ 0xC2,0xCC,0x7B,0x2A,0x65,0x55,0x19,0x30,0x35,0xDC,
+
+ 0x76,0x31,0x08,0x04,0xF1,0x2E,0x54,0x9B,0xDB,0x01, /* y */
+ 0x1C,0x10,0x30,0x89,0xE7,0x35,0x10,0xAC,0xB2,0x75,
+ 0xFC,0x31,0x2A,0x5D,0xC6,0xB7,0x65,0x53,0xF0,0xCA,
+
+ 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x00,0x00,0x00,0x5A,0x79,0xFE,0xC6,0x7C,
+ 0xB6,0xE9,0x1F,0x1C,0x1D,0xA8,0x00,0xE4,0x78,0xA5 }
};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_283K = {
- NID_X9_62_characteristic_two_field,
- "080000000000000000000000000000000000000000000000000000000000000000001"
- "0A1",
- "0",
- "1",
- "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492"
- "836",
- "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2"
- "259",
- "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163"
- "C61", 4,
- NULL, 20,
- "NIST/SECG curve over a 283 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+36*6]; }
+ _EC_NIST_CHAR2_283K = {
+ { NID_X9_62_characteristic_two_field,0,36,4 },
+ { /* no seed */
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x10,0xA1,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x05,0x03,0x21,0x3F,0x78,0xCA,0x44,0x88,0x3F,0x1A, /* x */
+ 0x3B,0x81,0x62,0xF1,0x88,0xE5,0x53,0xCD,0x26,0x5F,
+ 0x23,0xC1,0x56,0x7A,0x16,0x87,0x69,0x13,0xB0,0xC2,
+ 0xAC,0x24,0x58,0x49,0x28,0x36,
+ 0x01,0xCC,0xDA,0x38,0x0F,0x1C,0x9E,0x31,0x8D,0x90, /* y */
+ 0xF9,0x5D,0x07,0xE5,0x42,0x6F,0xE8,0x7E,0x45,0xC0,
+ 0xE8,0x18,0x46,0x98,0xE4,0x59,0x62,0x36,0x4E,0x34,
+ 0x11,0x61,0x77,0xDD,0x22,0x59,
+ 0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE9,0xAE,
+ 0x2E,0xD0,0x75,0x77,0x26,0x5D,0xFF,0x7F,0x94,0x45,
+ 0x1E,0x06,0x1E,0x16,0x3C,0x61 }
};
-static const unsigned char _EC_NIST_CHAR2_283B_SEED[] = {
- 0x77,0xE2,0xB0,0x73,0x70,0xEB,0x0F,0x83,0x2A,0x6D,
- 0xD5,0xB6,0x2D,0xFC,0x88,0xCD,0x06,0xBB,0x84,0xBE};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_283B = {
- NID_X9_62_characteristic_two_field,
- "080000000000000000000000000000000000000000000000000000000000000000001"
- "0A1",
- "000000000000000000000000000000000000000000000000000000000000000000000"
- "001",
- "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A"
- "2F5",
- "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12"
- "053",
- "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE811"
- "2F4",
- "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB"
- "307", 2,
- _EC_NIST_CHAR2_283B_SEED, 20,
- "NIST/SECG curve over a 283 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+36*6]; }
+ _EC_NIST_CHAR2_283B = {
+ { NID_X9_62_characteristic_two_field,20,36,2 },
+ { 0x77,0xE2,0xB0,0x73,0x70,0xEB,0x0F,0x83,0x2A,0x6D, /* no seed */
+ 0xD5,0xB6,0x2D,0xFC,0x88,0xCD,0x06,0xBB,0x84,0xBE,
+
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x10,0xA1,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x02,0x7B,0x68,0x0A,0xC8,0xB8,0x59,0x6D,0xA5,0xA4, /* b */
+ 0xAF,0x8A,0x19,0xA0,0x30,0x3F,0xCA,0x97,0xFD,0x76,
+ 0x45,0x30,0x9F,0xA2,0xA5,0x81,0x48,0x5A,0xF6,0x26,
+ 0x3E,0x31,0x3B,0x79,0xA2,0xF5,
+ 0x05,0xF9,0x39,0x25,0x8D,0xB7,0xDD,0x90,0xE1,0x93, /* x */
+ 0x4F,0x8C,0x70,0xB0,0xDF,0xEC,0x2E,0xED,0x25,0xB8,
+ 0x55,0x7E,0xAC,0x9C,0x80,0xE2,0xE1,0x98,0xF8,0xCD,
+ 0xBE,0xCD,0x86,0xB1,0x20,0x53,
+ 0x03,0x67,0x68,0x54,0xFE,0x24,0x14,0x1C,0xB9,0x8F, /* y */
+ 0xE6,0xD4,0xB2,0x0D,0x02,0xB4,0x51,0x6F,0xF7,0x02,
+ 0x35,0x0E,0xDD,0xB0,0x82,0x67,0x79,0xC8,0x13,0xF0,
+ 0xDF,0x45,0xBE,0x81,0x12,0xF4,
+ 0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0x90,
+ 0x39,0x96,0x60,0xFC,0x93,0x8A,0x90,0x16,0x5B,0x04,
+ 0x2A,0x7C,0xEF,0xAD,0xB3,0x07 }
};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_409K = {
- NID_X9_62_characteristic_two_field,
- "020000000000000000000000000000000000000000000000000000000000000000000"
- "00000000000008000000000000000000001",
- "0",
- "1",
- "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C4601"
- "89EB5AAAA62EE222EB1B35540CFE9023746",
- "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6"
- "C42E9C55215AA9CA27A5863EC48D8E0286B",
- "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400"
- "EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", 4,
- NULL, 0,
- "NIST/SECG curve over a 409 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+52*6]; }
+ _EC_NIST_CHAR2_409K = {
+ { NID_X9_62_characteristic_two_field,0,52,4 },
+ { /* no seed */
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x01,
+ 0x00,0x60,0xF0,0x5F,0x65,0x8F,0x49,0xC1,0xAD,0x3A, /* x */
+ 0xB1,0x89,0x0F,0x71,0x84,0x21,0x0E,0xFD,0x09,0x87,
+ 0xE3,0x07,0xC8,0x4C,0x27,0xAC,0xCF,0xB8,0xF9,0xF6,
+ 0x7C,0xC2,0xC4,0x60,0x18,0x9E,0xB5,0xAA,0xAA,0x62,
+ 0xEE,0x22,0x2E,0xB1,0xB3,0x55,0x40,0xCF,0xE9,0x02,
+ 0x37,0x46,
+ 0x01,0xE3,0x69,0x05,0x0B,0x7C,0x4E,0x42,0xAC,0xBA, /* y */
+ 0x1D,0xAC,0xBF,0x04,0x29,0x9C,0x34,0x60,0x78,0x2F,
+ 0x91,0x8E,0xA4,0x27,0xE6,0x32,0x51,0x65,0xE9,0xEA,
+ 0x10,0xE3,0xDA,0x5F,0x6C,0x42,0xE9,0xC5,0x52,0x15,
+ 0xAA,0x9C,0xA2,0x7A,0x58,0x63,0xEC,0x48,0xD8,0xE0,
+ 0x28,0x6B,
+ 0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0x83,0xB2,
+ 0xD4,0xEA,0x20,0x40,0x0E,0xC4,0x55,0x7D,0x5E,0xD3,
+ 0xE3,0xE7,0xCA,0x5B,0x4B,0x5C,0x83,0xB8,0xE0,0x1E,
+ 0x5F,0xCF }
};
-static const unsigned char _EC_NIST_CHAR2_409B_SEED[] = {
- 0x40,0x99,0xB5,0xA4,0x57,0xF9,0xD6,0x9F,0x79,0x21,
- 0x3D,0x09,0x4C,0x4B,0xCD,0x4D,0x42,0x62,0x21,0x0B};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_409B = {
- NID_X9_62_characteristic_two_field,
- "020000000000000000000000000000000000000000000000000000000000000000000"
- "00000000000008000000000000000000001",
- "000000000000000000000000000000000000000000000000000000000000000000000"
- "00000000000000000000000000000000001",
- "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A19"
- "7B272822F6CD57A55AA4F50AE317B13545F",
- "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255"
- "A868A1180515603AEAB60794E54BB7996A7",
- "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514"
- "F1FDF4B4F40D2181B3681C364BA0273C706",
- "010000000000000000000000000000000000000000000000000001E2AAD6A612F3330"
- "7BE5FA47C3C9E052F838164CD37D9A21173", 2,
- _EC_NIST_CHAR2_409B_SEED, 20,
- "NIST/SECG curve over a 409 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+52*6]; }
+ _EC_NIST_CHAR2_409B = {
+ { NID_X9_62_characteristic_two_field,20,52,2 },
+ { 0x40,0x99,0xB5,0xA4,0x57,0xF9,0xD6,0x9F,0x79,0x21, /* seed */
+ 0x3D,0x09,0x4C,0x4B,0xCD,0x4D,0x42,0x62,0x21,0x0B,
+
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x01,
+ 0x00,0x21,0xA5,0xC2,0xC8,0xEE,0x9F,0xEB,0x5C,0x4B, /* b */
+ 0x9A,0x75,0x3B,0x7B,0x47,0x6B,0x7F,0xD6,0x42,0x2E,
+ 0xF1,0xF3,0xDD,0x67,0x47,0x61,0xFA,0x99,0xD6,0xAC,
+ 0x27,0xC8,0xA9,0xA1,0x97,0xB2,0x72,0x82,0x2F,0x6C,
+ 0xD5,0x7A,0x55,0xAA,0x4F,0x50,0xAE,0x31,0x7B,0x13,
+ 0x54,0x5F,
+ 0x01,0x5D,0x48,0x60,0xD0,0x88,0xDD,0xB3,0x49,0x6B, /* x */
+ 0x0C,0x60,0x64,0x75,0x62,0x60,0x44,0x1C,0xDE,0x4A,
+ 0xF1,0x77,0x1D,0x4D,0xB0,0x1F,0xFE,0x5B,0x34,0xE5,
+ 0x97,0x03,0xDC,0x25,0x5A,0x86,0x8A,0x11,0x80,0x51,
+ 0x56,0x03,0xAE,0xAB,0x60,0x79,0x4E,0x54,0xBB,0x79,
+ 0x96,0xA7,
+ 0x00,0x61,0xB1,0xCF,0xAB,0x6B,0xE5,0xF3,0x2B,0xBF, /* y */
+ 0xA7,0x83,0x24,0xED,0x10,0x6A,0x76,0x36,0xB9,0xC5,
+ 0xA7,0xBD,0x19,0x8D,0x01,0x58,0xAA,0x4F,0x54,0x88,
+ 0xD0,0x8F,0x38,0x51,0x4F,0x1F,0xDF,0x4B,0x4F,0x40,
+ 0xD2,0x18,0x1B,0x36,0x81,0xC3,0x64,0xBA,0x02,0x73,
+ 0xC7,0x06,
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xE2,0xAA,0xD6,
+ 0xA6,0x12,0xF3,0x33,0x07,0xBE,0x5F,0xA4,0x7C,0x3C,
+ 0x9E,0x05,0x2F,0x83,0x81,0x64,0xCD,0x37,0xD9,0xA2,
+ 0x11,0x73 }
};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_571K = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000000000000000000000000000"
- "000000000000000000000000000000000000000000000000000000000000000000000"
- "00425",
- "0",
- "1",
- "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA443709"
- "58493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A0"
- "1C8972",
- "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D497"
- "9C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143E"
- "F1C7A3",
- "020000000000000000000000000000000000000000000000000000000000000000000"
- "000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F63"
- "7C1001", 4,
- NULL, 0,
- "NIST/SECG curve over a 571 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+72*6]; }
+ _EC_NIST_CHAR2_571K = {
+ { NID_X9_62_characteristic_two_field,0,72,4 },
+ { /* no seed */
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x04,0x25,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x01,
+ 0x02,0x6E,0xB7,0xA8,0x59,0x92,0x3F,0xBC,0x82,0x18, /* x */
+ 0x96,0x31,0xF8,0x10,0x3F,0xE4,0xAC,0x9C,0xA2,0x97,
+ 0x00,0x12,0xD5,0xD4,0x60,0x24,0x80,0x48,0x01,0x84,
+ 0x1C,0xA4,0x43,0x70,0x95,0x84,0x93,0xB2,0x05,0xE6,
+ 0x47,0xDA,0x30,0x4D,0xB4,0xCE,0xB0,0x8C,0xBB,0xD1,
+ 0xBA,0x39,0x49,0x47,0x76,0xFB,0x98,0x8B,0x47,0x17,
+ 0x4D,0xCA,0x88,0xC7,0xE2,0x94,0x52,0x83,0xA0,0x1C,
+ 0x89,0x72,
+ 0x03,0x49,0xDC,0x80,0x7F,0x4F,0xBF,0x37,0x4F,0x4A, /* y */
+ 0xEA,0xDE,0x3B,0xCA,0x95,0x31,0x4D,0xD5,0x8C,0xEC,
+ 0x9F,0x30,0x7A,0x54,0xFF,0xC6,0x1E,0xFC,0x00,0x6D,
+ 0x8A,0x2C,0x9D,0x49,0x79,0xC0,0xAC,0x44,0xAE,0xA7,
+ 0x4F,0xBE,0xBB,0xB9,0xF7,0x72,0xAE,0xDC,0xB6,0x20,
+ 0xB0,0x1A,0x7B,0xA7,0xAF,0x1B,0x32,0x04,0x30,0xC8,
+ 0x59,0x19,0x84,0xF6,0x01,0xCD,0x4C,0x14,0x3E,0xF1,
+ 0xC7,0xA3,
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x18,0x50,0xE1,
+ 0xF1,0x9A,0x63,0xE4,0xB3,0x91,0xA8,0xDB,0x91,0x7F,
+ 0x41,0x38,0xB6,0x30,0xD8,0x4B,0xE5,0xD6,0x39,0x38,
+ 0x1E,0x91,0xDE,0xB4,0x5C,0xFE,0x77,0x8F,0x63,0x7C,
+ 0x10,0x01 }
};
-static const unsigned char _EC_NIST_CHAR2_571B_SEED[] = {
- 0x2A,0xA0,0x58,0xF7,0x3A,0x0E,0x33,0xAB,0x48,0x6B,
- 0x0F,0x61,0x04,0x10,0xC5,0x3A,0x7F,0x13,0x23,0x10};
-static const EC_CURVE_DATA _EC_NIST_CHAR2_571B = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000000000000000000000000000"
- "000000000000000000000000000000000000000000000000000000000000000000000"
- "00425",
- "000000000000000000000000000000000000000000000000000000000000000000000"
- "000000000000000000000000000000000000000000000000000000000000000000000"
- "000001",
- "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFA"
- "BBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F29"
- "55727A",
- "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53"
- "950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8E"
- "EC2D19",
- "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423"
- "E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B"
- "8AC15B",
- "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
- "FFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2F"
- "E84E47", 2,
- _EC_NIST_CHAR2_571B_SEED, 20,
- "NIST/SECG curve over a 571 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+72*6]; }
+ _EC_NIST_CHAR2_571B = {
+ { NID_X9_62_characteristic_two_field,20,72,2 },
+ { 0x2A,0xA0,0x58,0xF7,0x3A,0x0E,0x33,0xAB,0x48,0x6B, /* seed */
+ 0x0F,0x61,0x04,0x10,0xC5,0x3A,0x7F,0x13,0x23,0x10,
+
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x04,0x25,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x01,
+ 0x02,0xF4,0x0E,0x7E,0x22,0x21,0xF2,0x95,0xDE,0x29, /* b */
+ 0x71,0x17,0xB7,0xF3,0xD6,0x2F,0x5C,0x6A,0x97,0xFF,
+ 0xCB,0x8C,0xEF,0xF1,0xCD,0x6B,0xA8,0xCE,0x4A,0x9A,
+ 0x18,0xAD,0x84,0xFF,0xAB,0xBD,0x8E,0xFA,0x59,0x33,
+ 0x2B,0xE7,0xAD,0x67,0x56,0xA6,0x6E,0x29,0x4A,0xFD,
+ 0x18,0x5A,0x78,0xFF,0x12,0xAA,0x52,0x0E,0x4D,0xE7,
+ 0x39,0xBA,0xCA,0x0C,0x7F,0xFE,0xFF,0x7F,0x29,0x55,
+ 0x72,0x7A,
+ 0x03,0x03,0x00,0x1D,0x34,0xB8,0x56,0x29,0x6C,0x16, /* x */
+ 0xC0,0xD4,0x0D,0x3C,0xD7,0x75,0x0A,0x93,0xD1,0xD2,
+ 0x95,0x5F,0xA8,0x0A,0xA5,0xF4,0x0F,0xC8,0xDB,0x7B,
+ 0x2A,0xBD,0xBD,0xE5,0x39,0x50,0xF4,0xC0,0xD2,0x93,
+ 0xCD,0xD7,0x11,0xA3,0x5B,0x67,0xFB,0x14,0x99,0xAE,
+ 0x60,0x03,0x86,0x14,0xF1,0x39,0x4A,0xBF,0xA3,0xB4,
+ 0xC8,0x50,0xD9,0x27,0xE1,0xE7,0x76,0x9C,0x8E,0xEC,
+ 0x2D,0x19,
+ 0x03,0x7B,0xF2,0x73,0x42,0xDA,0x63,0x9B,0x6D,0xCC, /* y */
+ 0xFF,0xFE,0xB7,0x3D,0x69,0xD7,0x8C,0x6C,0x27,0xA6,
+ 0x00,0x9C,0xBB,0xCA,0x19,0x80,0xF8,0x53,0x39,0x21,
+ 0xE8,0xA6,0x84,0x42,0x3E,0x43,0xBA,0xB0,0x8A,0x57,
+ 0x62,0x91,0xAF,0x8F,0x46,0x1B,0xB2,0xA8,0xB3,0x53,
+ 0x1D,0x2F,0x04,0x85,0xC1,0x9B,0x16,0xE2,0xF1,0x51,
+ 0x6E,0x23,0xDD,0x3C,0x1A,0x48,0x27,0xAF,0x1B,0x8A,
+ 0xC1,0x5B,
+ 0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6,0x61,0xCE,0x18,
+ 0xFF,0x55,0x98,0x73,0x08,0x05,0x9B,0x18,0x68,0x23,
+ 0x85,0x1E,0xC7,0xDD,0x9C,0xA1,0x16,0x1D,0xE9,0x3D,
+ 0x51,0x74,0xD6,0x6E,0x83,0x82,0xE9,0xBB,0x2F,0xE8,
+ 0x4E,0x47 }
};
-static const unsigned char _EC_X9_62_CHAR2_163V1_SEED[] = {
- 0xD2,0xC0,0xFB,0x15,0x76,0x08,0x60,0xDE,0xF1,0xEE,
- 0xF4,0xD6,0x96,0xE6,0x76,0x87,0x56,0x15,0x17,0x54};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_163V1 = {
- NID_X9_62_characteristic_two_field,
- "080000000000000000000000000000000000000107",
- "072546B5435234A422E0789675F432C89435DE5242",
- "00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9",
- "07AF69989546103D79329FCC3D74880F33BBE803CB",
- "01EC23211B5966ADEA1D3F87F7EA5848AEF0B7CA9F",
- "0400000000000000000001E60FC8821CC74DAEAFC1", 2,
- _EC_X9_62_CHAR2_163V1_SEED, 20,
- "X9.62 curve over a 163 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+21*6]; }
+ _EC_X9_62_CHAR2_163V1 = {
+ { NID_X9_62_characteristic_two_field,20,21,2 },
+ { 0xD2,0xC0,0xFB,0x15,0x76,0x08,0x60,0xDE,0xF1,0xEE,
+ 0xF4,0xD6,0x96,0xE6,0x76,0x87,0x56,0x15,0x17,0x54, /* seed */
+
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x07,
+ 0x07,0x25,0x46,0xB5,0x43,0x52,0x34,0xA4,0x22,0xE0, /* a */
+ 0x78,0x96,0x75,0xF4,0x32,0xC8,0x94,0x35,0xDE,0x52,
+ 0x42,
+ 0x00,0xC9,0x51,0x7D,0x06,0xD5,0x24,0x0D,0x3C,0xFF, /* b */
+ 0x38,0xC7,0x4B,0x20,0xB6,0xCD,0x4D,0x6F,0x9D,0xD4,
+ 0xD9,
+ 0x07,0xAF,0x69,0x98,0x95,0x46,0x10,0x3D,0x79,0x32, /* x */
+ 0x9F,0xCC,0x3D,0x74,0x88,0x0F,0x33,0xBB,0xE8,0x03,
+ 0xCB,
+ 0x01,0xEC,0x23,0x21,0x1B,0x59,0x66,0xAD,0xEA,0x1D, /* y */
+ 0x3F,0x87,0xF7,0xEA,0x58,0x48,0xAE,0xF0,0xB7,0xCA,
+ 0x9F,
+ 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x01,0xE6,0x0F,0xC8,0x82,0x1C,0xC7,0x4D,0xAE,0xAF,
+ 0xC1 }
};
-static const unsigned char _EC_X9_62_CHAR2_163V2_SEED[] = {
- 0x53,0x81,0x4C,0x05,0x0D,0x44,0xD6,0x96,0xE6,0x76,
- 0x87,0x56,0x15,0x17,0x58,0x0C,0xA4,0xE2,0x9F,0xFD};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_163V2 = {
- NID_X9_62_characteristic_two_field,
- "080000000000000000000000000000000000000107",
- "0108B39E77C4B108BED981ED0E890E117C511CF072",
- "0667ACEB38AF4E488C407433FFAE4F1C811638DF20",
- "0024266E4EB5106D0A964D92C4860E2671DB9B6CC5",
- "079F684DDF6684C5CD258B3890021B2386DFD19FC5",
- "03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 2,
- _EC_X9_62_CHAR2_163V2_SEED, 20,
- "X9.62 curve over a 163 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+21*6]; }
+ _EC_X9_62_CHAR2_163V2 = {
+ { NID_X9_62_characteristic_two_field,20,21,2 },
+ { 0x53,0x81,0x4C,0x05,0x0D,0x44,0xD6,0x96,0xE6,0x76, /* seed */
+ 0x87,0x56,0x15,0x17,0x58,0x0C,0xA4,0xE2,0x9F,0xFD,
+
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x07,
+ 0x01,0x08,0xB3,0x9E,0x77,0xC4,0xB1,0x08,0xBE,0xD9, /* a */
+ 0x81,0xED,0x0E,0x89,0x0E,0x11,0x7C,0x51,0x1C,0xF0,
+ 0x72,
+ 0x06,0x67,0xAC,0xEB,0x38,0xAF,0x4E,0x48,0x8C,0x40, /* b */
+ 0x74,0x33,0xFF,0xAE,0x4F,0x1C,0x81,0x16,0x38,0xDF,
+ 0x20,
+ 0x00,0x24,0x26,0x6E,0x4E,0xB5,0x10,0x6D,0x0A,0x96, /* x */
+ 0x4D,0x92,0xC4,0x86,0x0E,0x26,0x71,0xDB,0x9B,0x6C,
+ 0xC5,
+ 0x07,0x9F,0x68,0x4D,0xDF,0x66,0x84,0xC5,0xCD,0x25, /* y */
+ 0x8B,0x38,0x90,0x02,0x1B,0x23,0x86,0xDF,0xD1,0x9F,
+ 0xC5,
+ 0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFD,0xF6,0x4D,0xE1,0x15,0x1A,0xDB,0xB7,0x8F,0x10,
+ 0xA7 }
};
-static const unsigned char _EC_X9_62_CHAR2_163V3_SEED[] = {
- 0x50,0xCB,0xF1,0xD9,0x5C,0xA9,0x4D,0x69,0x6E,0x67,
- 0x68,0x75,0x61,0x51,0x75,0xF1,0x6A,0x36,0xA3,0xB8};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_163V3 = {
- NID_X9_62_characteristic_two_field,
- "080000000000000000000000000000000000000107",
- "07A526C63D3E25A256A007699F5447E32AE456B50E",
- "03F7061798EB99E238FD6F1BF95B48FEEB4854252B",
- "02F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB",
- "05B935590C155E17EA48EB3FF3718B893DF59A05D0",
- "03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 2,
- _EC_X9_62_CHAR2_163V3_SEED, 20,
- "X9.62 curve over a 163 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+21*6]; }
+ _EC_X9_62_CHAR2_163V3 = {
+ { NID_X9_62_characteristic_two_field,20,21,2 },
+ { 0x50,0xCB,0xF1,0xD9,0x5C,0xA9,0x4D,0x69,0x6E,0x67, /* seed */
+ 0x68,0x75,0x61,0x51,0x75,0xF1,0x6A,0x36,0xA3,0xB8,
+
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0x07,
+ 0x07,0xA5,0x26,0xC6,0x3D,0x3E,0x25,0xA2,0x56,0xA0, /* a */
+ 0x07,0x69,0x9F,0x54,0x47,0xE3,0x2A,0xE4,0x56,0xB5,
+ 0x0E,
+ 0x03,0xF7,0x06,0x17,0x98,0xEB,0x99,0xE2,0x38,0xFD, /* b */
+ 0x6F,0x1B,0xF9,0x5B,0x48,0xFE,0xEB,0x48,0x54,0x25,
+ 0x2B,
+ 0x02,0xF9,0xF8,0x7B,0x7C,0x57,0x4D,0x0B,0xDE,0xCF, /* x */
+ 0x8A,0x22,0xE6,0x52,0x47,0x75,0xF9,0x8C,0xDE,0xBD,
+ 0xCB,
+ 0x05,0xB9,0x35,0x59,0x0C,0x15,0x5E,0x17,0xEA,0x48, /* y */
+ 0xEB,0x3F,0xF3,0x71,0x8B,0x89,0x3D,0xF5,0x9A,0x05,
+ 0xD0,
+ 0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFE,0x1A,0xEE,0x14,0x0F,0x11,0x0A,0xFF,0x96,0x13,
+ 0x09 }
};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_176V1 = {
- NID_X9_62_characteristic_two_field,
- "0100000000000000000000000000000000080000000007",
- "E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B",
- "5DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2",
- "8D16C2866798B600F9F08BB4A8E860F3298CE04A5798",
- "6FA4539C2DADDDD6BAB5167D61B436E1D92BB16A562C",
- "00010092537397ECA4F6145799D62B0A19CE06FE26AD", 0xFF6E,
- NULL, 0,
- "X9.62 curve over a 176 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+23*6]; }
+ _EC_X9_62_CHAR2_176V1 = {
+ { NID_X9_62_characteristic_two_field,0,23,0xFF6E },
+ { /* no seed */
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,
+ 0x00,0x00,0x07,
+ 0x00,0xE4,0xE6,0xDB,0x29,0x95,0x06,0x5C,0x40,0x7D, /* a */
+ 0x9D,0x39,0xB8,0xD0,0x96,0x7B,0x96,0x70,0x4B,0xA8,
+ 0xE9,0xC9,0x0B,
+ 0x00,0x5D,0xDA,0x47,0x0A,0xBE,0x64,0x14,0xDE,0x8E, /* b */
+ 0xC1,0x33,0xAE,0x28,0xE9,0xBB,0xD7,0xFC,0xEC,0x0A,
+ 0xE0,0xFF,0xF2,
+ 0x00,0x8D,0x16,0xC2,0x86,0x67,0x98,0xB6,0x00,0xF9, /* x */
+ 0xF0,0x8B,0xB4,0xA8,0xE8,0x60,0xF3,0x29,0x8C,0xE0,
+ 0x4A,0x57,0x98,
+ 0x00,0x6F,0xA4,0x53,0x9C,0x2D,0xAD,0xDD,0xD6,0xBA, /* y */
+ 0xB5,0x16,0x7D,0x61,0xB4,0x36,0xE1,0xD9,0x2B,0xB1,
+ 0x6A,0x56,0x2C,
+ 0x00,0x00,0x01,0x00,0x92,0x53,0x73,0x97,0xEC,0xA4, /* order */
+ 0xF6,0x14,0x57,0x99,0xD6,0x2B,0x0A,0x19,0xCE,0x06,
+ 0xFE,0x26,0xAD }
};
-static const unsigned char _EC_X9_62_CHAR2_191V1_SEED[] = {
- 0x4E,0x13,0xCA,0x54,0x27,0x44,0xD6,0x96,0xE6,0x76,
- 0x87,0x56,0x15,0x17,0x55,0x2F,0x27,0x9A,0x8C,0x84};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_191V1 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000201",
- "2866537B676752636A68F56554E12640276B649EF7526267",
- "2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC",
- "36B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D",
- "765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB",
- "40000000000000000000000004A20E90C39067C893BBB9A5", 2,
- _EC_X9_62_CHAR2_191V1_SEED, 20,
- "X9.62 curve over a 191 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+24*6]; }
+ _EC_X9_62_CHAR2_191V1 = {
+ { NID_X9_62_characteristic_two_field,20,24,2 },
+ { 0x4E,0x13,0xCA,0x54,0x27,0x44,0xD6,0x96,0xE6,0x76, /* seed */
+ 0x87,0x56,0x15,0x17,0x55,0x2F,0x27,0x9A,0x8C,0x84,
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x02,0x01,
+ 0x28,0x66,0x53,0x7B,0x67,0x67,0x52,0x63,0x6A,0x68, /* a */
+ 0xF5,0x65,0x54,0xE1,0x26,0x40,0x27,0x6B,0x64,0x9E,
+ 0xF7,0x52,0x62,0x67,
+ 0x2E,0x45,0xEF,0x57,0x1F,0x00,0x78,0x6F,0x67,0xB0, /* b */
+ 0x08,0x1B,0x94,0x95,0xA3,0xD9,0x54,0x62,0xF5,0xDE,
+ 0x0A,0xA1,0x85,0xEC,
+ 0x36,0xB3,0xDA,0xF8,0xA2,0x32,0x06,0xF9,0xC4,0xF2, /* x */
+ 0x99,0xD7,0xB2,0x1A,0x9C,0x36,0x91,0x37,0xF2,0xC8,
+ 0x4A,0xE1,0xAA,0x0D,
+ 0x76,0x5B,0xE7,0x34,0x33,0xB3,0xF9,0x5E,0x33,0x29, /* y */
+ 0x32,0xE7,0x0E,0xA2,0x45,0xCA,0x24,0x18,0xEA,0x0E,
+ 0xF9,0x80,0x18,0xFB,
+ 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x04,0xA2,0x0E,0x90,0xC3,0x90,0x67,0xC8,
+ 0x93,0xBB,0xB9,0xA5 }
};
-static const unsigned char _EC_X9_62_CHAR2_191V2_SEED[] = {
- 0x08,0x71,0xEF,0x2F,0xEF,0x24,0xD6,0x96,0xE6,0x76,
- 0x87,0x56,0x15,0x17,0x58,0xBE,0xE0,0xD9,0x5C,0x15};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_191V2 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000201",
- "401028774D7777C7B7666D1366EA432071274F89FF01E718",
- "0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01",
- "3809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10",
- "17434386626D14F3DBF01760D9213A3E1CF37AEC437D668A",
- "20000000000000000000000050508CB89F652824E06B8173", 4,
- _EC_X9_62_CHAR2_191V2_SEED, 20,
- "X9.62 curve over a 191 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+24*6]; }
+ _EC_X9_62_CHAR2_191V2 = {
+ { NID_X9_62_characteristic_two_field,20,24,4 },
+ { 0x08,0x71,0xEF,0x2F,0xEF,0x24,0xD6,0x96,0xE6,0x76, /* seed */
+ 0x87,0x56,0x15,0x17,0x58,0xBE,0xE0,0xD9,0x5C,0x15,
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x02,0x01,
+ 0x40,0x10,0x28,0x77,0x4D,0x77,0x77,0xC7,0xB7,0x66, /* a */
+ 0x6D,0x13,0x66,0xEA,0x43,0x20,0x71,0x27,0x4F,0x89,
+ 0xFF,0x01,0xE7,0x18,
+ 0x06,0x20,0x04,0x8D,0x28,0xBC,0xBD,0x03,0xB6,0x24, /* b */
+ 0x9C,0x99,0x18,0x2B,0x7C,0x8C,0xD1,0x97,0x00,0xC3,
+ 0x62,0xC4,0x6A,0x01,
+ 0x38,0x09,0xB2,0xB7,0xCC,0x1B,0x28,0xCC,0x5A,0x87, /* x */
+ 0x92,0x6A,0xAD,0x83,0xFD,0x28,0x78,0x9E,0x81,0xE2,
+ 0xC9,0xE3,0xBF,0x10,
+ 0x17,0x43,0x43,0x86,0x62,0x6D,0x14,0xF3,0xDB,0xF0, /* y */
+ 0x17,0x60,0xD9,0x21,0x3A,0x3E,0x1C,0xF3,0x7A,0xEC,
+ 0x43,0x7D,0x66,0x8A,
+ 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x50,0x50,0x8C,0xB8,0x9F,0x65,0x28,0x24,
+ 0xE0,0x6B,0x81,0x73 }
};
-static const unsigned char _EC_X9_62_CHAR2_191V3_SEED[] = {
- 0xE0,0x53,0x51,0x2D,0xC6,0x84,0xD6,0x96,0xE6,0x76,
- 0x87,0x56,0x15,0x17,0x50,0x67,0xAE,0x78,0x6D,0x1F};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_191V3 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000201",
- "6C01074756099122221056911C77D77E77A777E7E7E77FCB",
- "71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8",
- "375D4CE24FDE434489DE8746E71786015009E66E38A926DD",
- "545A39176196575D985999366E6AD34CE0A77CD7127B06BE",
- "155555555555555555555555610C0B196812BFB6288A3EA3", 6,
- _EC_X9_62_CHAR2_191V3_SEED, 20,
- "X9.62 curve over a 191 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+24*6]; }
+ _EC_X9_62_CHAR2_191V3 = {
+ { NID_X9_62_characteristic_two_field,20,24,6 },
+ { 0xE0,0x53,0x51,0x2D,0xC6,0x84,0xD6,0x96,0xE6,0x76, /* seed */
+ 0x87,0x56,0x15,0x17,0x50,0x67,0xAE,0x78,0x6D,0x1F,
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x02,0x01,
+ 0x6C,0x01,0x07,0x47,0x56,0x09,0x91,0x22,0x22,0x10, /* a */
+ 0x56,0x91,0x1C,0x77,0xD7,0x7E,0x77,0xA7,0x77,0xE7,
+ 0xE7,0xE7,0x7F,0xCB,
+ 0x71,0xFE,0x1A,0xF9,0x26,0xCF,0x84,0x79,0x89,0xEF, /* b */
+ 0xEF,0x8D,0xB4,0x59,0xF6,0x63,0x94,0xD9,0x0F,0x32,
+ 0xAD,0x3F,0x15,0xE8,
+ 0x37,0x5D,0x4C,0xE2,0x4F,0xDE,0x43,0x44,0x89,0xDE, /* x */
+ 0x87,0x46,0xE7,0x17,0x86,0x01,0x50,0x09,0xE6,0x6E,
+ 0x38,0xA9,0x26,0xDD,
+ 0x54,0x5A,0x39,0x17,0x61,0x96,0x57,0x5D,0x98,0x59, /* y */
+ 0x99,0x36,0x6E,0x6A,0xD3,0x4C,0xE0,0xA7,0x7C,0xD7,
+ 0x12,0x7B,0x06,0xBE,
+ 0x15,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, /* order */
+ 0x55,0x55,0x61,0x0C,0x0B,0x19,0x68,0x12,0xBF,0xB6,
+ 0x28,0x8A,0x3E,0xA3 }
};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_208W1 = {
- NID_X9_62_characteristic_two_field,
- "010000000000000000000000000000000800000000000000000007",
- "0000000000000000000000000000000000000000000000000000",
- "C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E",
- "89FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A",
- "0F55B51A06E78E9AC38A035FF520D8B01781BEB1A6BB08617DE3",
- "000101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 0xFE48,
- NULL, 0,
- "X9.62 curve over a 208 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+27*6]; }
+ _EC_X9_62_CHAR2_208W1 = {
+ { NID_X9_62_characteristic_two_field,0,27,0xFE48 },
+ { /* no seed */
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0xC8,0x61,0x9E,0xD4,0x5A,0x62,0xE6,0x21,0x2E, /* b */
+ 0x11,0x60,0x34,0x9E,0x2B,0xFA,0x84,0x44,0x39,0xFA,
+ 0xFC,0x2A,0x3F,0xD1,0x63,0x8F,0x9E,
+ 0x00,0x89,0xFD,0xFB,0xE4,0xAB,0xE1,0x93,0xDF,0x95, /* x */
+ 0x59,0xEC,0xF0,0x7A,0xC0,0xCE,0x78,0x55,0x4E,0x27,
+ 0x84,0xEB,0x8C,0x1E,0xD1,0xA5,0x7A,
+ 0x00,0x0F,0x55,0xB5,0x1A,0x06,0xE7,0x8E,0x9A,0xC3, /* y */
+ 0x8A,0x03,0x5F,0xF5,0x20,0xD8,0xB0,0x17,0x81,0xBE,
+ 0xB1,0xA6,0xBB,0x08,0x61,0x7D,0xE3,
+ 0x00,0x00,0x01,0x01,0xBA,0xF9,0x5C,0x97,0x23,0xC5, /* order */
+ 0x7B,0x6C,0x21,0xDA,0x2E,0xFF,0x2D,0x5E,0xD5,0x88,
+ 0xBD,0xD5,0x71,0x7E,0x21,0x2F,0x9D }
};
-static const unsigned char _EC_X9_62_CHAR2_239V1_SEED[] = {
- 0xD3,0x4B,0x9A,0x4D,0x69,0x6E,0x67,0x68,0x75,0x61,
- 0x51,0x75,0xCA,0x71,0xB9,0x20,0xBF,0xEF,0xB0,0x5D};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_239V1 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000000001000000001",
- "32010857077C5431123A46B808906756F543423E8D27877578125778AC76",
- "790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16",
- "57927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D",
- "61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305",
- "2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 4,
- _EC_X9_62_CHAR2_239V1_SEED, 20,
- "X9.62 curve over a 239 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+30*6]; }
+ _EC_X9_62_CHAR2_239V1 = {
+ { NID_X9_62_characteristic_two_field,20,30,4 },
+ { 0xD3,0x4B,0x9A,0x4D,0x69,0x6E,0x67,0x68,0x75,0x61, /* seed */
+ 0x51,0x75,0xCA,0x71,0xB9,0x20,0xBF,0xEF,0xB0,0x5D,
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,
+
+ 0x32,0x01,0x08,0x57,0x07,0x7C,0x54,0x31,0x12,0x3A, /* a */
+ 0x46,0xB8,0x08,0x90,0x67,0x56,0xF5,0x43,0x42,0x3E,
+ 0x8D,0x27,0x87,0x75,0x78,0x12,0x57,0x78,0xAC,0x76,
+
+ 0x79,0x04,0x08,0xF2,0xEE,0xDA,0xF3,0x92,0xB0,0x12, /* b */
+ 0xED,0xEF,0xB3,0x39,0x2F,0x30,0xF4,0x32,0x7C,0x0C,
+ 0xA3,0xF3,0x1F,0xC3,0x83,0xC4,0x22,0xAA,0x8C,0x16,
+
+ 0x57,0x92,0x70,0x98,0xFA,0x93,0x2E,0x7C,0x0A,0x96, /* x */
+ 0xD3,0xFD,0x5B,0x70,0x6E,0xF7,0xE5,0xF5,0xC1,0x56,
+ 0xE1,0x6B,0x7E,0x7C,0x86,0x03,0x85,0x52,0xE9,0x1D,
+
+ 0x61,0xD8,0xEE,0x50,0x77,0xC3,0x3F,0xEC,0xF6,0xF1, /* y */
+ 0xA1,0x6B,0x26,0x8D,0xE4,0x69,0xC3,0xC7,0x74,0x4E,
+ 0xA9,0xA9,0x71,0x64,0x9F,0xC7,0xA9,0x61,0x63,0x05,
+
+ 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* order */
+ 0x00,0x00,0x00,0x00,0x00,0x0F,0x4D,0x42,0xFF,0xE1,
+ 0x49,0x2A,0x49,0x93,0xF1,0xCA,0xD6,0x66,0xE4,0x47 }
};
-static const unsigned char _EC_X9_62_CHAR2_239V2_SEED[] = {
- 0x2A,0xA6,0x98,0x2F,0xDF,0xA4,0xD6,0x96,0xE6,0x76,
- 0x87,0x56,0x15,0x17,0x5D,0x26,0x67,0x27,0x27,0x7D};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_239V2 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000000001000000001",
- "4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F",
- "5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B",
- "28F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205",
- "5667334C45AFF3B5A03BAD9DD75E2C71A99362567D5453F7FA6E227EC833",
- "1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 6,
- _EC_X9_62_CHAR2_239V2_SEED, 20,
- "X9.62 curve over a 239 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+30*6]; }
+ _EC_X9_62_CHAR2_239V2 = {
+ { NID_X9_62_characteristic_two_field,20,30,6 },
+ { 0x2A,0xA6,0x98,0x2F,0xDF,0xA4,0xD6,0x96,0xE6,0x76, /* seed */
+ 0x87,0x56,0x15,0x17,0x5D,0x26,0x67,0x27,0x27,0x7D,
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,
+
+ 0x42,0x30,0x01,0x77,0x57,0xA7,0x67,0xFA,0xE4,0x23, /* a */
+ 0x98,0x56,0x9B,0x74,0x63,0x25,0xD4,0x53,0x13,0xAF,
+ 0x07,0x66,0x26,0x64,0x79,0xB7,0x56,0x54,0xE6,0x5F,
+
+ 0x50,0x37,0xEA,0x65,0x41,0x96,0xCF,0xF0,0xCD,0x82, /* b */
+ 0xB2,0xC1,0x4A,0x2F,0xCF,0x2E,0x3F,0xF8,0x77,0x52,
+ 0x85,0xB5,0x45,0x72,0x2F,0x03,0xEA,0xCD,0xB7,0x4B,
+
+ 0x28,0xF9,0xD0,0x4E,0x90,0x00,0x69,0xC8,0xDC,0x47, /* x */
+ 0xA0,0x85,0x34,0xFE,0x76,0xD2,0xB9,0x00,0xB7,0xD7,
+ 0xEF,0x31,0xF5,0x70,0x9F,0x20,0x0C,0x4C,0xA2,0x05,
+
+ 0x56,0x67,0x33,0x4C,0x45,0xAF,0xF3,0xB5,0xA0,0x3B, /* y */
+ 0xAD,0x9D,0xD7,0x5E,0x2C,0x71,0xA9,0x93,0x62,0x56,
+ 0x7D,0x54,0x53,0xF7,0xFA,0x6E,0x22,0x7E,0xC8,0x33,
+
+ 0x15,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, /* order */
+ 0x55,0x55,0x55,0x55,0x55,0x3C,0x6F,0x28,0x85,0x25,
+ 0x9C,0x31,0xE3,0xFC,0xDF,0x15,0x46,0x24,0x52,0x2D }
};
-static const unsigned char _EC_X9_62_CHAR2_239V3_SEED[] = {
- 0x9E,0x07,0x6F,0x4D,0x69,0x6E,0x67,0x68,0x75,0x61,
- 0x51,0x75,0xE1,0x1E,0x9F,0xDD,0x77,0xF9,0x20,0x41};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_239V3 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000000001000000001",
- "01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F",
- "6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40",
- "70F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92",
- "2E5A0EAF6E5E1305B9004DCE5C0ED7FE59A35608F33837C816D80B79F461",
- "0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 0xA,
- _EC_X9_62_CHAR2_239V3_SEED, 20,
- "X9.62 curve over a 239 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+30*6]; }
+ _EC_X9_62_CHAR2_239V3 = {
+ { NID_X9_62_characteristic_two_field,20,30,0xA },
+ { 0x9E,0x07,0x6F,0x4D,0x69,0x6E,0x67,0x68,0x75,0x61, /* seed */
+ 0x51,0x75,0xE1,0x1E,0x9F,0xDD,0x77,0xF9,0x20,0x41,
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,
+
+ 0x01,0x23,0x87,0x74,0x66,0x6A,0x67,0x76,0x6D,0x66, /* a */
+ 0x76,0xF7,0x78,0xE6,0x76,0xB6,0x69,0x99,0x17,0x66,
+ 0x66,0xE6,0x87,0x66,0x6D,0x87,0x66,0xC6,0x6A,0x9F,
+
+ 0x6A,0x94,0x19,0x77,0xBA,0x9F,0x6A,0x43,0x51,0x99, /* b */
+ 0xAC,0xFC,0x51,0x06,0x7E,0xD5,0x87,0xF5,0x19,0xC5,
+ 0xEC,0xB5,0x41,0xB8,0xE4,0x41,0x11,0xDE,0x1D,0x40,
+
+ 0x70,0xF6,0xE9,0xD0,0x4D,0x28,0x9C,0x4E,0x89,0x91, /* x */
+ 0x3C,0xE3,0x53,0x0B,0xFD,0xE9,0x03,0x97,0x7D,0x42,
+ 0xB1,0x46,0xD5,0x39,0xBF,0x1B,0xDE,0x4E,0x9C,0x92,
+
+ 0x2E,0x5A,0x0E,0xAF,0x6E,0x5E,0x13,0x05,0xB9,0x00, /* y */
+ 0x4D,0xCE,0x5C,0x0E,0xD7,0xFE,0x59,0xA3,0x56,0x08,
+ 0xF3,0x38,0x37,0xC8,0x16,0xD8,0x0B,0x79,0xF4,0x61,
+
+ 0x0C,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, /* order */
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xAC,0x49,0x12,0xD2,0xD9,
+ 0xDF,0x90,0x3E,0xF9,0x88,0x8B,0x8A,0x0E,0x4C,0xFF }
};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_272W1 = {
- NID_X9_62_characteristic_two_field,
- "010000000000000000000000000000000000000000000000000000010000000000000"
- "B",
- "91A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20",
- "7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7",
- "6108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D",
- "10C7695716851EEF6BA7F6872E6142FBD241B830FF5EFCACECCAB05E02005DDE9D23",
- "000100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521",
- 0xFF06,
- NULL, 0,
- "X9.62 curve over a 272 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+35*6]; }
+ _EC_X9_62_CHAR2_272W1 = {
+ { NID_X9_62_characteristic_two_field,0,35,0xFF06 },
+ { /* no seed */
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x0B,
+ 0x00,0x91,0xA0,0x91,0xF0,0x3B,0x5F,0xBA,0x4A,0xB2, /* a */
+ 0xCC,0xF4,0x9C,0x4E,0xDD,0x22,0x0F,0xB0,0x28,0x71,
+ 0x2D,0x42,0xBE,0x75,0x2B,0x2C,0x40,0x09,0x4D,0xBA,
+ 0xCD,0xB5,0x86,0xFB,0x20,
+ 0x00,0x71,0x67,0xEF,0xC9,0x2B,0xB2,0xE3,0xCE,0x7C, /* b */
+ 0x8A,0xAA,0xFF,0x34,0xE1,0x2A,0x9C,0x55,0x70,0x03,
+ 0xD7,0xC7,0x3A,0x6F,0xAF,0x00,0x3F,0x99,0xF6,0xCC,
+ 0x84,0x82,0xE5,0x40,0xF7,
+ 0x00,0x61,0x08,0xBA,0xBB,0x2C,0xEE,0xBC,0xF7,0x87, /* x */
+ 0x05,0x8A,0x05,0x6C,0xBE,0x0C,0xFE,0x62,0x2D,0x77,
+ 0x23,0xA2,0x89,0xE0,0x8A,0x07,0xAE,0x13,0xEF,0x0D,
+ 0x10,0xD1,0x71,0xDD,0x8D,
+ 0x00,0x10,0xC7,0x69,0x57,0x16,0x85,0x1E,0xEF,0x6B, /* y */
+ 0xA7,0xF6,0x87,0x2E,0x61,0x42,0xFB,0xD2,0x41,0xB8,
+ 0x30,0xFF,0x5E,0xFC,0xAC,0xEC,0xCA,0xB0,0x5E,0x02,
+ 0x00,0x5D,0xDE,0x9D,0x23,
+ 0x00,0x00,0x01,0x00,0xFA,0xF5,0x13,0x54,0xE0,0xE3, /* order */
+ 0x9E,0x48,0x92,0xDF,0x6E,0x31,0x9C,0x72,0xC8,0x16,
+ 0x16,0x03,0xFA,0x45,0xAA,0x7B,0x99,0x8A,0x16,0x7B,
+ 0x8F,0x1E,0x62,0x95,0x21 }
};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_304W1 = {
- NID_X9_62_characteristic_two_field,
- "010000000000000000000000000000000000000000000000000000000000000000000"
- "000000807",
- "FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A039"
- "6C8E681",
- "BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E558"
- "27340BE",
- "197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F7"
- "40A2614",
- "E19FBEB76E0DA171517ECF401B50289BF014103288527A9B416A105E80260B549FDC1"
- "B92C03B",
- "000101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164"
- "443051D", 0xFE2E,
- NULL, 0,
- "X9.62 curve over a 304 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+39*6]; }
+ _EC_X9_62_CHAR2_304W1 = {
+ { NID_X9_62_characteristic_two_field,0,39,0xFE2E },
+ { /* no seed */
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x07,
+ 0x00,0xFD,0x0D,0x69,0x31,0x49,0xA1,0x18,0xF6,0x51, /* a */
+ 0xE6,0xDC,0xE6,0x80,0x20,0x85,0x37,0x7E,0x5F,0x88,
+ 0x2D,0x1B,0x51,0x0B,0x44,0x16,0x00,0x74,0xC1,0x28,
+ 0x80,0x78,0x36,0x5A,0x03,0x96,0xC8,0xE6,0x81,
+ 0x00,0xBD,0xDB,0x97,0xE5,0x55,0xA5,0x0A,0x90,0x8E, /* b */
+ 0x43,0xB0,0x1C,0x79,0x8E,0xA5,0xDA,0xA6,0x78,0x8F,
+ 0x1E,0xA2,0x79,0x4E,0xFC,0xF5,0x71,0x66,0xB8,0xC1,
+ 0x40,0x39,0x60,0x1E,0x55,0x82,0x73,0x40,0xBE,
+ 0x00,0x19,0x7B,0x07,0x84,0x5E,0x9B,0xE2,0xD9,0x6A, /* x */
+ 0xDB,0x0F,0x5F,0x3C,0x7F,0x2C,0xFF,0xBD,0x7A,0x3E,
+ 0xB8,0xB6,0xFE,0xC3,0x5C,0x7F,0xD6,0x7F,0x26,0xDD,
+ 0xF6,0x28,0x5A,0x64,0x4F,0x74,0x0A,0x26,0x14,
+ 0x00,0xE1,0x9F,0xBE,0xB7,0x6E,0x0D,0xA1,0x71,0x51, /* y */
+ 0x7E,0xCF,0x40,0x1B,0x50,0x28,0x9B,0xF0,0x14,0x10,
+ 0x32,0x88,0x52,0x7A,0x9B,0x41,0x6A,0x10,0x5E,0x80,
+ 0x26,0x0B,0x54,0x9F,0xDC,0x1B,0x92,0xC0,0x3B,
+ 0x00,0x00,0x01,0x01,0xD5,0x56,0x57,0x2A,0xAB,0xAC, /* order */
+ 0x80,0x01,0x01,0xD5,0x56,0x57,0x2A,0xAB,0xAC,0x80,
+ 0x01,0x02,0x2D,0x5C,0x91,0xDD,0x17,0x3F,0x8F,0xB5,
+ 0x61,0xDA,0x68,0x99,0x16,0x44,0x43,0x05,0x1D }
};
-static const unsigned char _EC_X9_62_CHAR2_359V1_SEED[] = {
- 0x2B,0x35,0x49,0x20,0xB7,0x24,0xD6,0x96,0xE6,0x76,
- 0x87,0x56,0x15,0x17,0x58,0x5B,0xA1,0x33,0x2D,0xC6};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_359V1 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000000000000000000000000000"
- "000100000000000000001",
- "5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05"
- "656FB549016A96656A557",
- "2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC34562608968"
- "7742B6329E70680231988",
- "3C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE9"
- "8E8E707C07A2239B1B097",
- "53D7E08529547048121E9C95F3791DD804963948F34FAE7BF44EA82365DC7868FE57E"
- "4AE2DE211305A407104BD",
- "01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB9"
- "64FE7719E74F490758D3B", 0x4C,
- _EC_X9_62_CHAR2_359V1_SEED, 20,
- "X9.62 curve over a 359 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[20+45*6]; }
+ _EC_X9_62_CHAR2_359V1 = {
+ { NID_X9_62_characteristic_two_field,20,45,0x4C },
+ { 0x2B,0x35,0x49,0x20,0xB7,0x24,0xD6,0x96,0xE6,0x76, /* seed */
+ 0x87,0x56,0x15,0x17,0x58,0x5B,0xA1,0x33,0x2D,0xC6,
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x01,
+ 0x56,0x67,0x67,0x6A,0x65,0x4B,0x20,0x75,0x4F,0x35, /* a */
+ 0x6E,0xA9,0x20,0x17,0xD9,0x46,0x56,0x7C,0x46,0x67,
+ 0x55,0x56,0xF1,0x95,0x56,0xA0,0x46,0x16,0xB5,0x67,
+ 0xD2,0x23,0xA5,0xE0,0x56,0x56,0xFB,0x54,0x90,0x16,
+ 0xA9,0x66,0x56,0xA5,0x57,
+ 0x24,0x72,0xE2,0xD0,0x19,0x7C,0x49,0x36,0x3F,0x1F, /* b */
+ 0xE7,0xF5,0xB6,0xDB,0x07,0x5D,0x52,0xB6,0x94,0x7D,
+ 0x13,0x5D,0x8C,0xA4,0x45,0x80,0x5D,0x39,0xBC,0x34,
+ 0x56,0x26,0x08,0x96,0x87,0x74,0x2B,0x63,0x29,0xE7,
+ 0x06,0x80,0x23,0x19,0x88,
+ 0x3C,0x25,0x8E,0xF3,0x04,0x77,0x67,0xE7,0xED,0xE0, /* x */
+ 0xF1,0xFD,0xAA,0x79,0xDA,0xEE,0x38,0x41,0x36,0x6A,
+ 0x13,0x2E,0x16,0x3A,0xCE,0xD4,0xED,0x24,0x01,0xDF,
+ 0x9C,0x6B,0xDC,0xDE,0x98,0xE8,0xE7,0x07,0xC0,0x7A,
+ 0x22,0x39,0xB1,0xB0,0x97,
+ 0x53,0xD7,0xE0,0x85,0x29,0x54,0x70,0x48,0x12,0x1E, /* y */
+ 0x9C,0x95,0xF3,0x79,0x1D,0xD8,0x04,0x96,0x39,0x48,
+ 0xF3,0x4F,0xAE,0x7B,0xF4,0x4E,0xA8,0x23,0x65,0xDC,
+ 0x78,0x68,0xFE,0x57,0xE4,0xAE,0x2D,0xE2,0x11,0x30,
+ 0x5A,0x40,0x71,0x04,0xBD,
+ 0x01,0xAF,0x28,0x6B,0xCA,0x1A,0xF2,0x86,0xBC,0xA1, /* order */
+ 0xAF,0x28,0x6B,0xCA,0x1A,0xF2,0x86,0xBC,0xA1,0xAF,
+ 0x28,0x6B,0xC9,0xFB,0x8F,0x6B,0x85,0xC5,0x56,0x89,
+ 0x2C,0x20,0xA7,0xEB,0x96,0x4F,0xE7,0x71,0x9E,0x74,
+ 0xF4,0x90,0x75,0x8D,0x3B }
};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_368W1 = {
- NID_X9_62_characteristic_two_field,
- "010000000000000000000000000000000000000000000000000000000000000000000"
- "0002000000000000000000007",
- "E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62"
- "F0AB7519CCD2A1A906AE30D",
- "FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112"
- "D84D164F444F8F74786046A",
- "1085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E78"
- "9E927BE216F02E1FB136A5F",
- "7B3EB1BDDCBA62D5D8B2059B525797FC73822C59059C623A45FF3843CEE8F87CD1855"
- "ADAA81E2A0750B80FDA2310",
- "00010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E90"
- "9AE40A6F131E9CFCE5BD967", 0xFF70,
- NULL, 0,
- "X9.62 curve over a 368 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+47*6]; }
+ _EC_X9_62_CHAR2_368W1 = {
+ { NID_X9_62_characteristic_two_field,0,47,0xFF70 },
+ { /* no seed */
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,
+ 0x00,0xE0,0xD2,0xEE,0x25,0x09,0x52,0x06,0xF5,0xE2, /* a */
+ 0xA4,0xF9,0xED,0x22,0x9F,0x1F,0x25,0x6E,0x79,0xA0,
+ 0xE2,0xB4,0x55,0x97,0x0D,0x8D,0x0D,0x86,0x5B,0xD9,
+ 0x47,0x78,0xC5,0x76,0xD6,0x2F,0x0A,0xB7,0x51,0x9C,
+ 0xCD,0x2A,0x1A,0x90,0x6A,0xE3,0x0D,
+ 0x00,0xFC,0x12,0x17,0xD4,0x32,0x0A,0x90,0x45,0x2C, /* b */
+ 0x76,0x0A,0x58,0xED,0xCD,0x30,0xC8,0xDD,0x06,0x9B,
+ 0x3C,0x34,0x45,0x38,0x37,0xA3,0x4E,0xD5,0x0C,0xB5,
+ 0x49,0x17,0xE1,0xC2,0x11,0x2D,0x84,0xD1,0x64,0xF4,
+ 0x44,0xF8,0xF7,0x47,0x86,0x04,0x6A,
+ 0x00,0x10,0x85,0xE2,0x75,0x53,0x81,0xDC,0xCC,0xE3, /* x */
+ 0xC1,0x55,0x7A,0xFA,0x10,0xC2,0xF0,0xC0,0xC2,0x82,
+ 0x56,0x46,0xC5,0xB3,0x4A,0x39,0x4C,0xBC,0xFA,0x8B,
+ 0xC1,0x6B,0x22,0xE7,0xE7,0x89,0xE9,0x27,0xBE,0x21,
+ 0x6F,0x02,0xE1,0xFB,0x13,0x6A,0x5F,
+ 0x00,0x7B,0x3E,0xB1,0xBD,0xDC,0xBA,0x62,0xD5,0xD8, /* y */
+ 0xB2,0x05,0x9B,0x52,0x57,0x97,0xFC,0x73,0x82,0x2C,
+ 0x59,0x05,0x9C,0x62,0x3A,0x45,0xFF,0x38,0x43,0xCE,
+ 0xE8,0xF8,0x7C,0xD1,0x85,0x5A,0xDA,0xA8,0x1E,0x2A,
+ 0x07,0x50,0xB8,0x0F,0xDA,0x23,0x10,
+ 0x00,0x00,0x01,0x00,0x90,0x51,0x2D,0xA9,0xAF,0x72, /* order */
+ 0xB0,0x83,0x49,0xD9,0x8A,0x5D,0xD4,0xC7,0xB0,0x53,
+ 0x2E,0xCA,0x51,0xCE,0x03,0xE2,0xD1,0x0F,0x3B,0x7A,
+ 0xC5,0x79,0xBD,0x87,0xE9,0x09,0xAE,0x40,0xA6,0xF1,
+ 0x31,0xE9,0xCF,0xCE,0x5B,0xD9,0x67 }
};
-static const EC_CURVE_DATA _EC_X9_62_CHAR2_431R1 = {
- NID_X9_62_characteristic_two_field,
- "800000000000000000000000000000000000000000000000000000000000000000000"
- "000000001000000000000000000000000000001",
- "1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0E"
- "B9906D0957F6C6FEACD615468DF104DE296CD8F",
- "10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B6"
- "26D4E50A8DD731B107A9962381FB5D807BF2618",
- "120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C2"
- "1E7C5EFE965361F6C2999C0C247B0DBD70CE6B7",
- "20D0AF8903A96F8D5FA2C255745D3C451B302C9346D9B7E485E7BCE41F6B591F3E8F6"
- "ADDCBB0BC4C2F947A7DE1A89B625D6A598B3760",
- "0340340340340340340340340340340340340340340340340340340323C313FAB5058"
- "9703B5EC68D3587FEC60D161CC149C1AD4A91", 0x2760,
- NULL, 0,
- "X9.62 curve over a 431 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+54*6]; }
+ _EC_X9_62_CHAR2_431R1 = {
+ { NID_X9_62_characteristic_two_field,0,54,0x2760 },
+ { /* no seed */
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x01,
+ 0x1A,0x82,0x7E,0xF0,0x0D,0xD6,0xFC,0x0E,0x23,0x4C, /* a */
+ 0xAF,0x04,0x6C,0x6A,0x5D,0x8A,0x85,0x39,0x5B,0x23,
+ 0x6C,0xC4,0xAD,0x2C,0xF3,0x2A,0x0C,0xAD,0xBD,0xC9,
+ 0xDD,0xF6,0x20,0xB0,0xEB,0x99,0x06,0xD0,0x95,0x7F,
+ 0x6C,0x6F,0xEA,0xCD,0x61,0x54,0x68,0xDF,0x10,0x4D,
+ 0xE2,0x96,0xCD,0x8F,
+ 0x10,0xD9,0xB4,0xA3,0xD9,0x04,0x7D,0x8B,0x15,0x43, /* b */
+ 0x59,0xAB,0xFB,0x1B,0x7F,0x54,0x85,0xB0,0x4C,0xEB,
+ 0x86,0x82,0x37,0xDD,0xC9,0xDE,0xDA,0x98,0x2A,0x67,
+ 0x9A,0x5A,0x91,0x9B,0x62,0x6D,0x4E,0x50,0xA8,0xDD,
+ 0x73,0x1B,0x10,0x7A,0x99,0x62,0x38,0x1F,0xB5,0xD8,
+ 0x07,0xBF,0x26,0x18,
+ 0x12,0x0F,0xC0,0x5D,0x3C,0x67,0xA9,0x9D,0xE1,0x61, /* x */
+ 0xD2,0xF4,0x09,0x26,0x22,0xFE,0xCA,0x70,0x1B,0xE4,
+ 0xF5,0x0F,0x47,0x58,0x71,0x4E,0x8A,0x87,0xBB,0xF2,
+ 0xA6,0x58,0xEF,0x8C,0x21,0xE7,0xC5,0xEF,0xE9,0x65,
+ 0x36,0x1F,0x6C,0x29,0x99,0xC0,0xC2,0x47,0xB0,0xDB,
+ 0xD7,0x0C,0xE6,0xB7,
+ 0x20,0xD0,0xAF,0x89,0x03,0xA9,0x6F,0x8D,0x5F,0xA2, /* y */
+ 0xC2,0x55,0x74,0x5D,0x3C,0x45,0x1B,0x30,0x2C,0x93,
+ 0x46,0xD9,0xB7,0xE4,0x85,0xE7,0xBC,0xE4,0x1F,0x6B,
+ 0x59,0x1F,0x3E,0x8F,0x6A,0xDD,0xCB,0xB0,0xBC,0x4C,
+ 0x2F,0x94,0x7A,0x7D,0xE1,0xA8,0x9B,0x62,0x5D,0x6A,
+ 0x59,0x8B,0x37,0x60,
+ 0x00,0x03,0x40,0x34,0x03,0x40,0x34,0x03,0x40,0x34, /* order */
+ 0x03,0x40,0x34,0x03,0x40,0x34,0x03,0x40,0x34,0x03,
+ 0x40,0x34,0x03,0x40,0x34,0x03,0x40,0x34,0x03,0x23,
+ 0xC3,0x13,0xFA,0xB5,0x05,0x89,0x70,0x3B,0x5E,0xC6,
+ 0x8D,0x35,0x87,0xFE,0xC6,0x0D,0x16,0x1C,0xC1,0x49,
+ 0xC1,0xAD,0x4A,0x91 }
};
-static const EC_CURVE_DATA _EC_WTLS_1 = {
- NID_X9_62_characteristic_two_field,
- "020000000000000000000000000201",
- "1",
- "1",
- "01667979A40BA497E5D5C270780617",
- "00F44B4AF1ECC2630E08785CEBCC15",
- "00FFFFFFFFFFFFFFFDBF91AF6DEA73", 2,
- NULL, 0,
- "WTLS curve over a 113 bit binary field"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+15*6]; }
+ _EC_WTLS_1 = {
+ { NID_X9_62_characteristic_two_field,0,15,2 },
+ { /* no seed */
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x02,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x01,
+ 0x01,0x66,0x79,0x79,0xA4,0x0B,0xA4,0x97,0xE5,0xD5, /* x */
+ 0xC2,0x70,0x78,0x06,0x17,
+ 0x00,0xF4,0x4B,0x4A,0xF1,0xEC,0xC2,0x63,0x0E,0x08, /* y */
+ 0x78,0x5C,0xEB,0xCC,0x15,
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF, /* order */
+ 0x91,0xAF,0x6D,0xEA,0x73 }
};
/* IPSec curves */
@@ -1001,17 +1768,27 @@ static const EC_CURVE_DATA _EC_WTLS_1 = {
* As the group order is not a prime this curve is not suitable
* for ECDSA.
*/
-static const EC_CURVE_DATA _EC_IPSEC_155_ID3 = {
- NID_X9_62_characteristic_two_field,
- "0800000000000000000000004000000000000001",
- "0",
- "07338f",
- "7b",
- "1c8",
- "2AAAAAAAAAAAAAAAAAAC7F3C7881BD0868FA86C",3,
- NULL, 0,
- "\n\tIPSec/IKE/Oakley curve #3 over a 155 bit binary field.\n"
- "\tNot suitable for ECDSA.\n\tQuestionable extension field!"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+20*6]; }
+ _EC_IPSEC_155_ID3 = {
+ { NID_X9_62_characteristic_two_field,0,20,3 },
+ { /* no seed */
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x33,0x8f,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7b,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xc8,
+
+ 0x02,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, /* order */
+ 0xC7,0xF3,0xC7,0x88,0x1B,0xD0,0x86,0x8F,0xA8,0x6C }
};
/* NOTE: The of curves over a extension field of non prime degree
@@ -1019,136 +1796,185 @@ static const EC_CURVE_DATA _EC_IPSEC_155_ID3 = {
* As the group order is not a prime this curve is not suitable
* for ECDSA.
*/
-static const EC_CURVE_DATA _EC_IPSEC_185_ID4 = {
- NID_X9_62_characteristic_two_field,
- "020000000000000000000000000000200000000000000001",
- "0",
- "1ee9",
- "18",
- "0d",
- "FFFFFFFFFFFFFFFFFFFFFFEDF97C44DB9F2420BAFCA75E",2,
- NULL, 0,
- "\n\tIPSec/IKE/Oakley curve #4 over a 185 bit binary field.\n"
- "\tNot suitable for ECDSA.\n\tQuestionable extension field!"
+static const struct { EC_CURVE_DATA h; unsigned char data[0+24*6]; }
+ _EC_IPSEC_185_ID4 = {
+ { NID_X9_62_characteristic_two_field,0,24,2 },
+ { /* no seed */
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p */
+ 0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x1e,0xe9,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x18,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x0d,
+ 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */
+ 0xFF,0xFF,0xED,0xF9,0x7C,0x44,0xDB,0x9F,0x24,0x20,
+ 0xBA,0xFC,0xA7,0x5E }
};
+#endif
+
typedef struct _ec_list_element_st {
int nid;
const EC_CURVE_DATA *data;
+ const EC_METHOD *(*meth)(void);
+ const char *comment;
} ec_list_element;
static const ec_list_element curve_list[] = {
- /* prime field curves */
+ /* prime field curves */
/* secg curves */
- { NID_secp112r1, &_EC_SECG_PRIME_112R1},
- { NID_secp112r2, &_EC_SECG_PRIME_112R2},
- { NID_secp128r1, &_EC_SECG_PRIME_128R1},
- { NID_secp128r2, &_EC_SECG_PRIME_128R2},
- { NID_secp160k1, &_EC_SECG_PRIME_160K1},
- { NID_secp160r1, &_EC_SECG_PRIME_160R1},
- { NID_secp160r2, &_EC_SECG_PRIME_160R2},
+ { NID_secp112r1, &_EC_SECG_PRIME_112R1.h, 0, "SECG/WTLS curve over a 112 bit prime field" },
+ { NID_secp112r2, &_EC_SECG_PRIME_112R2.h, 0, "SECG curve over a 112 bit prime field" },
+ { NID_secp128r1, &_EC_SECG_PRIME_128R1.h, 0, "SECG curve over a 128 bit prime field" },
+ { NID_secp128r2, &_EC_SECG_PRIME_128R2.h, 0, "SECG curve over a 128 bit prime field" },
+ { NID_secp160k1, &_EC_SECG_PRIME_160K1.h, 0, "SECG curve over a 160 bit prime field" },
+ { NID_secp160r1, &_EC_SECG_PRIME_160R1.h, 0, "SECG curve over a 160 bit prime field" },
+ { NID_secp160r2, &_EC_SECG_PRIME_160R2.h, 0, "SECG/WTLS curve over a 160 bit prime field" },
/* SECG secp192r1 is the same as X9.62 prime192v1 and hence omitted */
- { NID_secp192k1, &_EC_SECG_PRIME_192K1},
- { NID_secp224k1, &_EC_SECG_PRIME_224K1},
- { NID_secp224r1, &_EC_NIST_PRIME_224},
- { NID_secp256k1, &_EC_SECG_PRIME_256K1},
+ { NID_secp192k1, &_EC_SECG_PRIME_192K1.h, 0, "SECG curve over a 192 bit prime field" },
+ { NID_secp224k1, &_EC_SECG_PRIME_224K1.h, 0, "SECG curve over a 224 bit prime field" },
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+ { NID_secp224r1, &_EC_NIST_PRIME_224.h, EC_GFp_nistp224_method, "NIST/SECG curve over a 224 bit prime field" },
+#else
+ { NID_secp224r1, &_EC_NIST_PRIME_224.h, 0, "NIST/SECG curve over a 224 bit prime field" },
+#endif
+ { NID_secp256k1, &_EC_SECG_PRIME_256K1.h, 0, "SECG curve over a 256 bit prime field" },
/* SECG secp256r1 is the same as X9.62 prime256v1 and hence omitted */
- { NID_secp384r1, &_EC_NIST_PRIME_384},
- { NID_secp521r1, &_EC_NIST_PRIME_521},
+ { NID_secp384r1, &_EC_NIST_PRIME_384.h, 0, "NIST/SECG curve over a 384 bit prime field" },
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+ { NID_secp521r1, &_EC_NIST_PRIME_521.h, EC_GFp_nistp521_method, "NIST/SECG curve over a 521 bit prime field" },
+#else
+ { NID_secp521r1, &_EC_NIST_PRIME_521.h, 0, "NIST/SECG curve over a 521 bit prime field" },
+#endif
/* X9.62 curves */
- { NID_X9_62_prime192v1, &_EC_NIST_PRIME_192},
- { NID_X9_62_prime192v2, &_EC_X9_62_PRIME_192V2},
- { NID_X9_62_prime192v3, &_EC_X9_62_PRIME_192V3},
- { NID_X9_62_prime239v1, &_EC_X9_62_PRIME_239V1},
- { NID_X9_62_prime239v2, &_EC_X9_62_PRIME_239V2},
- { NID_X9_62_prime239v3, &_EC_X9_62_PRIME_239V3},
- { NID_X9_62_prime256v1, &_EC_X9_62_PRIME_256V1},
+ { NID_X9_62_prime192v1, &_EC_NIST_PRIME_192.h, 0, "NIST/X9.62/SECG curve over a 192 bit prime field" },
+ { NID_X9_62_prime192v2, &_EC_X9_62_PRIME_192V2.h, 0, "X9.62 curve over a 192 bit prime field" },
+ { NID_X9_62_prime192v3, &_EC_X9_62_PRIME_192V3.h, 0, "X9.62 curve over a 192 bit prime field" },
+ { NID_X9_62_prime239v1, &_EC_X9_62_PRIME_239V1.h, 0, "X9.62 curve over a 239 bit prime field" },
+ { NID_X9_62_prime239v2, &_EC_X9_62_PRIME_239V2.h, 0, "X9.62 curve over a 239 bit prime field" },
+ { NID_X9_62_prime239v3, &_EC_X9_62_PRIME_239V3.h, 0, "X9.62 curve over a 239 bit prime field" },
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+ { NID_X9_62_prime256v1, &_EC_X9_62_PRIME_256V1.h, EC_GFp_nistp256_method, "X9.62/SECG curve over a 256 bit prime field" },
+#else
+ { NID_X9_62_prime256v1, &_EC_X9_62_PRIME_256V1.h, 0, "X9.62/SECG curve over a 256 bit prime field" },
+#endif
+#ifndef OPENSSL_NO_EC2M
/* characteristic two field curves */
/* NIST/SECG curves */
- { NID_sect113r1, &_EC_SECG_CHAR2_113R1},
- { NID_sect113r2, &_EC_SECG_CHAR2_113R2},
- { NID_sect131r1, &_EC_SECG_CHAR2_131R1},
- { NID_sect131r2, &_EC_SECG_CHAR2_131R2},
- { NID_sect163k1, &_EC_NIST_CHAR2_163K },
- { NID_sect163r1, &_EC_SECG_CHAR2_163R1},
- { NID_sect163r2, &_EC_NIST_CHAR2_163B },
- { NID_sect193r1, &_EC_SECG_CHAR2_193R1},
- { NID_sect193r2, &_EC_SECG_CHAR2_193R2},
- { NID_sect233k1, &_EC_NIST_CHAR2_233K },
- { NID_sect233r1, &_EC_NIST_CHAR2_233B },
- { NID_sect239k1, &_EC_SECG_CHAR2_239K1},
- { NID_sect283k1, &_EC_NIST_CHAR2_283K },
- { NID_sect283r1, &_EC_NIST_CHAR2_283B },
- { NID_sect409k1, &_EC_NIST_CHAR2_409K },
- { NID_sect409r1, &_EC_NIST_CHAR2_409B },
- { NID_sect571k1, &_EC_NIST_CHAR2_571K },
- { NID_sect571r1, &_EC_NIST_CHAR2_571B },
+ { NID_sect113r1, &_EC_SECG_CHAR2_113R1.h, 0, "SECG curve over a 113 bit binary field" },
+ { NID_sect113r2, &_EC_SECG_CHAR2_113R2.h, 0, "SECG curve over a 113 bit binary field" },
+ { NID_sect131r1, &_EC_SECG_CHAR2_131R1.h, 0, "SECG/WTLS curve over a 131 bit binary field" },
+ { NID_sect131r2, &_EC_SECG_CHAR2_131R2.h, 0, "SECG curve over a 131 bit binary field" },
+ { NID_sect163k1, &_EC_NIST_CHAR2_163K.h, 0, "NIST/SECG/WTLS curve over a 163 bit binary field" },
+ { NID_sect163r1, &_EC_SECG_CHAR2_163R1.h, 0, "SECG curve over a 163 bit binary field" },
+ { NID_sect163r2, &_EC_NIST_CHAR2_163B.h, 0, "NIST/SECG curve over a 163 bit binary field" },
+ { NID_sect193r1, &_EC_SECG_CHAR2_193R1.h, 0, "SECG curve over a 193 bit binary field" },
+ { NID_sect193r2, &_EC_SECG_CHAR2_193R2.h, 0, "SECG curve over a 193 bit binary field" },
+ { NID_sect233k1, &_EC_NIST_CHAR2_233K.h, 0, "NIST/SECG/WTLS curve over a 233 bit binary field" },
+ { NID_sect233r1, &_EC_NIST_CHAR2_233B.h, 0, "NIST/SECG/WTLS curve over a 233 bit binary field" },
+ { NID_sect239k1, &_EC_SECG_CHAR2_239K1.h, 0, "SECG curve over a 239 bit binary field" },
+ { NID_sect283k1, &_EC_NIST_CHAR2_283K.h, 0, "NIST/SECG curve over a 283 bit binary field" },
+ { NID_sect283r1, &_EC_NIST_CHAR2_283B.h, 0, "NIST/SECG curve over a 283 bit binary field" },
+ { NID_sect409k1, &_EC_NIST_CHAR2_409K.h, 0, "NIST/SECG curve over a 409 bit binary field" },
+ { NID_sect409r1, &_EC_NIST_CHAR2_409B.h, 0, "NIST/SECG curve over a 409 bit binary field" },
+ { NID_sect571k1, &_EC_NIST_CHAR2_571K.h, 0, "NIST/SECG curve over a 571 bit binary field" },
+ { NID_sect571r1, &_EC_NIST_CHAR2_571B.h, 0, "NIST/SECG curve over a 571 bit binary field" },
/* X9.62 curves */
- { NID_X9_62_c2pnb163v1, &_EC_X9_62_CHAR2_163V1},
- { NID_X9_62_c2pnb163v2, &_EC_X9_62_CHAR2_163V2},
- { NID_X9_62_c2pnb163v3, &_EC_X9_62_CHAR2_163V3},
- { NID_X9_62_c2pnb176v1, &_EC_X9_62_CHAR2_176V1},
- { NID_X9_62_c2tnb191v1, &_EC_X9_62_CHAR2_191V1},
- { NID_X9_62_c2tnb191v2, &_EC_X9_62_CHAR2_191V2},
- { NID_X9_62_c2tnb191v3, &_EC_X9_62_CHAR2_191V3},
- { NID_X9_62_c2pnb208w1, &_EC_X9_62_CHAR2_208W1},
- { NID_X9_62_c2tnb239v1, &_EC_X9_62_CHAR2_239V1},
- { NID_X9_62_c2tnb239v2, &_EC_X9_62_CHAR2_239V2},
- { NID_X9_62_c2tnb239v3, &_EC_X9_62_CHAR2_239V3},
- { NID_X9_62_c2pnb272w1, &_EC_X9_62_CHAR2_272W1},
- { NID_X9_62_c2pnb304w1, &_EC_X9_62_CHAR2_304W1},
- { NID_X9_62_c2tnb359v1, &_EC_X9_62_CHAR2_359V1},
- { NID_X9_62_c2pnb368w1, &_EC_X9_62_CHAR2_368W1},
- { NID_X9_62_c2tnb431r1, &_EC_X9_62_CHAR2_431R1},
+ { NID_X9_62_c2pnb163v1, &_EC_X9_62_CHAR2_163V1.h, 0, "X9.62 curve over a 163 bit binary field" },
+ { NID_X9_62_c2pnb163v2, &_EC_X9_62_CHAR2_163V2.h, 0, "X9.62 curve over a 163 bit binary field" },
+ { NID_X9_62_c2pnb163v3, &_EC_X9_62_CHAR2_163V3.h, 0, "X9.62 curve over a 163 bit binary field" },
+ { NID_X9_62_c2pnb176v1, &_EC_X9_62_CHAR2_176V1.h, 0, "X9.62 curve over a 176 bit binary field" },
+ { NID_X9_62_c2tnb191v1, &_EC_X9_62_CHAR2_191V1.h, 0, "X9.62 curve over a 191 bit binary field" },
+ { NID_X9_62_c2tnb191v2, &_EC_X9_62_CHAR2_191V2.h, 0, "X9.62 curve over a 191 bit binary field" },
+ { NID_X9_62_c2tnb191v3, &_EC_X9_62_CHAR2_191V3.h, 0, "X9.62 curve over a 191 bit binary field" },
+ { NID_X9_62_c2pnb208w1, &_EC_X9_62_CHAR2_208W1.h, 0, "X9.62 curve over a 208 bit binary field" },
+ { NID_X9_62_c2tnb239v1, &_EC_X9_62_CHAR2_239V1.h, 0, "X9.62 curve over a 239 bit binary field" },
+ { NID_X9_62_c2tnb239v2, &_EC_X9_62_CHAR2_239V2.h, 0, "X9.62 curve over a 239 bit binary field" },
+ { NID_X9_62_c2tnb239v3, &_EC_X9_62_CHAR2_239V3.h, 0, "X9.62 curve over a 239 bit binary field" },
+ { NID_X9_62_c2pnb272w1, &_EC_X9_62_CHAR2_272W1.h, 0, "X9.62 curve over a 272 bit binary field" },
+ { NID_X9_62_c2pnb304w1, &_EC_X9_62_CHAR2_304W1.h, 0, "X9.62 curve over a 304 bit binary field" },
+ { NID_X9_62_c2tnb359v1, &_EC_X9_62_CHAR2_359V1.h, 0, "X9.62 curve over a 359 bit binary field" },
+ { NID_X9_62_c2pnb368w1, &_EC_X9_62_CHAR2_368W1.h, 0, "X9.62 curve over a 368 bit binary field" },
+ { NID_X9_62_c2tnb431r1, &_EC_X9_62_CHAR2_431R1.h, 0, "X9.62 curve over a 431 bit binary field" },
/* the WAP/WTLS curves
* [unlike SECG, spec has its own OIDs for curves from X9.62] */
- { NID_wap_wsg_idm_ecid_wtls1, &_EC_WTLS_1},
- { NID_wap_wsg_idm_ecid_wtls3, &_EC_NIST_CHAR2_163K},
- { NID_wap_wsg_idm_ecid_wtls4, &_EC_SECG_CHAR2_113R1},
- { NID_wap_wsg_idm_ecid_wtls5, &_EC_X9_62_CHAR2_163V1},
- { NID_wap_wsg_idm_ecid_wtls6, &_EC_SECG_PRIME_112R1},
- { NID_wap_wsg_idm_ecid_wtls7, &_EC_SECG_PRIME_160R2},
- { NID_wap_wsg_idm_ecid_wtls8, &_EC_WTLS_8},
- { NID_wap_wsg_idm_ecid_wtls9, &_EC_WTLS_9 },
- { NID_wap_wsg_idm_ecid_wtls10, &_EC_NIST_CHAR2_233K},
- { NID_wap_wsg_idm_ecid_wtls11, &_EC_NIST_CHAR2_233B},
- { NID_wap_wsg_idm_ecid_wtls12, &_EC_WTLS_12},
+ { NID_wap_wsg_idm_ecid_wtls1, &_EC_WTLS_1.h, 0, "WTLS curve over a 113 bit binary field" },
+ { NID_wap_wsg_idm_ecid_wtls3, &_EC_NIST_CHAR2_163K.h, 0, "NIST/SECG/WTLS curve over a 163 bit binary field" },
+ { NID_wap_wsg_idm_ecid_wtls4, &_EC_SECG_CHAR2_113R1.h, 0, "SECG curve over a 113 bit binary field" },
+ { NID_wap_wsg_idm_ecid_wtls5, &_EC_X9_62_CHAR2_163V1.h, 0, "X9.62 curve over a 163 bit binary field" },
+#endif
+ { NID_wap_wsg_idm_ecid_wtls6, &_EC_SECG_PRIME_112R1.h, 0, "SECG/WTLS curve over a 112 bit prime field" },
+ { NID_wap_wsg_idm_ecid_wtls7, &_EC_SECG_PRIME_160R2.h, 0, "SECG/WTLS curve over a 160 bit prime field" },
+ { NID_wap_wsg_idm_ecid_wtls8, &_EC_WTLS_8.h, 0, "WTLS curve over a 112 bit prime field" },
+ { NID_wap_wsg_idm_ecid_wtls9, &_EC_WTLS_9.h, 0, "WTLS curve over a 160 bit prime field" },
+#ifndef OPENSSL_NO_EC2M
+ { NID_wap_wsg_idm_ecid_wtls10, &_EC_NIST_CHAR2_233K.h, 0, "NIST/SECG/WTLS curve over a 233 bit binary field" },
+ { NID_wap_wsg_idm_ecid_wtls11, &_EC_NIST_CHAR2_233B.h, 0, "NIST/SECG/WTLS curve over a 233 bit binary field" },
+#endif
+ { NID_wap_wsg_idm_ecid_wtls12, &_EC_WTLS_12.h, 0, "WTLS curvs over a 224 bit prime field" },
+#ifndef OPENSSL_NO_EC2M
/* IPSec curves */
- { NID_ipsec3, &_EC_IPSEC_155_ID3},
- { NID_ipsec4, &_EC_IPSEC_185_ID4},
+ { NID_ipsec3, &_EC_IPSEC_155_ID3.h, 0, "\n\tIPSec/IKE/Oakley curve #3 over a 155 bit binary field.\n"
+ "\tNot suitable for ECDSA.\n\tQuestionable extension field!" },
+ { NID_ipsec4, &_EC_IPSEC_185_ID4.h, 0, "\n\tIPSec/IKE/Oakley curve #4 over a 185 bit binary field.\n"
+ "\tNot suitable for ECDSA.\n\tQuestionable extension field!" },
+#endif
};
-static size_t curve_list_length = sizeof(curve_list)/sizeof(ec_list_element);
+#define curve_list_length (sizeof(curve_list)/sizeof(ec_list_element))
-static EC_GROUP *ec_group_new_from_data(const EC_CURVE_DATA *data)
+static EC_GROUP *ec_group_new_from_data(const ec_list_element curve)
{
EC_GROUP *group=NULL;
EC_POINT *P=NULL;
BN_CTX *ctx=NULL;
- BIGNUM *p=NULL, *a=NULL, *b=NULL, *x=NULL, *y=NULL, *order=NULL;
+ BIGNUM *p=NULL, *a=NULL, *b=NULL, *x=NULL, *y=NULL, *order=NULL;
int ok=0;
+ int seed_len,param_len;
+ const EC_METHOD *meth;
+ const EC_CURVE_DATA *data;
+ const unsigned char *params;
if ((ctx = BN_CTX_new()) == NULL)
{
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_MALLOC_FAILURE);
goto err;
}
- if ((p = BN_new()) == NULL || (a = BN_new()) == NULL ||
- (b = BN_new()) == NULL || (x = BN_new()) == NULL ||
- (y = BN_new()) == NULL || (order = BN_new()) == NULL)
- {
- ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (!BN_hex2bn(&p, data->p) || !BN_hex2bn(&a, data->a)
- || !BN_hex2bn(&b, data->b))
+
+ data = curve.data;
+ seed_len = data->seed_len;
+ param_len = data->param_len;
+ params = (const unsigned char *)(data+1); /* skip header */
+ params += seed_len; /* skip seed */
+
+ if (!(p = BN_bin2bn(params+0*param_len, param_len, NULL))
+ || !(a = BN_bin2bn(params+1*param_len, param_len, NULL))
+ || !(b = BN_bin2bn(params+2*param_len, param_len, NULL)))
{
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB);
goto err;
}
- if (data->field_type == NID_X9_62_prime_field)
+ if (curve.meth != 0)
+ {
+ meth = curve.meth();
+ if (((group = EC_GROUP_new(meth)) == NULL) ||
+ (!(group->meth->group_set_curve(group, p, a, b, ctx))))
+ {
+ ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB);
+ goto err;
+ }
+ }
+ else if (data->field_type == NID_X9_62_prime_field)
{
if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL)
{
@@ -1156,32 +1982,36 @@ static EC_GROUP *ec_group_new_from_data(const EC_CURVE_DATA *data)
goto err;
}
}
- else
- { /* field_type == NID_X9_62_characteristic_two_field */
+#ifndef OPENSSL_NO_EC2M
+ else /* field_type == NID_X9_62_characteristic_two_field */
+ {
if ((group = EC_GROUP_new_curve_GF2m(p, a, b, ctx)) == NULL)
{
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB);
goto err;
}
}
+#endif
if ((P = EC_POINT_new(group)) == NULL)
{
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB);
goto err;
}
-
- if (!BN_hex2bn(&x, data->x) || !BN_hex2bn(&y, data->y))
+
+ if (!(x = BN_bin2bn(params+3*param_len, param_len, NULL))
+ || !(y = BN_bin2bn(params+4*param_len, param_len, NULL)))
{
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB);
goto err;
}
- if (!EC_POINT_set_affine_coordinates_GF2m(group, P, x, y, ctx))
+ if (!EC_POINT_set_affine_coordinates_GFp(group, P, x, y, ctx))
{
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB);
goto err;
}
- if (!BN_hex2bn(&order, data->order) || !BN_set_word(x, data->cofactor))
+ if (!(order = BN_bin2bn(params+5*param_len, param_len, NULL))
+ || !BN_set_word(x, (BN_ULONG)data->cofactor))
{
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB);
goto err;
@@ -1191,9 +2021,9 @@ static EC_GROUP *ec_group_new_from_data(const EC_CURVE_DATA *data)
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB);
goto err;
}
- if (data->seed)
+ if (seed_len)
{
- if (!EC_GROUP_set_seed(group, data->seed, data->seed_len))
+ if (!EC_GROUP_set_seed(group, params-seed_len, seed_len))
{
ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB);
goto err;
@@ -1236,7 +2066,7 @@ EC_GROUP *EC_GROUP_new_by_curve_name(int nid)
for (i=0; i<curve_list_length; i++)
if (curve_list[i].nid == nid)
{
- ret = ec_group_new_from_data(curve_list[i].data);
+ ret = ec_group_new_from_data(curve_list[i]);
break;
}
@@ -1263,7 +2093,7 @@ size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems)
for (i = 0; i < min; i++)
{
r[i].nid = curve_list[i].nid;
- r[i].comment = curve_list[i].data->comment;
+ r[i].comment = curve_list[i].comment;
}
return curve_list_length;
diff --git a/crypto/ec/ec_cvt.c b/crypto/ec/ec_cvt.c
index d45640bab902f..bfcbab35fe695 100644
--- a/crypto/ec/ec_cvt.c
+++ b/crypto/ec/ec_cvt.c
@@ -78,7 +78,32 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM
const EC_METHOD *meth;
EC_GROUP *ret;
+#if defined(OPENSSL_BN_ASM_MONT)
+ /*
+ * This might appear controversial, but the fact is that generic
+ * prime method was observed to deliver better performance even
+ * for NIST primes on a range of platforms, e.g.: 60%-15%
+ * improvement on IA-64, ~25% on ARM, 30%-90% on P4, 20%-25%
+ * in 32-bit build and 35%--12% in 64-bit build on Core2...
+ * Coefficients are relative to optimized bn_nist.c for most
+ * intensive ECDSA verify and ECDH operations for 192- and 521-
+ * bit keys respectively. Choice of these boundary values is
+ * arguable, because the dependency of improvement coefficient
+ * from key length is not a "monotone" curve. For example while
+ * 571-bit result is 23% on ARM, 384-bit one is -1%. But it's
+ * generally faster, sometimes "respectfully" faster, sometimes
+ * "tolerably" slower... What effectively happens is that loop
+ * with bn_mul_add_words is put against bn_mul_mont, and the
+ * latter "wins" on short vectors. Correct solution should be
+ * implementing dedicated NxN multiplication subroutines for
+ * small N. But till it materializes, let's stick to generic
+ * prime method...
+ * <appro>
+ */
+ meth = EC_GFp_mont_method();
+#else
meth = EC_GFp_nist_method();
+#endif
ret = EC_GROUP_new(meth);
if (ret == NULL)
@@ -122,7 +147,7 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM
return ret;
}
-
+#ifndef OPENSSL_NO_EC2M
EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
{
const EC_METHOD *meth;
@@ -142,3 +167,4 @@ EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM
return ret;
}
+#endif
diff --git a/crypto/ec/ec_err.c b/crypto/ec/ec_err.c
index d04c8955604e0..0d19398731acb 100644
--- a/crypto/ec/ec_err.c
+++ b/crypto/ec/ec_err.c
@@ -1,6 +1,6 @@
/* crypto/ec/ec_err.c */
/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1999-2011 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -70,10 +70,19 @@
static ERR_STRING_DATA EC_str_functs[]=
{
+{ERR_FUNC(EC_F_BN_TO_FELEM), "BN_TO_FELEM"},
{ERR_FUNC(EC_F_COMPUTE_WNAF), "COMPUTE_WNAF"},
{ERR_FUNC(EC_F_D2I_ECPARAMETERS), "d2i_ECParameters"},
{ERR_FUNC(EC_F_D2I_ECPKPARAMETERS), "d2i_ECPKParameters"},
{ERR_FUNC(EC_F_D2I_ECPRIVATEKEY), "d2i_ECPrivateKey"},
+{ERR_FUNC(EC_F_DO_EC_KEY_PRINT), "DO_EC_KEY_PRINT"},
+{ERR_FUNC(EC_F_ECKEY_PARAM2TYPE), "ECKEY_PARAM2TYPE"},
+{ERR_FUNC(EC_F_ECKEY_PARAM_DECODE), "ECKEY_PARAM_DECODE"},
+{ERR_FUNC(EC_F_ECKEY_PRIV_DECODE), "ECKEY_PRIV_DECODE"},
+{ERR_FUNC(EC_F_ECKEY_PRIV_ENCODE), "ECKEY_PRIV_ENCODE"},
+{ERR_FUNC(EC_F_ECKEY_PUB_DECODE), "ECKEY_PUB_DECODE"},
+{ERR_FUNC(EC_F_ECKEY_PUB_ENCODE), "ECKEY_PUB_ENCODE"},
+{ERR_FUNC(EC_F_ECKEY_TYPE2PARAM), "ECKEY_TYPE2PARAM"},
{ERR_FUNC(EC_F_ECPARAMETERS_PRINT), "ECParameters_print"},
{ERR_FUNC(EC_F_ECPARAMETERS_PRINT_FP), "ECParameters_print_fp"},
{ERR_FUNC(EC_F_ECPKPARAMETERS_PRINT), "ECPKParameters_print"},
@@ -104,6 +113,15 @@ static ERR_STRING_DATA EC_str_functs[]=
{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_SQR), "ec_GFp_mont_field_sqr"},
{ERR_FUNC(EC_F_EC_GFP_MONT_GROUP_SET_CURVE), "ec_GFp_mont_group_set_curve"},
{ERR_FUNC(EC_F_EC_GFP_MONT_GROUP_SET_CURVE_GFP), "EC_GFP_MONT_GROUP_SET_CURVE_GFP"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP224_GROUP_SET_CURVE), "ec_GFp_nistp224_group_set_curve"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP224_POINTS_MUL), "ec_GFp_nistp224_points_mul"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES), "ec_GFp_nistp224_point_get_affine_coordinates"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP256_GROUP_SET_CURVE), "ec_GFp_nistp256_group_set_curve"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP256_POINTS_MUL), "ec_GFp_nistp256_points_mul"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES), "ec_GFp_nistp256_point_get_affine_coordinates"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP521_GROUP_SET_CURVE), "ec_GFp_nistp521_group_set_curve"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP521_POINTS_MUL), "ec_GFp_nistp521_points_mul"},
+{ERR_FUNC(EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES), "ec_GFp_nistp521_point_get_affine_coordinates"},
{ERR_FUNC(EC_F_EC_GFP_NIST_FIELD_MUL), "ec_GFp_nist_field_mul"},
{ERR_FUNC(EC_F_EC_GFP_NIST_FIELD_SQR), "ec_GFp_nist_field_sqr"},
{ERR_FUNC(EC_F_EC_GFP_NIST_GROUP_SET_CURVE), "ec_GFp_nist_group_set_curve"},
@@ -146,8 +164,8 @@ static ERR_STRING_DATA EC_str_functs[]=
{ERR_FUNC(EC_F_EC_KEY_NEW), "EC_KEY_new"},
{ERR_FUNC(EC_F_EC_KEY_PRINT), "EC_KEY_print"},
{ERR_FUNC(EC_F_EC_KEY_PRINT_FP), "EC_KEY_print_fp"},
+{ERR_FUNC(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES), "EC_KEY_set_public_key_affine_coordinates"},
{ERR_FUNC(EC_F_EC_POINTS_MAKE_AFFINE), "EC_POINTs_make_affine"},
-{ERR_FUNC(EC_F_EC_POINTS_MUL), "EC_POINTs_mul"},
{ERR_FUNC(EC_F_EC_POINT_ADD), "EC_POINT_add"},
{ERR_FUNC(EC_F_EC_POINT_CMP), "EC_POINT_cmp"},
{ERR_FUNC(EC_F_EC_POINT_COPY), "EC_POINT_copy"},
@@ -177,7 +195,17 @@ static ERR_STRING_DATA EC_str_functs[]=
{ERR_FUNC(EC_F_I2D_ECPKPARAMETERS), "i2d_ECPKParameters"},
{ERR_FUNC(EC_F_I2D_ECPRIVATEKEY), "i2d_ECPrivateKey"},
{ERR_FUNC(EC_F_I2O_ECPUBLICKEY), "i2o_ECPublicKey"},
+{ERR_FUNC(EC_F_NISTP224_PRE_COMP_NEW), "NISTP224_PRE_COMP_NEW"},
+{ERR_FUNC(EC_F_NISTP256_PRE_COMP_NEW), "NISTP256_PRE_COMP_NEW"},
+{ERR_FUNC(EC_F_NISTP521_PRE_COMP_NEW), "NISTP521_PRE_COMP_NEW"},
{ERR_FUNC(EC_F_O2I_ECPUBLICKEY), "o2i_ECPublicKey"},
+{ERR_FUNC(EC_F_OLD_EC_PRIV_DECODE), "OLD_EC_PRIV_DECODE"},
+{ERR_FUNC(EC_F_PKEY_EC_CTRL), "PKEY_EC_CTRL"},
+{ERR_FUNC(EC_F_PKEY_EC_CTRL_STR), "PKEY_EC_CTRL_STR"},
+{ERR_FUNC(EC_F_PKEY_EC_DERIVE), "PKEY_EC_DERIVE"},
+{ERR_FUNC(EC_F_PKEY_EC_KEYGEN), "PKEY_EC_KEYGEN"},
+{ERR_FUNC(EC_F_PKEY_EC_PARAMGEN), "PKEY_EC_PARAMGEN"},
+{ERR_FUNC(EC_F_PKEY_EC_SIGN), "PKEY_EC_SIGN"},
{0,NULL}
};
@@ -185,17 +213,23 @@ static ERR_STRING_DATA EC_str_reasons[]=
{
{ERR_REASON(EC_R_ASN1_ERROR) ,"asn1 error"},
{ERR_REASON(EC_R_ASN1_UNKNOWN_FIELD) ,"asn1 unknown field"},
+{ERR_REASON(EC_R_BIGNUM_OUT_OF_RANGE) ,"bignum out of range"},
{ERR_REASON(EC_R_BUFFER_TOO_SMALL) ,"buffer too small"},
+{ERR_REASON(EC_R_COORDINATES_OUT_OF_RANGE),"coordinates out of range"},
{ERR_REASON(EC_R_D2I_ECPKPARAMETERS_FAILURE),"d2i ecpkparameters failure"},
+{ERR_REASON(EC_R_DECODE_ERROR) ,"decode error"},
{ERR_REASON(EC_R_DISCRIMINANT_IS_ZERO) ,"discriminant is zero"},
{ERR_REASON(EC_R_EC_GROUP_NEW_BY_NAME_FAILURE),"ec group new by name failure"},
{ERR_REASON(EC_R_FIELD_TOO_LARGE) ,"field too large"},
+{ERR_REASON(EC_R_GF2M_NOT_SUPPORTED) ,"gf2m not supported"},
{ERR_REASON(EC_R_GROUP2PKPARAMETERS_FAILURE),"group2pkparameters failure"},
{ERR_REASON(EC_R_I2D_ECPKPARAMETERS_FAILURE),"i2d ecpkparameters failure"},
{ERR_REASON(EC_R_INCOMPATIBLE_OBJECTS) ,"incompatible objects"},
{ERR_REASON(EC_R_INVALID_ARGUMENT) ,"invalid argument"},
{ERR_REASON(EC_R_INVALID_COMPRESSED_POINT),"invalid compressed point"},
{ERR_REASON(EC_R_INVALID_COMPRESSION_BIT),"invalid compression bit"},
+{ERR_REASON(EC_R_INVALID_CURVE) ,"invalid curve"},
+{ERR_REASON(EC_R_INVALID_DIGEST_TYPE) ,"invalid digest type"},
{ERR_REASON(EC_R_INVALID_ENCODING) ,"invalid encoding"},
{ERR_REASON(EC_R_INVALID_FIELD) ,"invalid field"},
{ERR_REASON(EC_R_INVALID_FORM) ,"invalid form"},
@@ -203,6 +237,7 @@ static ERR_STRING_DATA EC_str_reasons[]=
{ERR_REASON(EC_R_INVALID_PENTANOMIAL_BASIS),"invalid pentanomial basis"},
{ERR_REASON(EC_R_INVALID_PRIVATE_KEY) ,"invalid private key"},
{ERR_REASON(EC_R_INVALID_TRINOMIAL_BASIS),"invalid trinomial basis"},
+{ERR_REASON(EC_R_KEYS_NOT_SET) ,"keys not set"},
{ERR_REASON(EC_R_MISSING_PARAMETERS) ,"missing parameters"},
{ERR_REASON(EC_R_MISSING_PRIVATE_KEY) ,"missing private key"},
{ERR_REASON(EC_R_NOT_A_NIST_PRIME) ,"not a NIST prime"},
@@ -210,6 +245,7 @@ static ERR_STRING_DATA EC_str_reasons[]=
{ERR_REASON(EC_R_NOT_IMPLEMENTED) ,"not implemented"},
{ERR_REASON(EC_R_NOT_INITIALIZED) ,"not initialized"},
{ERR_REASON(EC_R_NO_FIELD_MOD) ,"no field mod"},
+{ERR_REASON(EC_R_NO_PARAMETERS_SET) ,"no parameters set"},
{ERR_REASON(EC_R_PASSED_NULL_PARAMETER) ,"passed null parameter"},
{ERR_REASON(EC_R_PKPARAMETERS2GROUP_FAILURE),"pkparameters2group failure"},
{ERR_REASON(EC_R_POINT_AT_INFINITY) ,"point at infinity"},
@@ -220,6 +256,7 @@ static ERR_STRING_DATA EC_str_reasons[]=
{ERR_REASON(EC_R_UNKNOWN_GROUP) ,"unknown group"},
{ERR_REASON(EC_R_UNKNOWN_ORDER) ,"unknown order"},
{ERR_REASON(EC_R_UNSUPPORTED_FIELD) ,"unsupported field"},
+{ERR_REASON(EC_R_WRONG_CURVE_PARAMETERS) ,"wrong curve parameters"},
{ERR_REASON(EC_R_WRONG_ORDER) ,"wrong order"},
{0,NULL}
};
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index 522802c07ae13..bf9fd2dc2c43c 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -64,7 +64,9 @@
#include <string.h>
#include "ec_lcl.h"
#include <openssl/err.h>
-#include <string.h>
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
EC_KEY *EC_KEY_new(void)
{
@@ -78,6 +80,7 @@ EC_KEY *EC_KEY_new(void)
}
ret->version = 1;
+ ret->flags = 0;
ret->group = NULL;
ret->pub_key = NULL;
ret->priv_key= NULL;
@@ -197,6 +200,7 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src)
dest->enc_flag = src->enc_flag;
dest->conv_form = src->conv_form;
dest->version = src->version;
+ dest->flags = src->flags;
return dest;
}
@@ -237,6 +241,11 @@ int EC_KEY_generate_key(EC_KEY *eckey)
BIGNUM *priv_key = NULL, *order = NULL;
EC_POINT *pub_key = NULL;
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode())
+ return FIPS_ec_key_generate_key(eckey);
+#endif
+
if (!eckey || !eckey->group)
{
ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
@@ -371,6 +380,82 @@ err:
return(ok);
}
+int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y)
+ {
+ BN_CTX *ctx = NULL;
+ BIGNUM *tx, *ty;
+ EC_POINT *point = NULL;
+ int ok = 0, tmp_nid, is_char_two = 0;
+
+ if (!key || !key->group || !x || !y)
+ {
+ ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
+ ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ ctx = BN_CTX_new();
+ if (!ctx)
+ goto err;
+
+ point = EC_POINT_new(key->group);
+
+ if (!point)
+ goto err;
+
+ tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(key->group));
+
+ if (tmp_nid == NID_X9_62_characteristic_two_field)
+ is_char_two = 1;
+
+ tx = BN_CTX_get(ctx);
+ ty = BN_CTX_get(ctx);
+#ifndef OPENSSL_NO_EC2M
+ if (is_char_two)
+ {
+ if (!EC_POINT_set_affine_coordinates_GF2m(key->group, point,
+ x, y, ctx))
+ goto err;
+ if (!EC_POINT_get_affine_coordinates_GF2m(key->group, point,
+ tx, ty, ctx))
+ goto err;
+ }
+ else
+#endif
+ {
+ if (!EC_POINT_set_affine_coordinates_GFp(key->group, point,
+ x, y, ctx))
+ goto err;
+ if (!EC_POINT_get_affine_coordinates_GFp(key->group, point,
+ tx, ty, ctx))
+ goto err;
+ }
+ /* Check if retrieved coordinates match originals: if not values
+ * are out of range.
+ */
+ if (BN_cmp(x, tx) || BN_cmp(y, ty))
+ {
+ ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
+ EC_R_COORDINATES_OUT_OF_RANGE);
+ goto err;
+ }
+
+ if (!EC_KEY_set_public_key(key, point))
+ goto err;
+
+ if (EC_KEY_check_key(key) == 0)
+ goto err;
+
+ ok = 1;
+
+ err:
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (point)
+ EC_POINT_free(point);
+ return ok;
+
+ }
+
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key)
{
return key->group;
@@ -461,3 +546,18 @@ int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx)
return 0;
return EC_GROUP_precompute_mult(key->group, ctx);
}
+
+int EC_KEY_get_flags(const EC_KEY *key)
+ {
+ return key->flags;
+ }
+
+void EC_KEY_set_flags(EC_KEY *key, int flags)
+ {
+ key->flags |= flags;
+ }
+
+void EC_KEY_clear_flags(EC_KEY *key, int flags)
+ {
+ key->flags &= ~flags;
+ }
diff --git a/crypto/ec/ec_lcl.h b/crypto/ec/ec_lcl.h
index fdd7aa275563a..da7967df38a36 100644
--- a/crypto/ec/ec_lcl.h
+++ b/crypto/ec/ec_lcl.h
@@ -3,7 +3,7 @@
* Originally written by Bodo Moeller for the OpenSSL project.
*/
/* ====================================================================
- * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2010 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -82,10 +82,15 @@
# endif
#endif
+/* Use default functions for poin2oct, oct2point and compressed coordinates */
+#define EC_FLAGS_DEFAULT_OCT 0x1
+
/* Structure details are not part of the exported interface,
* so all this may change in future versions. */
struct ec_method_st {
+ /* Various method flags */
+ int flags;
/* used by EC_METHOD_get_field_type: */
int field_type; /* a NID */
@@ -205,11 +210,14 @@ struct ec_group_st {
* irreducible polynomial defining the field.
*/
- unsigned int poly[5]; /* Field specification for curves over GF(2^m).
- * The irreducible f(t) is then of the form:
- * t^poly[0] + t^poly[1] + ... + t^poly[k]
- * where m = poly[0] > poly[1] > ... > poly[k] = 0.
- */
+ int poly[6]; /* Field specification for curves over GF(2^m).
+ * The irreducible f(t) is then of the form:
+ * t^poly[0] + t^poly[1] + ... + t^poly[k]
+ * where m = poly[0] > poly[1] > ... > poly[k] = 0.
+ * The array is terminated with poly[k+1]=-1.
+ * All elliptic curve irreducibles have at most 5
+ * non-zero terms.
+ */
BIGNUM a, b; /* Curve coefficients.
* (Here the assumption is that BIGNUMs can be used
@@ -241,6 +249,7 @@ struct ec_key_st {
point_conversion_form_t conv_form;
int references;
+ int flags;
EC_EXTRA_DATA *method_data;
} /* EC_KEY */;
@@ -388,3 +397,50 @@ int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
int ec_GF2m_have_precompute_mult(const EC_GROUP *group);
+
+/* method functions in ec2_mult.c */
+int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GF2m_have_precompute_mult(const EC_GROUP *group);
+
+#ifndef OPENSSL_EC_NISTP_64_GCC_128
+/* method functions in ecp_nistp224.c */
+int ec_GFp_nistp224_group_init(EC_GROUP *group);
+int ec_GFp_nistp224_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
+int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
+int ec_GFp_nistp224_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
+int ec_GFp_nistp224_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GFp_nistp224_have_precompute_mult(const EC_GROUP *group);
+
+/* method functions in ecp_nistp256.c */
+int ec_GFp_nistp256_group_init(EC_GROUP *group);
+int ec_GFp_nistp256_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
+int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
+int ec_GFp_nistp256_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
+int ec_GFp_nistp256_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GFp_nistp256_have_precompute_mult(const EC_GROUP *group);
+
+/* method functions in ecp_nistp521.c */
+int ec_GFp_nistp521_group_init(EC_GROUP *group);
+int ec_GFp_nistp521_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *n, BN_CTX *);
+int ec_GFp_nistp521_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
+int ec_GFp_nistp521_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *);
+int ec_GFp_nistp521_points_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx);
+int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+int ec_GFp_nistp521_have_precompute_mult(const EC_GROUP *group);
+
+/* utility functions in ecp_nistputil.c */
+void ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
+ size_t felem_size, void *tmp_felems,
+ void (*felem_one)(void *out),
+ int (*felem_is_zero)(const void *in),
+ void (*felem_assign)(void *out, const void *in),
+ void (*felem_square)(void *out, const void *in),
+ void (*felem_mul)(void *out, const void *in1, const void *in2),
+ void (*felem_inv)(void *out, const void *in),
+ void (*felem_contract)(void *out, const void *in));
+void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign, unsigned char *digit, unsigned char in);
+#endif
diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c
index 5af84376c6025..25247b580332f 100644
--- a/crypto/ec/ec_lib.c
+++ b/crypto/ec/ec_lib.c
@@ -79,7 +79,7 @@ EC_GROUP *EC_GROUP_new(const EC_METHOD *meth)
if (meth == NULL)
{
- ECerr(EC_F_EC_GROUP_NEW, ERR_R_PASSED_NULL_PARAMETER);
+ ECerr(EC_F_EC_GROUP_NEW, EC_R_SLOT_FULL);
return NULL;
}
if (meth->group_init == 0)
@@ -425,7 +425,7 @@ int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *
return group->meth->group_get_curve(group, p, a, b, ctx);
}
-
+#ifndef OPENSSL_NO_EC2M
int EC_GROUP_set_curve_GF2m(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
{
if (group->meth->group_set_curve == 0)
@@ -446,7 +446,7 @@ int EC_GROUP_get_curve_GF2m(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM
}
return group->meth->group_get_curve(group, p, a, b, ctx);
}
-
+#endif
int EC_GROUP_get_degree(const EC_GROUP *group)
{
@@ -740,7 +740,7 @@ void EC_POINT_clear_free(EC_POINT *point)
if (point->meth->point_clear_finish != 0)
point->meth->point_clear_finish(point);
- else if (point->meth != NULL && point->meth->point_finish != 0)
+ else if (point->meth->point_finish != 0)
point->meth->point_finish(point);
OPENSSL_cleanse(point, sizeof *point);
OPENSSL_free(point);
@@ -856,7 +856,7 @@ int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
return group->meth->point_set_affine_coordinates(group, point, x, y, ctx);
}
-
+#ifndef OPENSSL_NO_EC2M
int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *point,
const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
{
@@ -872,7 +872,7 @@ int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *point,
}
return group->meth->point_set_affine_coordinates(group, point, x, y, ctx);
}
-
+#endif
int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point,
BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
@@ -890,7 +890,7 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *p
return group->meth->point_get_affine_coordinates(group, point, x, y, ctx);
}
-
+#ifndef OPENSSL_NO_EC2M
int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *group, const EC_POINT *point,
BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
{
@@ -906,75 +906,7 @@ int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *group, const EC_POINT *
}
return group->meth->point_get_affine_coordinates(group, point, x, y, ctx);
}
-
-
-int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
- const BIGNUM *x, int y_bit, BN_CTX *ctx)
- {
- if (group->meth->point_set_compressed_coordinates == 0)
- {
- ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
- if (group->meth != point->meth)
- {
- ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS);
- return 0;
- }
- return group->meth->point_set_compressed_coordinates(group, point, x, y_bit, ctx);
- }
-
-
-int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *group, EC_POINT *point,
- const BIGNUM *x, int y_bit, BN_CTX *ctx)
- {
- if (group->meth->point_set_compressed_coordinates == 0)
- {
- ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
- if (group->meth != point->meth)
- {
- ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M, EC_R_INCOMPATIBLE_OBJECTS);
- return 0;
- }
- return group->meth->point_set_compressed_coordinates(group, point, x, y_bit, ctx);
- }
-
-
-size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *ctx)
- {
- if (group->meth->point2oct == 0)
- {
- ECerr(EC_F_EC_POINT_POINT2OCT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
- if (group->meth != point->meth)
- {
- ECerr(EC_F_EC_POINT_POINT2OCT, EC_R_INCOMPATIBLE_OBJECTS);
- return 0;
- }
- return group->meth->point2oct(group, point, form, buf, len, ctx);
- }
-
-
-int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
- const unsigned char *buf, size_t len, BN_CTX *ctx)
- {
- if (group->meth->oct2point == 0)
- {
- ECerr(EC_F_EC_POINT_OCT2POINT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
- if (group->meth != point->meth)
- {
- ECerr(EC_F_EC_POINT_OCT2POINT, EC_R_INCOMPATIBLE_OBJECTS);
- return 0;
- }
- return group->meth->oct2point(group, point, buf, len, ctx);
- }
-
+#endif
int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
{
diff --git a/crypto/ec/ec_mult.c b/crypto/ec/ec_mult.c
index ee422697267e6..19f21675fbd80 100644
--- a/crypto/ec/ec_mult.c
+++ b/crypto/ec/ec_mult.c
@@ -226,6 +226,12 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len)
sign = -1;
}
+ if (scalar->d == NULL || scalar->top == 0)
+ {
+ ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
len = BN_num_bits(scalar);
r = OPENSSL_malloc(len + 1); /* modified wNAF may be one digit longer than binary representation
* (*ret_len will be set to the actual length, i.e. at most
@@ -235,12 +241,6 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len)
ECerr(EC_F_COMPUTE_WNAF, ERR_R_MALLOC_FAILURE);
goto err;
}
-
- if (scalar->d == NULL || scalar->top == 0)
- {
- ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR);
- goto err;
- }
window_val = scalar->d[0] & mask;
j = 0;
while ((window_val != 0) || (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */
@@ -421,7 +421,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
if (numblocks > pre_comp->numblocks)
numblocks = pre_comp->numblocks;
- pre_points_per_block = 1u << (pre_comp->w - 1);
+ pre_points_per_block = (size_t)1 << (pre_comp->w - 1);
/* check that pre_comp looks sane */
if (pre_comp->num != (pre_comp->numblocks * pre_points_per_block))
@@ -463,7 +463,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar);
wsize[i] = EC_window_bits_for_scalar_size(bits);
- num_val += 1u << (wsize[i] - 1);
+ num_val += (size_t)1 << (wsize[i] - 1);
wNAF[i + 1] = NULL; /* make sure we always have a pivot */
wNAF[i] = compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i]);
if (wNAF[i] == NULL)
@@ -602,7 +602,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
for (i = 0; i < num + num_scalar; i++)
{
val_sub[i] = v;
- for (j = 0; j < (1u << (wsize[i] - 1)); j++)
+ for (j = 0; j < ((size_t)1 << (wsize[i] - 1)); j++)
{
*v = EC_POINT_new(group);
if (*v == NULL) goto err;
@@ -638,7 +638,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
if (wsize[i] > 1)
{
if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx)) goto err;
- for (j = 1; j < (1u << (wsize[i] - 1)); j++)
+ for (j = 1; j < ((size_t)1 << (wsize[i] - 1)); j++)
{
if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) goto err;
}
@@ -822,7 +822,7 @@ int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
numblocks = (bits + blocksize - 1) / blocksize; /* max. number of blocks to use for wNAF splitting */
- pre_points_per_block = 1u << (w - 1);
+ pre_points_per_block = (size_t)1 << (w - 1);
num = pre_points_per_block * numblocks; /* number of points to compute and store */
points = OPENSSL_malloc(sizeof (EC_POINT*)*(num + 1));
diff --git a/crypto/ec/ec_oct.c b/crypto/ec/ec_oct.c
new file mode 100644
index 0000000000000..fd9db0798d3d3
--- /dev/null
+++ b/crypto/ec/ec_oct.c
@@ -0,0 +1,199 @@
+/* crypto/ec/ec_lib.c */
+/*
+ * Originally written by Bodo Moeller for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * Binary polynomial ECC support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#include <string.h>
+
+#include <openssl/err.h>
+#include <openssl/opensslv.h>
+
+#include "ec_lcl.h"
+
+int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
+ const BIGNUM *x, int y_bit, BN_CTX *ctx)
+ {
+ if (group->meth->point_set_compressed_coordinates == 0
+ && !(group->meth->flags & EC_FLAGS_DEFAULT_OCT))
+ {
+ ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ if (group->meth != point->meth)
+ {
+ ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if(group->meth->flags & EC_FLAGS_DEFAULT_OCT)
+ {
+ if (group->meth->field_type == NID_X9_62_prime_field)
+ return ec_GFp_simple_set_compressed_coordinates(
+ group, point, x, y_bit, ctx);
+ else
+#ifdef OPENSSL_NO_EC2M
+ {
+ ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP, EC_R_GF2M_NOT_SUPPORTED);
+ return 0;
+ }
+#else
+ return ec_GF2m_simple_set_compressed_coordinates(
+ group, point, x, y_bit, ctx);
+#endif
+ }
+ return group->meth->point_set_compressed_coordinates(group, point, x, y_bit, ctx);
+ }
+
+#ifndef OPENSSL_NO_EC2M
+int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *group, EC_POINT *point,
+ const BIGNUM *x, int y_bit, BN_CTX *ctx)
+ {
+ if (group->meth->point_set_compressed_coordinates == 0
+ && !(group->meth->flags & EC_FLAGS_DEFAULT_OCT))
+ {
+ ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ if (group->meth != point->meth)
+ {
+ ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if(group->meth->flags & EC_FLAGS_DEFAULT_OCT)
+ {
+ if (group->meth->field_type == NID_X9_62_prime_field)
+ return ec_GFp_simple_set_compressed_coordinates(
+ group, point, x, y_bit, ctx);
+ else
+ return ec_GF2m_simple_set_compressed_coordinates(
+ group, point, x, y_bit, ctx);
+ }
+ return group->meth->point_set_compressed_coordinates(group, point, x, y_bit, ctx);
+ }
+#endif
+
+size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
+ unsigned char *buf, size_t len, BN_CTX *ctx)
+ {
+ if (group->meth->point2oct == 0
+ && !(group->meth->flags & EC_FLAGS_DEFAULT_OCT))
+ {
+ ECerr(EC_F_EC_POINT_POINT2OCT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ if (group->meth != point->meth)
+ {
+ ECerr(EC_F_EC_POINT_POINT2OCT, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if(group->meth->flags & EC_FLAGS_DEFAULT_OCT)
+ {
+ if (group->meth->field_type == NID_X9_62_prime_field)
+ return ec_GFp_simple_point2oct(group, point,
+ form, buf, len, ctx);
+ else
+#ifdef OPENSSL_NO_EC2M
+ {
+ ECerr(EC_F_EC_POINT_POINT2OCT, EC_R_GF2M_NOT_SUPPORTED);
+ return 0;
+ }
+#else
+ return ec_GF2m_simple_point2oct(group, point,
+ form, buf, len, ctx);
+#endif
+ }
+
+ return group->meth->point2oct(group, point, form, buf, len, ctx);
+ }
+
+
+int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
+ const unsigned char *buf, size_t len, BN_CTX *ctx)
+ {
+ if (group->meth->oct2point == 0
+ && !(group->meth->flags & EC_FLAGS_DEFAULT_OCT))
+ {
+ ECerr(EC_F_EC_POINT_OCT2POINT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ if (group->meth != point->meth)
+ {
+ ECerr(EC_F_EC_POINT_OCT2POINT, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if(group->meth->flags & EC_FLAGS_DEFAULT_OCT)
+ {
+ if (group->meth->field_type == NID_X9_62_prime_field)
+ return ec_GFp_simple_oct2point(group, point,
+ buf, len, ctx);
+ else
+#ifdef OPENSSL_NO_EC2M
+ {
+ ECerr(EC_F_EC_POINT_OCT2POINT, EC_R_GF2M_NOT_SUPPORTED);
+ return 0;
+ }
+#else
+ return ec_GF2m_simple_oct2point(group, point,
+ buf, len, ctx);
+#endif
+ }
+ return group->meth->oct2point(group, point, buf, len, ctx);
+ }
+
diff --git a/crypto/ec/ec_pmeth.c b/crypto/ec/ec_pmeth.c
new file mode 100644
index 0000000000000..d1ed66c37e76e
--- /dev/null
+++ b/crypto/ec/ec_pmeth.c
@@ -0,0 +1,341 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include "evp_locl.h"
+
+/* EC pkey context structure */
+
+typedef struct
+ {
+ /* Key and paramgen group */
+ EC_GROUP *gen_group;
+ /* message digest */
+ const EVP_MD *md;
+ } EC_PKEY_CTX;
+
+static int pkey_ec_init(EVP_PKEY_CTX *ctx)
+ {
+ EC_PKEY_CTX *dctx;
+ dctx = OPENSSL_malloc(sizeof(EC_PKEY_CTX));
+ if (!dctx)
+ return 0;
+ dctx->gen_group = NULL;
+ dctx->md = NULL;
+
+ ctx->data = dctx;
+
+ return 1;
+ }
+
+static int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
+ {
+ EC_PKEY_CTX *dctx, *sctx;
+ if (!pkey_ec_init(dst))
+ return 0;
+ sctx = src->data;
+ dctx = dst->data;
+ if (sctx->gen_group)
+ {
+ dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
+ if (!dctx->gen_group)
+ return 0;
+ }
+ dctx->md = sctx->md;
+ return 1;
+ }
+
+static void pkey_ec_cleanup(EVP_PKEY_CTX *ctx)
+ {
+ EC_PKEY_CTX *dctx = ctx->data;
+ if (dctx)
+ {
+ if (dctx->gen_group)
+ EC_GROUP_free(dctx->gen_group);
+ OPENSSL_free(dctx);
+ }
+ }
+
+static int pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs, size_t tbslen)
+ {
+ int ret, type;
+ unsigned int sltmp;
+ EC_PKEY_CTX *dctx = ctx->data;
+ EC_KEY *ec = ctx->pkey->pkey.ec;
+
+ if (!sig)
+ {
+ *siglen = ECDSA_size(ec);
+ return 1;
+ }
+ else if(*siglen < (size_t)ECDSA_size(ec))
+ {
+ ECerr(EC_F_PKEY_EC_SIGN, EC_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if (dctx->md)
+ type = EVP_MD_type(dctx->md);
+ else
+ type = NID_sha1;
+
+
+ ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec);
+
+ if (ret <= 0)
+ return ret;
+ *siglen = (size_t)sltmp;
+ return 1;
+ }
+
+static int pkey_ec_verify(EVP_PKEY_CTX *ctx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+ {
+ int ret, type;
+ EC_PKEY_CTX *dctx = ctx->data;
+ EC_KEY *ec = ctx->pkey->pkey.ec;
+
+ if (dctx->md)
+ type = EVP_MD_type(dctx->md);
+ else
+ type = NID_sha1;
+
+ ret = ECDSA_verify(type, tbs, tbslen, sig, siglen, ec);
+
+ return ret;
+ }
+
+static int pkey_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
+ {
+ int ret;
+ size_t outlen;
+ const EC_POINT *pubkey = NULL;
+ if (!ctx->pkey || !ctx->peerkey)
+ {
+ ECerr(EC_F_PKEY_EC_DERIVE, EC_R_KEYS_NOT_SET);
+ return 0;
+ }
+
+ if (!key)
+ {
+ const EC_GROUP *group;
+ group = EC_KEY_get0_group(ctx->pkey->pkey.ec);
+ *keylen = (EC_GROUP_get_degree(group) + 7)/8;
+ return 1;
+ }
+
+ pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec);
+
+ /* NB: unlike PKS#3 DH, if *outlen is less than maximum size this is
+ * not an error, the result is truncated.
+ */
+
+ outlen = *keylen;
+
+ ret = ECDH_compute_key(key, outlen, pubkey, ctx->pkey->pkey.ec, 0);
+ if (ret < 0)
+ return ret;
+ *keylen = ret;
+ return 1;
+ }
+
+static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+ {
+ EC_PKEY_CTX *dctx = ctx->data;
+ EC_GROUP *group;
+ switch (type)
+ {
+ case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
+ group = EC_GROUP_new_by_curve_name(p1);
+ if (group == NULL)
+ {
+ ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_CURVE);
+ return 0;
+ }
+ if (dctx->gen_group)
+ EC_GROUP_free(dctx->gen_group);
+ dctx->gen_group = group;
+ return 1;
+
+ case EVP_PKEY_CTRL_MD:
+ if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 &&
+ EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 &&
+ EVP_MD_type((const EVP_MD *)p2) != NID_sha224 &&
+ EVP_MD_type((const EVP_MD *)p2) != NID_sha256 &&
+ EVP_MD_type((const EVP_MD *)p2) != NID_sha384 &&
+ EVP_MD_type((const EVP_MD *)p2) != NID_sha512)
+ {
+ ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE);
+ return 0;
+ }
+ dctx->md = p2;
+ return 1;
+
+ case EVP_PKEY_CTRL_PEER_KEY:
+ /* Default behaviour is OK */
+ case EVP_PKEY_CTRL_DIGESTINIT:
+ case EVP_PKEY_CTRL_PKCS7_SIGN:
+ case EVP_PKEY_CTRL_CMS_SIGN:
+ return 1;
+
+ default:
+ return -2;
+
+ }
+ }
+
+static int pkey_ec_ctrl_str(EVP_PKEY_CTX *ctx,
+ const char *type, const char *value)
+ {
+ if (!strcmp(type, "ec_paramgen_curve"))
+ {
+ int nid;
+ nid = OBJ_sn2nid(value);
+ if (nid == NID_undef)
+ nid = OBJ_ln2nid(value);
+ if (nid == NID_undef)
+ {
+ ECerr(EC_F_PKEY_EC_CTRL_STR, EC_R_INVALID_CURVE);
+ return 0;
+ }
+ return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
+ }
+ return -2;
+ }
+
+static int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
+ {
+ EC_KEY *ec = NULL;
+ EC_PKEY_CTX *dctx = ctx->data;
+ int ret = 0;
+ if (dctx->gen_group == NULL)
+ {
+ ECerr(EC_F_PKEY_EC_PARAMGEN, EC_R_NO_PARAMETERS_SET);
+ return 0;
+ }
+ ec = EC_KEY_new();
+ if (!ec)
+ return 0;
+ ret = EC_KEY_set_group(ec, dctx->gen_group);
+ if (ret)
+ EVP_PKEY_assign_EC_KEY(pkey, ec);
+ else
+ EC_KEY_free(ec);
+ return ret;
+ }
+
+static int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
+ {
+ EC_KEY *ec = NULL;
+ if (ctx->pkey == NULL)
+ {
+ ECerr(EC_F_PKEY_EC_KEYGEN, EC_R_NO_PARAMETERS_SET);
+ return 0;
+ }
+ ec = EC_KEY_new();
+ if (!ec)
+ return 0;
+ EVP_PKEY_assign_EC_KEY(pkey, ec);
+ /* Note: if error return, pkey is freed by parent routine */
+ if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
+ return 0;
+ return EC_KEY_generate_key(pkey->pkey.ec);
+ }
+
+const EVP_PKEY_METHOD ec_pkey_meth =
+ {
+ EVP_PKEY_EC,
+ 0,
+ pkey_ec_init,
+ pkey_ec_copy,
+ pkey_ec_cleanup,
+
+ 0,
+ pkey_ec_paramgen,
+
+ 0,
+ pkey_ec_keygen,
+
+ 0,
+ pkey_ec_sign,
+
+ 0,
+ pkey_ec_verify,
+
+ 0,0,
+
+ 0,0,0,0,
+
+ 0,0,
+
+ 0,0,
+
+ 0,
+ pkey_ec_derive,
+
+ pkey_ec_ctrl,
+ pkey_ec_ctrl_str
+
+ };
diff --git a/crypto/ec/eck_prn.c b/crypto/ec/eck_prn.c
new file mode 100644
index 0000000000000..06de8f3959d57
--- /dev/null
+++ b/crypto/ec/eck_prn.c
@@ -0,0 +1,392 @@
+/* crypto/ec/eck_prn.c */
+/*
+ * Written by Nils Larsch for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * Portions originally developed by SUN MICROSYSTEMS, INC., and
+ * contributed to the OpenSSL project.
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/evp.h>
+#include <openssl/ec.h>
+#include <openssl/bn.h>
+
+#ifndef OPENSSL_NO_FP_API
+int ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ ECerr(EC_F_ECPKPARAMETERS_PRINT_FP,ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b, fp, BIO_NOCLOSE);
+ ret = ECPKParameters_print(b, x, off);
+ BIO_free(b);
+ return(ret);
+ }
+
+int EC_KEY_print_fp(FILE *fp, const EC_KEY *x, int off)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ ECerr(EC_F_EC_KEY_PRINT_FP, ERR_R_BIO_LIB);
+ return(0);
+ }
+ BIO_set_fp(b, fp, BIO_NOCLOSE);
+ ret = EC_KEY_print(b, x, off);
+ BIO_free(b);
+ return(ret);
+ }
+
+int ECParameters_print_fp(FILE *fp, const EC_KEY *x)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ ECerr(EC_F_ECPARAMETERS_PRINT_FP, ERR_R_BIO_LIB);
+ return(0);
+ }
+ BIO_set_fp(b, fp, BIO_NOCLOSE);
+ ret = ECParameters_print(b, x);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+int EC_KEY_print(BIO *bp, const EC_KEY *x, int off)
+ {
+ EVP_PKEY *pk;
+ int ret;
+ pk = EVP_PKEY_new();
+ if (!pk || !EVP_PKEY_set1_EC_KEY(pk, (EC_KEY *)x))
+ return 0;
+ ret = EVP_PKEY_print_private(bp, pk, off, NULL);
+ EVP_PKEY_free(pk);
+ return ret;
+ }
+
+int ECParameters_print(BIO *bp, const EC_KEY *x)
+ {
+ EVP_PKEY *pk;
+ int ret;
+ pk = EVP_PKEY_new();
+ if (!pk || !EVP_PKEY_set1_EC_KEY(pk, (EC_KEY *)x))
+ return 0;
+ ret = EVP_PKEY_print_params(bp, pk, 4, NULL);
+ EVP_PKEY_free(pk);
+ return ret;
+ }
+
+static int print_bin(BIO *fp, const char *str, const unsigned char *num,
+ size_t len, int off);
+
+int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off)
+ {
+ unsigned char *buffer=NULL;
+ size_t buf_len=0, i;
+ int ret=0, reason=ERR_R_BIO_LIB;
+ BN_CTX *ctx=NULL;
+ const EC_POINT *point=NULL;
+ BIGNUM *p=NULL, *a=NULL, *b=NULL, *gen=NULL,
+ *order=NULL, *cofactor=NULL;
+ const unsigned char *seed;
+ size_t seed_len=0;
+
+ static const char *gen_compressed = "Generator (compressed):";
+ static const char *gen_uncompressed = "Generator (uncompressed):";
+ static const char *gen_hybrid = "Generator (hybrid):";
+
+ if (!x)
+ {
+ reason = ERR_R_PASSED_NULL_PARAMETER;
+ goto err;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL)
+ {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+
+ if (EC_GROUP_get_asn1_flag(x))
+ {
+ /* the curve parameter are given by an asn1 OID */
+ int nid;
+
+ if (!BIO_indent(bp, off, 128))
+ goto err;
+
+ nid = EC_GROUP_get_curve_name(x);
+ if (nid == 0)
+ goto err;
+
+ if (BIO_printf(bp, "ASN1 OID: %s", OBJ_nid2sn(nid)) <= 0)
+ goto err;
+ if (BIO_printf(bp, "\n") <= 0)
+ goto err;
+ }
+ else
+ {
+ /* explicit parameters */
+ int is_char_two = 0;
+ point_conversion_form_t form;
+ int tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(x));
+
+ if (tmp_nid == NID_X9_62_characteristic_two_field)
+ is_char_two = 1;
+
+ if ((p = BN_new()) == NULL || (a = BN_new()) == NULL ||
+ (b = BN_new()) == NULL || (order = BN_new()) == NULL ||
+ (cofactor = BN_new()) == NULL)
+ {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+#ifndef OPENSSL_NO_EC2M
+ if (is_char_two)
+ {
+ if (!EC_GROUP_get_curve_GF2m(x, p, a, b, ctx))
+ {
+ reason = ERR_R_EC_LIB;
+ goto err;
+ }
+ }
+ else /* prime field */
+#endif
+ {
+ if (!EC_GROUP_get_curve_GFp(x, p, a, b, ctx))
+ {
+ reason = ERR_R_EC_LIB;
+ goto err;
+ }
+ }
+
+ if ((point = EC_GROUP_get0_generator(x)) == NULL)
+ {
+ reason = ERR_R_EC_LIB;
+ goto err;
+ }
+ if (!EC_GROUP_get_order(x, order, NULL) ||
+ !EC_GROUP_get_cofactor(x, cofactor, NULL))
+ {
+ reason = ERR_R_EC_LIB;
+ goto err;
+ }
+
+ form = EC_GROUP_get_point_conversion_form(x);
+
+ if ((gen = EC_POINT_point2bn(x, point,
+ form, NULL, ctx)) == NULL)
+ {
+ reason = ERR_R_EC_LIB;
+ goto err;
+ }
+
+ buf_len = (size_t)BN_num_bytes(p);
+ if (buf_len < (i = (size_t)BN_num_bytes(a)))
+ buf_len = i;
+ if (buf_len < (i = (size_t)BN_num_bytes(b)))
+ buf_len = i;
+ if (buf_len < (i = (size_t)BN_num_bytes(gen)))
+ buf_len = i;
+ if (buf_len < (i = (size_t)BN_num_bytes(order)))
+ buf_len = i;
+ if (buf_len < (i = (size_t)BN_num_bytes(cofactor)))
+ buf_len = i;
+
+ if ((seed = EC_GROUP_get0_seed(x)) != NULL)
+ seed_len = EC_GROUP_get_seed_len(x);
+
+ buf_len += 10;
+ if ((buffer = OPENSSL_malloc(buf_len)) == NULL)
+ {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+
+ if (!BIO_indent(bp, off, 128))
+ goto err;
+
+ /* print the 'short name' of the field type */
+ if (BIO_printf(bp, "Field Type: %s\n", OBJ_nid2sn(tmp_nid))
+ <= 0)
+ goto err;
+
+ if (is_char_two)
+ {
+ /* print the 'short name' of the base type OID */
+ int basis_type = EC_GROUP_get_basis_type(x);
+ if (basis_type == 0)
+ goto err;
+
+ if (!BIO_indent(bp, off, 128))
+ goto err;
+
+ if (BIO_printf(bp, "Basis Type: %s\n",
+ OBJ_nid2sn(basis_type)) <= 0)
+ goto err;
+
+ /* print the polynomial */
+ if ((p != NULL) && !ASN1_bn_print(bp, "Polynomial:", p, buffer,
+ off))
+ goto err;
+ }
+ else
+ {
+ if ((p != NULL) && !ASN1_bn_print(bp, "Prime:", p, buffer,off))
+ goto err;
+ }
+ if ((a != NULL) && !ASN1_bn_print(bp, "A: ", a, buffer, off))
+ goto err;
+ if ((b != NULL) && !ASN1_bn_print(bp, "B: ", b, buffer, off))
+ goto err;
+ if (form == POINT_CONVERSION_COMPRESSED)
+ {
+ if ((gen != NULL) && !ASN1_bn_print(bp, gen_compressed, gen,
+ buffer, off))
+ goto err;
+ }
+ else if (form == POINT_CONVERSION_UNCOMPRESSED)
+ {
+ if ((gen != NULL) && !ASN1_bn_print(bp, gen_uncompressed, gen,
+ buffer, off))
+ goto err;
+ }
+ else /* form == POINT_CONVERSION_HYBRID */
+ {
+ if ((gen != NULL) && !ASN1_bn_print(bp, gen_hybrid, gen,
+ buffer, off))
+ goto err;
+ }
+ if ((order != NULL) && !ASN1_bn_print(bp, "Order: ", order,
+ buffer, off)) goto err;
+ if ((cofactor != NULL) && !ASN1_bn_print(bp, "Cofactor: ", cofactor,
+ buffer, off)) goto err;
+ if (seed && !print_bin(bp, "Seed:", seed, seed_len, off))
+ goto err;
+ }
+ ret=1;
+err:
+ if (!ret)
+ ECerr(EC_F_ECPKPARAMETERS_PRINT, reason);
+ if (p)
+ BN_free(p);
+ if (a)
+ BN_free(a);
+ if (b)
+ BN_free(b);
+ if (gen)
+ BN_free(gen);
+ if (order)
+ BN_free(order);
+ if (cofactor)
+ BN_free(cofactor);
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (buffer != NULL)
+ OPENSSL_free(buffer);
+ return(ret);
+ }
+
+static int print_bin(BIO *fp, const char *name, const unsigned char *buf,
+ size_t len, int off)
+ {
+ size_t i;
+ char str[128];
+
+ if (buf == NULL)
+ return 1;
+ if (off)
+ {
+ if (off > 128)
+ off=128;
+ memset(str,' ',off);
+ if (BIO_write(fp, str, off) <= 0)
+ return 0;
+ }
+
+ if (BIO_printf(fp,"%s", name) <= 0)
+ return 0;
+
+ for (i=0; i<len; i++)
+ {
+ if ((i%15) == 0)
+ {
+ str[0]='\n';
+ memset(&(str[1]),' ',off+4);
+ if (BIO_write(fp, str, off+1+4) <= 0)
+ return 0;
+ }
+ if (BIO_printf(fp,"%02x%s",buf[i],((i+1) == len)?"":":") <= 0)
+ return 0;
+ }
+ if (BIO_write(fp,"\n",1) <= 0)
+ return 0;
+
+ return 1;
+ }
diff --git a/crypto/ec/ecp_mont.c b/crypto/ec/ecp_mont.c
index 9fc4a466a59f2..079e47431b4f8 100644
--- a/crypto/ec/ecp_mont.c
+++ b/crypto/ec/ecp_mont.c
@@ -63,12 +63,20 @@
#include <openssl/err.h>
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
+
#include "ec_lcl.h"
const EC_METHOD *EC_GFp_mont_method(void)
{
+#ifdef OPENSSL_FIPS
+ return fips_ec_gfp_mont_method();
+#else
static const EC_METHOD ret = {
+ EC_FLAGS_DEFAULT_OCT,
NID_X9_62_prime_field,
ec_GFp_mont_group_init,
ec_GFp_mont_group_finish,
@@ -87,9 +95,7 @@ const EC_METHOD *EC_GFp_mont_method(void)
ec_GFp_simple_get_Jprojective_coordinates_GFp,
ec_GFp_simple_point_set_affine_coordinates,
ec_GFp_simple_point_get_affine_coordinates,
- ec_GFp_simple_set_compressed_coordinates,
- ec_GFp_simple_point2oct,
- ec_GFp_simple_oct2point,
+ 0,0,0,
ec_GFp_simple_add,
ec_GFp_simple_dbl,
ec_GFp_simple_invert,
@@ -108,7 +114,9 @@ const EC_METHOD *EC_GFp_mont_method(void)
ec_GFp_mont_field_decode,
ec_GFp_mont_field_set_to_one };
+
return &ret;
+#endif
}
diff --git a/crypto/ec/ecp_nist.c b/crypto/ec/ecp_nist.c
index 71893d5eaba18..aad2d5f44389a 100644
--- a/crypto/ec/ecp_nist.c
+++ b/crypto/ec/ecp_nist.c
@@ -67,9 +67,17 @@
#include <openssl/obj_mac.h>
#include "ec_lcl.h"
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
+
const EC_METHOD *EC_GFp_nist_method(void)
{
+#ifdef OPENSSL_FIPS
+ return fips_ec_gfp_nist_method();
+#else
static const EC_METHOD ret = {
+ EC_FLAGS_DEFAULT_OCT,
NID_X9_62_prime_field,
ec_GFp_simple_group_init,
ec_GFp_simple_group_finish,
@@ -88,9 +96,7 @@ const EC_METHOD *EC_GFp_nist_method(void)
ec_GFp_simple_get_Jprojective_coordinates_GFp,
ec_GFp_simple_point_set_affine_coordinates,
ec_GFp_simple_point_get_affine_coordinates,
- ec_GFp_simple_set_compressed_coordinates,
- ec_GFp_simple_point2oct,
- ec_GFp_simple_oct2point,
+ 0,0,0,
ec_GFp_simple_add,
ec_GFp_simple_dbl,
ec_GFp_simple_invert,
@@ -110,11 +116,8 @@ const EC_METHOD *EC_GFp_nist_method(void)
0 /* field_set_to_one */ };
return &ret;
- }
-
-#if BN_BITS2 == 64
-#define NO_32_BIT_TYPE
#endif
+ }
int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src)
{
@@ -139,34 +142,12 @@ int ec_GFp_nist_group_set_curve(EC_GROUP *group, const BIGNUM *p,
if (BN_ucmp(BN_get0_nist_prime_192(), p) == 0)
group->field_mod_func = BN_nist_mod_192;
else if (BN_ucmp(BN_get0_nist_prime_224(), p) == 0)
- {
-#ifndef NO_32_BIT_TYPE
group->field_mod_func = BN_nist_mod_224;
-#else
- ECerr(EC_F_EC_GFP_NIST_GROUP_SET_CURVE, EC_R_NOT_A_SUPPORTED_NIST_PRIME);
- goto err;
-#endif
- }
else if (BN_ucmp(BN_get0_nist_prime_256(), p) == 0)
- {
-#ifndef NO_32_BIT_TYPE
group->field_mod_func = BN_nist_mod_256;
-#else
- ECerr(EC_F_EC_GFP_NIST_GROUP_SET_CURVE, EC_R_NOT_A_SUPPORTED_NIST_PRIME);
- goto err;
-#endif
- }
else if (BN_ucmp(BN_get0_nist_prime_384(), p) == 0)
- {
-#ifndef NO_32_BIT_TYPE
group->field_mod_func = BN_nist_mod_384;
-#else
- ECerr(EC_F_EC_GFP_NIST_GROUP_SET_CURVE, EC_R_NOT_A_SUPPORTED_NIST_PRIME);
- goto err;
-#endif
- }
else if (BN_ucmp(BN_get0_nist_prime_521(), p) == 0)
- /* this one works in the NO_32_BIT_TYPE case */
group->field_mod_func = BN_nist_mod_521;
else
{
diff --git a/crypto/ec/ecp_nistp224.c b/crypto/ec/ecp_nistp224.c
new file mode 100644
index 0000000000000..b5ff56c252776
--- /dev/null
+++ b/crypto/ec/ecp_nistp224.c
@@ -0,0 +1,1658 @@
+/* crypto/ec/ecp_nistp224.c */
+/*
+ * Written by Emilia Kasper (Google) for the OpenSSL project.
+ */
+/* Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ *
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A 64-bit implementation of the NIST P-224 elliptic curve point multiplication
+ *
+ * Inspired by Daniel J. Bernstein's public domain nistp224 implementation
+ * and Adam Langley's public domain 64-bit C implementation of curve25519
+ */
+
+#include <openssl/opensslconf.h>
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+
+#ifndef OPENSSL_SYS_VMS
+#include <stdint.h>
+#else
+#include <inttypes.h>
+#endif
+
+#include <string.h>
+#include <openssl/err.h>
+#include "ec_lcl.h"
+
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+ /* even with gcc, the typedef won't work for 32-bit platforms */
+ typedef __uint128_t uint128_t; /* nonstandard; implemented by gcc on 64-bit platforms */
+#else
+ #error "Need GCC 3.1 or later to define type uint128_t"
+#endif
+
+typedef uint8_t u8;
+typedef uint64_t u64;
+typedef int64_t s64;
+
+
+/******************************************************************************/
+/* INTERNAL REPRESENTATION OF FIELD ELEMENTS
+ *
+ * Field elements are represented as a_0 + 2^56*a_1 + 2^112*a_2 + 2^168*a_3
+ * using 64-bit coefficients called 'limbs',
+ * and sometimes (for multiplication results) as
+ * b_0 + 2^56*b_1 + 2^112*b_2 + 2^168*b_3 + 2^224*b_4 + 2^280*b_5 + 2^336*b_6
+ * using 128-bit coefficients called 'widelimbs'.
+ * A 4-limb representation is an 'felem';
+ * a 7-widelimb representation is a 'widefelem'.
+ * Even within felems, bits of adjacent limbs overlap, and we don't always
+ * reduce the representations: we ensure that inputs to each felem
+ * multiplication satisfy a_i < 2^60, so outputs satisfy b_i < 4*2^60*2^60,
+ * and fit into a 128-bit word without overflow. The coefficients are then
+ * again partially reduced to obtain an felem satisfying a_i < 2^57.
+ * We only reduce to the unique minimal representation at the end of the
+ * computation.
+ */
+
+typedef uint64_t limb;
+typedef uint128_t widelimb;
+
+typedef limb felem[4];
+typedef widelimb widefelem[7];
+
+/* Field element represented as a byte arrary.
+ * 28*8 = 224 bits is also the group order size for the elliptic curve,
+ * and we also use this type for scalars for point multiplication.
+ */
+typedef u8 felem_bytearray[28];
+
+static const felem_bytearray nistp224_curve_params[5] = {
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE},
+ {0xB4,0x05,0x0A,0x85,0x0C,0x04,0xB3,0xAB,0xF5,0x41, /* b */
+ 0x32,0x56,0x50,0x44,0xB0,0xB7,0xD7,0xBF,0xD8,0xBA,
+ 0x27,0x0B,0x39,0x43,0x23,0x55,0xFF,0xB4},
+ {0xB7,0x0E,0x0C,0xBD,0x6B,0xB4,0xBF,0x7F,0x32,0x13, /* x */
+ 0x90,0xB9,0x4A,0x03,0xC1,0xD3,0x56,0xC2,0x11,0x22,
+ 0x34,0x32,0x80,0xD6,0x11,0x5C,0x1D,0x21},
+ {0xbd,0x37,0x63,0x88,0xb5,0xf7,0x23,0xfb,0x4c,0x22, /* y */
+ 0xdf,0xe6,0xcd,0x43,0x75,0xa0,0x5a,0x07,0x47,0x64,
+ 0x44,0xd5,0x81,0x99,0x85,0x00,0x7e,0x34}
+};
+
+/* Precomputed multiples of the standard generator
+ * Points are given in coordinates (X, Y, Z) where Z normally is 1
+ * (0 for the point at infinity).
+ * For each field element, slice a_0 is word 0, etc.
+ *
+ * The table has 2 * 16 elements, starting with the following:
+ * index | bits | point
+ * ------+---------+------------------------------
+ * 0 | 0 0 0 0 | 0G
+ * 1 | 0 0 0 1 | 1G
+ * 2 | 0 0 1 0 | 2^56G
+ * 3 | 0 0 1 1 | (2^56 + 1)G
+ * 4 | 0 1 0 0 | 2^112G
+ * 5 | 0 1 0 1 | (2^112 + 1)G
+ * 6 | 0 1 1 0 | (2^112 + 2^56)G
+ * 7 | 0 1 1 1 | (2^112 + 2^56 + 1)G
+ * 8 | 1 0 0 0 | 2^168G
+ * 9 | 1 0 0 1 | (2^168 + 1)G
+ * 10 | 1 0 1 0 | (2^168 + 2^56)G
+ * 11 | 1 0 1 1 | (2^168 + 2^56 + 1)G
+ * 12 | 1 1 0 0 | (2^168 + 2^112)G
+ * 13 | 1 1 0 1 | (2^168 + 2^112 + 1)G
+ * 14 | 1 1 1 0 | (2^168 + 2^112 + 2^56)G
+ * 15 | 1 1 1 1 | (2^168 + 2^112 + 2^56 + 1)G
+ * followed by a copy of this with each element multiplied by 2^28.
+ *
+ * The reason for this is so that we can clock bits into four different
+ * locations when doing simple scalar multiplies against the base point,
+ * and then another four locations using the second 16 elements.
+ */
+static const felem gmul[2][16][3] =
+{{{{0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}},
+ {{0x3280d6115c1d21, 0xc1d356c2112234, 0x7f321390b94a03, 0xb70e0cbd6bb4bf},
+ {0xd5819985007e34, 0x75a05a07476444, 0xfb4c22dfe6cd43, 0xbd376388b5f723},
+ {1, 0, 0, 0}},
+ {{0xfd9675666ebbe9, 0xbca7664d40ce5e, 0x2242df8d8a2a43, 0x1f49bbb0f99bc5},
+ {0x29e0b892dc9c43, 0xece8608436e662, 0xdc858f185310d0, 0x9812dd4eb8d321},
+ {1, 0, 0, 0}},
+ {{0x6d3e678d5d8eb8, 0x559eed1cb362f1, 0x16e9a3bbce8a3f, 0xeedcccd8c2a748},
+ {0xf19f90ed50266d, 0xabf2b4bf65f9df, 0x313865468fafec, 0x5cb379ba910a17},
+ {1, 0, 0, 0}},
+ {{0x0641966cab26e3, 0x91fb2991fab0a0, 0xefec27a4e13a0b, 0x0499aa8a5f8ebe},
+ {0x7510407766af5d, 0x84d929610d5450, 0x81d77aae82f706, 0x6916f6d4338c5b},
+ {1, 0, 0, 0}},
+ {{0xea95ac3b1f15c6, 0x086000905e82d4, 0xdd323ae4d1c8b1, 0x932b56be7685a3},
+ {0x9ef93dea25dbbf, 0x41665960f390f0, 0xfdec76dbe2a8a7, 0x523e80f019062a},
+ {1, 0, 0, 0}},
+ {{0x822fdd26732c73, 0xa01c83531b5d0f, 0x363f37347c1ba4, 0xc391b45c84725c},
+ {0xbbd5e1b2d6ad24, 0xddfbcde19dfaec, 0xc393da7e222a7f, 0x1efb7890ede244},
+ {1, 0, 0, 0}},
+ {{0x4c9e90ca217da1, 0xd11beca79159bb, 0xff8d33c2c98b7c, 0x2610b39409f849},
+ {0x44d1352ac64da0, 0xcdbb7b2c46b4fb, 0x966c079b753c89, 0xfe67e4e820b112},
+ {1, 0, 0, 0}},
+ {{0xe28cae2df5312d, 0xc71b61d16f5c6e, 0x79b7619a3e7c4c, 0x05c73240899b47},
+ {0x9f7f6382c73e3a, 0x18615165c56bda, 0x641fab2116fd56, 0x72855882b08394},
+ {1, 0, 0, 0}},
+ {{0x0469182f161c09, 0x74a98ca8d00fb5, 0xb89da93489a3e0, 0x41c98768fb0c1d},
+ {0xe5ea05fb32da81, 0x3dce9ffbca6855, 0x1cfe2d3fbf59e6, 0x0e5e03408738a7},
+ {1, 0, 0, 0}},
+ {{0xdab22b2333e87f, 0x4430137a5dd2f6, 0xe03ab9f738beb8, 0xcb0c5d0dc34f24},
+ {0x764a7df0c8fda5, 0x185ba5c3fa2044, 0x9281d688bcbe50, 0xc40331df893881},
+ {1, 0, 0, 0}},
+ {{0xb89530796f0f60, 0xade92bd26909a3, 0x1a0c83fb4884da, 0x1765bf22a5a984},
+ {0x772a9ee75db09e, 0x23bc6c67cec16f, 0x4c1edba8b14e2f, 0xe2a215d9611369},
+ {1, 0, 0, 0}},
+ {{0x571e509fb5efb3, 0xade88696410552, 0xc8ae85fada74fe, 0x6c7e4be83bbde3},
+ {0xff9f51160f4652, 0xb47ce2495a6539, 0xa2946c53b582f4, 0x286d2db3ee9a60},
+ {1, 0, 0, 0}},
+ {{0x40bbd5081a44af, 0x0995183b13926c, 0xbcefba6f47f6d0, 0x215619e9cc0057},
+ {0x8bc94d3b0df45e, 0xf11c54a3694f6f, 0x8631b93cdfe8b5, 0xe7e3f4b0982db9},
+ {1, 0, 0, 0}},
+ {{0xb17048ab3e1c7b, 0xac38f36ff8a1d8, 0x1c29819435d2c6, 0xc813132f4c07e9},
+ {0x2891425503b11f, 0x08781030579fea, 0xf5426ba5cc9674, 0x1e28ebf18562bc},
+ {1, 0, 0, 0}},
+ {{0x9f31997cc864eb, 0x06cd91d28b5e4c, 0xff17036691a973, 0xf1aef351497c58},
+ {0xdd1f2d600564ff, 0xdead073b1402db, 0x74a684435bd693, 0xeea7471f962558},
+ {1, 0, 0, 0}}},
+ {{{0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}},
+ {{0x9665266dddf554, 0x9613d78b60ef2d, 0xce27a34cdba417, 0xd35ab74d6afc31},
+ {0x85ccdd22deb15e, 0x2137e5783a6aab, 0xa141cffd8c93c6, 0x355a1830e90f2d},
+ {1, 0, 0, 0}},
+ {{0x1a494eadaade65, 0xd6da4da77fe53c, 0xe7992996abec86, 0x65c3553c6090e3},
+ {0xfa610b1fb09346, 0xf1c6540b8a4aaf, 0xc51a13ccd3cbab, 0x02995b1b18c28a},
+ {1, 0, 0, 0}},
+ {{0x7874568e7295ef, 0x86b419fbe38d04, 0xdc0690a7550d9a, 0xd3966a44beac33},
+ {0x2b7280ec29132f, 0xbeaa3b6a032df3, 0xdc7dd88ae41200, 0xd25e2513e3a100},
+ {1, 0, 0, 0}},
+ {{0x924857eb2efafd, 0xac2bce41223190, 0x8edaa1445553fc, 0x825800fd3562d5},
+ {0x8d79148ea96621, 0x23a01c3dd9ed8d, 0xaf8b219f9416b5, 0xd8db0cc277daea},
+ {1, 0, 0, 0}},
+ {{0x76a9c3b1a700f0, 0xe9acd29bc7e691, 0x69212d1a6b0327, 0x6322e97fe154be},
+ {0x469fc5465d62aa, 0x8d41ed18883b05, 0x1f8eae66c52b88, 0xe4fcbe9325be51},
+ {1, 0, 0, 0}},
+ {{0x825fdf583cac16, 0x020b857c7b023a, 0x683c17744b0165, 0x14ffd0a2daf2f1},
+ {0x323b36184218f9, 0x4944ec4e3b47d4, 0xc15b3080841acf, 0x0bced4b01a28bb},
+ {1, 0, 0, 0}},
+ {{0x92ac22230df5c4, 0x52f33b4063eda8, 0xcb3f19870c0c93, 0x40064f2ba65233},
+ {0xfe16f0924f8992, 0x012da25af5b517, 0x1a57bb24f723a6, 0x06f8bc76760def},
+ {1, 0, 0, 0}},
+ {{0x4a7084f7817cb9, 0xbcab0738ee9a78, 0x3ec11e11d9c326, 0xdc0fe90e0f1aae},
+ {0xcf639ea5f98390, 0x5c350aa22ffb74, 0x9afae98a4047b7, 0x956ec2d617fc45},
+ {1, 0, 0, 0}},
+ {{0x4306d648c1be6a, 0x9247cd8bc9a462, 0xf5595e377d2f2e, 0xbd1c3caff1a52e},
+ {0x045e14472409d0, 0x29f3e17078f773, 0x745a602b2d4f7d, 0x191837685cdfbb},
+ {1, 0, 0, 0}},
+ {{0x5b6ee254a8cb79, 0x4953433f5e7026, 0xe21faeb1d1def4, 0xc4c225785c09de},
+ {0x307ce7bba1e518, 0x31b125b1036db8, 0x47e91868839e8f, 0xc765866e33b9f3},
+ {1, 0, 0, 0}},
+ {{0x3bfece24f96906, 0x4794da641e5093, 0xde5df64f95db26, 0x297ecd89714b05},
+ {0x701bd3ebb2c3aa, 0x7073b4f53cb1d5, 0x13c5665658af16, 0x9895089d66fe58},
+ {1, 0, 0, 0}},
+ {{0x0fef05f78c4790, 0x2d773633b05d2e, 0x94229c3a951c94, 0xbbbd70df4911bb},
+ {0xb2c6963d2c1168, 0x105f47a72b0d73, 0x9fdf6111614080, 0x7b7e94b39e67b0},
+ {1, 0, 0, 0}},
+ {{0xad1a7d6efbe2b3, 0xf012482c0da69d, 0x6b3bdf12438345, 0x40d7558d7aa4d9},
+ {0x8a09fffb5c6d3d, 0x9a356e5d9ffd38, 0x5973f15f4f9b1c, 0xdcd5f59f63c3ea},
+ {1, 0, 0, 0}},
+ {{0xacf39f4c5ca7ab, 0x4c8071cc5fd737, 0xc64e3602cd1184, 0x0acd4644c9abba},
+ {0x6c011a36d8bf6e, 0xfecd87ba24e32a, 0x19f6f56574fad8, 0x050b204ced9405},
+ {1, 0, 0, 0}},
+ {{0xed4f1cae7d9a96, 0x5ceef7ad94c40a, 0x778e4a3bf3ef9b, 0x7405783dc3b55e},
+ {0x32477c61b6e8c6, 0xb46a97570f018b, 0x91176d0a7e95d1, 0x3df90fbc4c7d0e},
+ {1, 0, 0, 0}}}};
+
+/* Precomputation for the group generator. */
+typedef struct {
+ felem g_pre_comp[2][16][3];
+ int references;
+} NISTP224_PRE_COMP;
+
+const EC_METHOD *EC_GFp_nistp224_method(void)
+ {
+ static const EC_METHOD ret = {
+ EC_FLAGS_DEFAULT_OCT,
+ NID_X9_62_prime_field,
+ ec_GFp_nistp224_group_init,
+ ec_GFp_simple_group_finish,
+ ec_GFp_simple_group_clear_finish,
+ ec_GFp_nist_group_copy,
+ ec_GFp_nistp224_group_set_curve,
+ ec_GFp_simple_group_get_curve,
+ ec_GFp_simple_group_get_degree,
+ ec_GFp_simple_group_check_discriminant,
+ ec_GFp_simple_point_init,
+ ec_GFp_simple_point_finish,
+ ec_GFp_simple_point_clear_finish,
+ ec_GFp_simple_point_copy,
+ ec_GFp_simple_point_set_to_infinity,
+ ec_GFp_simple_set_Jprojective_coordinates_GFp,
+ ec_GFp_simple_get_Jprojective_coordinates_GFp,
+ ec_GFp_simple_point_set_affine_coordinates,
+ ec_GFp_nistp224_point_get_affine_coordinates,
+ 0 /* point_set_compressed_coordinates */,
+ 0 /* point2oct */,
+ 0 /* oct2point */,
+ ec_GFp_simple_add,
+ ec_GFp_simple_dbl,
+ ec_GFp_simple_invert,
+ ec_GFp_simple_is_at_infinity,
+ ec_GFp_simple_is_on_curve,
+ ec_GFp_simple_cmp,
+ ec_GFp_simple_make_affine,
+ ec_GFp_simple_points_make_affine,
+ ec_GFp_nistp224_points_mul,
+ ec_GFp_nistp224_precompute_mult,
+ ec_GFp_nistp224_have_precompute_mult,
+ ec_GFp_nist_field_mul,
+ ec_GFp_nist_field_sqr,
+ 0 /* field_div */,
+ 0 /* field_encode */,
+ 0 /* field_decode */,
+ 0 /* field_set_to_one */ };
+
+ return &ret;
+ }
+
+/* Helper functions to convert field elements to/from internal representation */
+static void bin28_to_felem(felem out, const u8 in[28])
+ {
+ out[0] = *((const uint64_t *)(in)) & 0x00ffffffffffffff;
+ out[1] = (*((const uint64_t *)(in+7))) & 0x00ffffffffffffff;
+ out[2] = (*((const uint64_t *)(in+14))) & 0x00ffffffffffffff;
+ out[3] = (*((const uint64_t *)(in+21))) & 0x00ffffffffffffff;
+ }
+
+static void felem_to_bin28(u8 out[28], const felem in)
+ {
+ unsigned i;
+ for (i = 0; i < 7; ++i)
+ {
+ out[i] = in[0]>>(8*i);
+ out[i+7] = in[1]>>(8*i);
+ out[i+14] = in[2]>>(8*i);
+ out[i+21] = in[3]>>(8*i);
+ }
+ }
+
+/* To preserve endianness when using BN_bn2bin and BN_bin2bn */
+static void flip_endian(u8 *out, const u8 *in, unsigned len)
+ {
+ unsigned i;
+ for (i = 0; i < len; ++i)
+ out[i] = in[len-1-i];
+ }
+
+/* From OpenSSL BIGNUM to internal representation */
+static int BN_to_felem(felem out, const BIGNUM *bn)
+ {
+ felem_bytearray b_in;
+ felem_bytearray b_out;
+ unsigned num_bytes;
+
+ /* BN_bn2bin eats leading zeroes */
+ memset(b_out, 0, sizeof b_out);
+ num_bytes = BN_num_bytes(bn);
+ if (num_bytes > sizeof b_out)
+ {
+ ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
+ return 0;
+ }
+ if (BN_is_negative(bn))
+ {
+ ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
+ return 0;
+ }
+ num_bytes = BN_bn2bin(bn, b_in);
+ flip_endian(b_out, b_in, num_bytes);
+ bin28_to_felem(out, b_out);
+ return 1;
+ }
+
+/* From internal representation to OpenSSL BIGNUM */
+static BIGNUM *felem_to_BN(BIGNUM *out, const felem in)
+ {
+ felem_bytearray b_in, b_out;
+ felem_to_bin28(b_in, in);
+ flip_endian(b_out, b_in, sizeof b_out);
+ return BN_bin2bn(b_out, sizeof b_out, out);
+ }
+
+/******************************************************************************/
+/* FIELD OPERATIONS
+ *
+ * Field operations, using the internal representation of field elements.
+ * NB! These operations are specific to our point multiplication and cannot be
+ * expected to be correct in general - e.g., multiplication with a large scalar
+ * will cause an overflow.
+ *
+ */
+
+static void felem_one(felem out)
+ {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ }
+
+static void felem_assign(felem out, const felem in)
+ {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ }
+
+/* Sum two field elements: out += in */
+static void felem_sum(felem out, const felem in)
+ {
+ out[0] += in[0];
+ out[1] += in[1];
+ out[2] += in[2];
+ out[3] += in[3];
+ }
+
+/* Get negative value: out = -in */
+/* Assumes in[i] < 2^57 */
+static void felem_neg(felem out, const felem in)
+ {
+ static const limb two58p2 = (((limb) 1) << 58) + (((limb) 1) << 2);
+ static const limb two58m2 = (((limb) 1) << 58) - (((limb) 1) << 2);
+ static const limb two58m42m2 = (((limb) 1) << 58) -
+ (((limb) 1) << 42) - (((limb) 1) << 2);
+
+ /* Set to 0 mod 2^224-2^96+1 to ensure out > in */
+ out[0] = two58p2 - in[0];
+ out[1] = two58m42m2 - in[1];
+ out[2] = two58m2 - in[2];
+ out[3] = two58m2 - in[3];
+ }
+
+/* Subtract field elements: out -= in */
+/* Assumes in[i] < 2^57 */
+static void felem_diff(felem out, const felem in)
+ {
+ static const limb two58p2 = (((limb) 1) << 58) + (((limb) 1) << 2);
+ static const limb two58m2 = (((limb) 1) << 58) - (((limb) 1) << 2);
+ static const limb two58m42m2 = (((limb) 1) << 58) -
+ (((limb) 1) << 42) - (((limb) 1) << 2);
+
+ /* Add 0 mod 2^224-2^96+1 to ensure out > in */
+ out[0] += two58p2;
+ out[1] += two58m42m2;
+ out[2] += two58m2;
+ out[3] += two58m2;
+
+ out[0] -= in[0];
+ out[1] -= in[1];
+ out[2] -= in[2];
+ out[3] -= in[3];
+ }
+
+/* Subtract in unreduced 128-bit mode: out -= in */
+/* Assumes in[i] < 2^119 */
+static void widefelem_diff(widefelem out, const widefelem in)
+ {
+ static const widelimb two120 = ((widelimb) 1) << 120;
+ static const widelimb two120m64 = (((widelimb) 1) << 120) -
+ (((widelimb) 1) << 64);
+ static const widelimb two120m104m64 = (((widelimb) 1) << 120) -
+ (((widelimb) 1) << 104) - (((widelimb) 1) << 64);
+
+ /* Add 0 mod 2^224-2^96+1 to ensure out > in */
+ out[0] += two120;
+ out[1] += two120m64;
+ out[2] += two120m64;
+ out[3] += two120;
+ out[4] += two120m104m64;
+ out[5] += two120m64;
+ out[6] += two120m64;
+
+ out[0] -= in[0];
+ out[1] -= in[1];
+ out[2] -= in[2];
+ out[3] -= in[3];
+ out[4] -= in[4];
+ out[5] -= in[5];
+ out[6] -= in[6];
+ }
+
+/* Subtract in mixed mode: out128 -= in64 */
+/* in[i] < 2^63 */
+static void felem_diff_128_64(widefelem out, const felem in)
+ {
+ static const widelimb two64p8 = (((widelimb) 1) << 64) +
+ (((widelimb) 1) << 8);
+ static const widelimb two64m8 = (((widelimb) 1) << 64) -
+ (((widelimb) 1) << 8);
+ static const widelimb two64m48m8 = (((widelimb) 1) << 64) -
+ (((widelimb) 1) << 48) - (((widelimb) 1) << 8);
+
+ /* Add 0 mod 2^224-2^96+1 to ensure out > in */
+ out[0] += two64p8;
+ out[1] += two64m48m8;
+ out[2] += two64m8;
+ out[3] += two64m8;
+
+ out[0] -= in[0];
+ out[1] -= in[1];
+ out[2] -= in[2];
+ out[3] -= in[3];
+ }
+
+/* Multiply a field element by a scalar: out = out * scalar
+ * The scalars we actually use are small, so results fit without overflow */
+static void felem_scalar(felem out, const limb scalar)
+ {
+ out[0] *= scalar;
+ out[1] *= scalar;
+ out[2] *= scalar;
+ out[3] *= scalar;
+ }
+
+/* Multiply an unreduced field element by a scalar: out = out * scalar
+ * The scalars we actually use are small, so results fit without overflow */
+static void widefelem_scalar(widefelem out, const widelimb scalar)
+ {
+ out[0] *= scalar;
+ out[1] *= scalar;
+ out[2] *= scalar;
+ out[3] *= scalar;
+ out[4] *= scalar;
+ out[5] *= scalar;
+ out[6] *= scalar;
+ }
+
+/* Square a field element: out = in^2 */
+static void felem_square(widefelem out, const felem in)
+ {
+ limb tmp0, tmp1, tmp2;
+ tmp0 = 2 * in[0]; tmp1 = 2 * in[1]; tmp2 = 2 * in[2];
+ out[0] = ((widelimb) in[0]) * in[0];
+ out[1] = ((widelimb) in[0]) * tmp1;
+ out[2] = ((widelimb) in[0]) * tmp2 + ((widelimb) in[1]) * in[1];
+ out[3] = ((widelimb) in[3]) * tmp0 +
+ ((widelimb) in[1]) * tmp2;
+ out[4] = ((widelimb) in[3]) * tmp1 + ((widelimb) in[2]) * in[2];
+ out[5] = ((widelimb) in[3]) * tmp2;
+ out[6] = ((widelimb) in[3]) * in[3];
+ }
+
+/* Multiply two field elements: out = in1 * in2 */
+static void felem_mul(widefelem out, const felem in1, const felem in2)
+ {
+ out[0] = ((widelimb) in1[0]) * in2[0];
+ out[1] = ((widelimb) in1[0]) * in2[1] + ((widelimb) in1[1]) * in2[0];
+ out[2] = ((widelimb) in1[0]) * in2[2] + ((widelimb) in1[1]) * in2[1] +
+ ((widelimb) in1[2]) * in2[0];
+ out[3] = ((widelimb) in1[0]) * in2[3] + ((widelimb) in1[1]) * in2[2] +
+ ((widelimb) in1[2]) * in2[1] + ((widelimb) in1[3]) * in2[0];
+ out[4] = ((widelimb) in1[1]) * in2[3] + ((widelimb) in1[2]) * in2[2] +
+ ((widelimb) in1[3]) * in2[1];
+ out[5] = ((widelimb) in1[2]) * in2[3] + ((widelimb) in1[3]) * in2[2];
+ out[6] = ((widelimb) in1[3]) * in2[3];
+ }
+
+/* Reduce seven 128-bit coefficients to four 64-bit coefficients.
+ * Requires in[i] < 2^126,
+ * ensures out[0] < 2^56, out[1] < 2^56, out[2] < 2^56, out[3] <= 2^56 + 2^16 */
+static void felem_reduce(felem out, const widefelem in)
+ {
+ static const widelimb two127p15 = (((widelimb) 1) << 127) +
+ (((widelimb) 1) << 15);
+ static const widelimb two127m71 = (((widelimb) 1) << 127) -
+ (((widelimb) 1) << 71);
+ static const widelimb two127m71m55 = (((widelimb) 1) << 127) -
+ (((widelimb) 1) << 71) - (((widelimb) 1) << 55);
+ widelimb output[5];
+
+ /* Add 0 mod 2^224-2^96+1 to ensure all differences are positive */
+ output[0] = in[0] + two127p15;
+ output[1] = in[1] + two127m71m55;
+ output[2] = in[2] + two127m71;
+ output[3] = in[3];
+ output[4] = in[4];
+
+ /* Eliminate in[4], in[5], in[6] */
+ output[4] += in[6] >> 16;
+ output[3] += (in[6] & 0xffff) << 40;
+ output[2] -= in[6];
+
+ output[3] += in[5] >> 16;
+ output[2] += (in[5] & 0xffff) << 40;
+ output[1] -= in[5];
+
+ output[2] += output[4] >> 16;
+ output[1] += (output[4] & 0xffff) << 40;
+ output[0] -= output[4];
+
+ /* Carry 2 -> 3 -> 4 */
+ output[3] += output[2] >> 56;
+ output[2] &= 0x00ffffffffffffff;
+
+ output[4] = output[3] >> 56;
+ output[3] &= 0x00ffffffffffffff;
+
+ /* Now output[2] < 2^56, output[3] < 2^56, output[4] < 2^72 */
+
+ /* Eliminate output[4] */
+ output[2] += output[4] >> 16;
+ /* output[2] < 2^56 + 2^56 = 2^57 */
+ output[1] += (output[4] & 0xffff) << 40;
+ output[0] -= output[4];
+
+ /* Carry 0 -> 1 -> 2 -> 3 */
+ output[1] += output[0] >> 56;
+ out[0] = output[0] & 0x00ffffffffffffff;
+
+ output[2] += output[1] >> 56;
+ /* output[2] < 2^57 + 2^72 */
+ out[1] = output[1] & 0x00ffffffffffffff;
+ output[3] += output[2] >> 56;
+ /* output[3] <= 2^56 + 2^16 */
+ out[2] = output[2] & 0x00ffffffffffffff;
+
+ /* out[0] < 2^56, out[1] < 2^56, out[2] < 2^56,
+ * out[3] <= 2^56 + 2^16 (due to final carry),
+ * so out < 2*p */
+ out[3] = output[3];
+ }
+
+static void felem_square_reduce(felem out, const felem in)
+ {
+ widefelem tmp;
+ felem_square(tmp, in);
+ felem_reduce(out, tmp);
+ }
+
+static void felem_mul_reduce(felem out, const felem in1, const felem in2)
+ {
+ widefelem tmp;
+ felem_mul(tmp, in1, in2);
+ felem_reduce(out, tmp);
+ }
+
+/* Reduce to unique minimal representation.
+ * Requires 0 <= in < 2*p (always call felem_reduce first) */
+static void felem_contract(felem out, const felem in)
+ {
+ static const int64_t two56 = ((limb) 1) << 56;
+ /* 0 <= in < 2*p, p = 2^224 - 2^96 + 1 */
+ /* if in > p , reduce in = in - 2^224 + 2^96 - 1 */
+ int64_t tmp[4], a;
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+ tmp[3] = in[3];
+ /* Case 1: a = 1 iff in >= 2^224 */
+ a = (in[3] >> 56);
+ tmp[0] -= a;
+ tmp[1] += a << 40;
+ tmp[3] &= 0x00ffffffffffffff;
+ /* Case 2: a = 0 iff p <= in < 2^224, i.e.,
+ * the high 128 bits are all 1 and the lower part is non-zero */
+ a = ((in[3] & in[2] & (in[1] | 0x000000ffffffffff)) + 1) |
+ (((int64_t)(in[0] + (in[1] & 0x000000ffffffffff)) - 1) >> 63);
+ a &= 0x00ffffffffffffff;
+ /* turn a into an all-one mask (if a = 0) or an all-zero mask */
+ a = (a - 1) >> 63;
+ /* subtract 2^224 - 2^96 + 1 if a is all-one*/
+ tmp[3] &= a ^ 0xffffffffffffffff;
+ tmp[2] &= a ^ 0xffffffffffffffff;
+ tmp[1] &= (a ^ 0xffffffffffffffff) | 0x000000ffffffffff;
+ tmp[0] -= 1 & a;
+
+ /* eliminate negative coefficients: if tmp[0] is negative, tmp[1] must
+ * be non-zero, so we only need one step */
+ a = tmp[0] >> 63;
+ tmp[0] += two56 & a;
+ tmp[1] -= 1 & a;
+
+ /* carry 1 -> 2 -> 3 */
+ tmp[2] += tmp[1] >> 56;
+ tmp[1] &= 0x00ffffffffffffff;
+
+ tmp[3] += tmp[2] >> 56;
+ tmp[2] &= 0x00ffffffffffffff;
+
+ /* Now 0 <= out < p */
+ out[0] = tmp[0];
+ out[1] = tmp[1];
+ out[2] = tmp[2];
+ out[3] = tmp[3];
+ }
+
+/* Zero-check: returns 1 if input is 0, and 0 otherwise.
+ * We know that field elements are reduced to in < 2^225,
+ * so we only need to check three cases: 0, 2^224 - 2^96 + 1,
+ * and 2^225 - 2^97 + 2 */
+static limb felem_is_zero(const felem in)
+ {
+ limb zero, two224m96p1, two225m97p2;
+
+ zero = in[0] | in[1] | in[2] | in[3];
+ zero = (((int64_t)(zero) - 1) >> 63) & 1;
+ two224m96p1 = (in[0] ^ 1) | (in[1] ^ 0x00ffff0000000000)
+ | (in[2] ^ 0x00ffffffffffffff) | (in[3] ^ 0x00ffffffffffffff);
+ two224m96p1 = (((int64_t)(two224m96p1) - 1) >> 63) & 1;
+ two225m97p2 = (in[0] ^ 2) | (in[1] ^ 0x00fffe0000000000)
+ | (in[2] ^ 0x00ffffffffffffff) | (in[3] ^ 0x01ffffffffffffff);
+ two225m97p2 = (((int64_t)(two225m97p2) - 1) >> 63) & 1;
+ return (zero | two224m96p1 | two225m97p2);
+ }
+
+static limb felem_is_zero_int(const felem in)
+ {
+ return (int) (felem_is_zero(in) & ((limb)1));
+ }
+
+/* Invert a field element */
+/* Computation chain copied from djb's code */
+static void felem_inv(felem out, const felem in)
+ {
+ felem ftmp, ftmp2, ftmp3, ftmp4;
+ widefelem tmp;
+ unsigned i;
+
+ felem_square(tmp, in); felem_reduce(ftmp, tmp); /* 2 */
+ felem_mul(tmp, in, ftmp); felem_reduce(ftmp, tmp); /* 2^2 - 1 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^3 - 2 */
+ felem_mul(tmp, in, ftmp); felem_reduce(ftmp, tmp); /* 2^3 - 1 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp2, tmp); /* 2^4 - 2 */
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); /* 2^5 - 4 */
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); /* 2^6 - 8 */
+ felem_mul(tmp, ftmp2, ftmp); felem_reduce(ftmp, tmp); /* 2^6 - 1 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp2, tmp); /* 2^7 - 2 */
+ for (i = 0; i < 5; ++i) /* 2^12 - 2^6 */
+ {
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp);
+ }
+ felem_mul(tmp, ftmp2, ftmp); felem_reduce(ftmp2, tmp); /* 2^12 - 1 */
+ felem_square(tmp, ftmp2); felem_reduce(ftmp3, tmp); /* 2^13 - 2 */
+ for (i = 0; i < 11; ++i) /* 2^24 - 2^12 */
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp);
+ }
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp2, tmp); /* 2^24 - 1 */
+ felem_square(tmp, ftmp2); felem_reduce(ftmp3, tmp); /* 2^25 - 2 */
+ for (i = 0; i < 23; ++i) /* 2^48 - 2^24 */
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp);
+ }
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^48 - 1 */
+ felem_square(tmp, ftmp3); felem_reduce(ftmp4, tmp); /* 2^49 - 2 */
+ for (i = 0; i < 47; ++i) /* 2^96 - 2^48 */
+ {
+ felem_square(tmp, ftmp4); felem_reduce(ftmp4, tmp);
+ }
+ felem_mul(tmp, ftmp3, ftmp4); felem_reduce(ftmp3, tmp); /* 2^96 - 1 */
+ felem_square(tmp, ftmp3); felem_reduce(ftmp4, tmp); /* 2^97 - 2 */
+ for (i = 0; i < 23; ++i) /* 2^120 - 2^24 */
+ {
+ felem_square(tmp, ftmp4); felem_reduce(ftmp4, tmp);
+ }
+ felem_mul(tmp, ftmp2, ftmp4); felem_reduce(ftmp2, tmp); /* 2^120 - 1 */
+ for (i = 0; i < 6; ++i) /* 2^126 - 2^6 */
+ {
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp);
+ }
+ felem_mul(tmp, ftmp2, ftmp); felem_reduce(ftmp, tmp); /* 2^126 - 1 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^127 - 2 */
+ felem_mul(tmp, ftmp, in); felem_reduce(ftmp, tmp); /* 2^127 - 1 */
+ for (i = 0; i < 97; ++i) /* 2^224 - 2^97 */
+ {
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp);
+ }
+ felem_mul(tmp, ftmp, ftmp3); felem_reduce(out, tmp); /* 2^224 - 2^96 - 1 */
+ }
+
+/* Copy in constant time:
+ * if icopy == 1, copy in to out,
+ * if icopy == 0, copy out to itself. */
+static void
+copy_conditional(felem out, const felem in, limb icopy)
+ {
+ unsigned i;
+ /* icopy is a (64-bit) 0 or 1, so copy is either all-zero or all-one */
+ const limb copy = -icopy;
+ for (i = 0; i < 4; ++i)
+ {
+ const limb tmp = copy & (in[i] ^ out[i]);
+ out[i] ^= tmp;
+ }
+ }
+
+/******************************************************************************/
+/* ELLIPTIC CURVE POINT OPERATIONS
+ *
+ * Points are represented in Jacobian projective coordinates:
+ * (X, Y, Z) corresponds to the affine point (X/Z^2, Y/Z^3),
+ * or to the point at infinity if Z == 0.
+ *
+ */
+
+/* Double an elliptic curve point:
+ * (X', Y', Z') = 2 * (X, Y, Z), where
+ * X' = (3 * (X - Z^2) * (X + Z^2))^2 - 8 * X * Y^2
+ * Y' = 3 * (X - Z^2) * (X + Z^2) * (4 * X * Y^2 - X') - 8 * Y^2
+ * Z' = (Y + Z)^2 - Y^2 - Z^2 = 2 * Y * Z
+ * Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed,
+ * while x_out == y_in is not (maybe this works, but it's not tested). */
+static void
+point_double(felem x_out, felem y_out, felem z_out,
+ const felem x_in, const felem y_in, const felem z_in)
+ {
+ widefelem tmp, tmp2;
+ felem delta, gamma, beta, alpha, ftmp, ftmp2;
+
+ felem_assign(ftmp, x_in);
+ felem_assign(ftmp2, x_in);
+
+ /* delta = z^2 */
+ felem_square(tmp, z_in);
+ felem_reduce(delta, tmp);
+
+ /* gamma = y^2 */
+ felem_square(tmp, y_in);
+ felem_reduce(gamma, tmp);
+
+ /* beta = x*gamma */
+ felem_mul(tmp, x_in, gamma);
+ felem_reduce(beta, tmp);
+
+ /* alpha = 3*(x-delta)*(x+delta) */
+ felem_diff(ftmp, delta);
+ /* ftmp[i] < 2^57 + 2^58 + 2 < 2^59 */
+ felem_sum(ftmp2, delta);
+ /* ftmp2[i] < 2^57 + 2^57 = 2^58 */
+ felem_scalar(ftmp2, 3);
+ /* ftmp2[i] < 3 * 2^58 < 2^60 */
+ felem_mul(tmp, ftmp, ftmp2);
+ /* tmp[i] < 2^60 * 2^59 * 4 = 2^121 */
+ felem_reduce(alpha, tmp);
+
+ /* x' = alpha^2 - 8*beta */
+ felem_square(tmp, alpha);
+ /* tmp[i] < 4 * 2^57 * 2^57 = 2^116 */
+ felem_assign(ftmp, beta);
+ felem_scalar(ftmp, 8);
+ /* ftmp[i] < 8 * 2^57 = 2^60 */
+ felem_diff_128_64(tmp, ftmp);
+ /* tmp[i] < 2^116 + 2^64 + 8 < 2^117 */
+ felem_reduce(x_out, tmp);
+
+ /* z' = (y + z)^2 - gamma - delta */
+ felem_sum(delta, gamma);
+ /* delta[i] < 2^57 + 2^57 = 2^58 */
+ felem_assign(ftmp, y_in);
+ felem_sum(ftmp, z_in);
+ /* ftmp[i] < 2^57 + 2^57 = 2^58 */
+ felem_square(tmp, ftmp);
+ /* tmp[i] < 4 * 2^58 * 2^58 = 2^118 */
+ felem_diff_128_64(tmp, delta);
+ /* tmp[i] < 2^118 + 2^64 + 8 < 2^119 */
+ felem_reduce(z_out, tmp);
+
+ /* y' = alpha*(4*beta - x') - 8*gamma^2 */
+ felem_scalar(beta, 4);
+ /* beta[i] < 4 * 2^57 = 2^59 */
+ felem_diff(beta, x_out);
+ /* beta[i] < 2^59 + 2^58 + 2 < 2^60 */
+ felem_mul(tmp, alpha, beta);
+ /* tmp[i] < 4 * 2^57 * 2^60 = 2^119 */
+ felem_square(tmp2, gamma);
+ /* tmp2[i] < 4 * 2^57 * 2^57 = 2^116 */
+ widefelem_scalar(tmp2, 8);
+ /* tmp2[i] < 8 * 2^116 = 2^119 */
+ widefelem_diff(tmp, tmp2);
+ /* tmp[i] < 2^119 + 2^120 < 2^121 */
+ felem_reduce(y_out, tmp);
+ }
+
+/* Add two elliptic curve points:
+ * (X_1, Y_1, Z_1) + (X_2, Y_2, Z_2) = (X_3, Y_3, Z_3), where
+ * X_3 = (Z_1^3 * Y_2 - Z_2^3 * Y_1)^2 - (Z_1^2 * X_2 - Z_2^2 * X_1)^3 -
+ * 2 * Z_2^2 * X_1 * (Z_1^2 * X_2 - Z_2^2 * X_1)^2
+ * Y_3 = (Z_1^3 * Y_2 - Z_2^3 * Y_1) * (Z_2^2 * X_1 * (Z_1^2 * X_2 - Z_2^2 * X_1)^2 - X_3) -
+ * Z_2^3 * Y_1 * (Z_1^2 * X_2 - Z_2^2 * X_1)^3
+ * Z_3 = (Z_1^2 * X_2 - Z_2^2 * X_1) * (Z_1 * Z_2)
+ *
+ * This runs faster if 'mixed' is set, which requires Z_2 = 1 or Z_2 = 0.
+ */
+
+/* This function is not entirely constant-time:
+ * it includes a branch for checking whether the two input points are equal,
+ * (while not equal to the point at infinity).
+ * This case never happens during single point multiplication,
+ * so there is no timing leak for ECDH or ECDSA signing. */
+static void point_add(felem x3, felem y3, felem z3,
+ const felem x1, const felem y1, const felem z1,
+ const int mixed, const felem x2, const felem y2, const felem z2)
+ {
+ felem ftmp, ftmp2, ftmp3, ftmp4, ftmp5, x_out, y_out, z_out;
+ widefelem tmp, tmp2;
+ limb z1_is_zero, z2_is_zero, x_equal, y_equal;
+
+ if (!mixed)
+ {
+ /* ftmp2 = z2^2 */
+ felem_square(tmp, z2);
+ felem_reduce(ftmp2, tmp);
+
+ /* ftmp4 = z2^3 */
+ felem_mul(tmp, ftmp2, z2);
+ felem_reduce(ftmp4, tmp);
+
+ /* ftmp4 = z2^3*y1 */
+ felem_mul(tmp2, ftmp4, y1);
+ felem_reduce(ftmp4, tmp2);
+
+ /* ftmp2 = z2^2*x1 */
+ felem_mul(tmp2, ftmp2, x1);
+ felem_reduce(ftmp2, tmp2);
+ }
+ else
+ {
+ /* We'll assume z2 = 1 (special case z2 = 0 is handled later) */
+
+ /* ftmp4 = z2^3*y1 */
+ felem_assign(ftmp4, y1);
+
+ /* ftmp2 = z2^2*x1 */
+ felem_assign(ftmp2, x1);
+ }
+
+ /* ftmp = z1^2 */
+ felem_square(tmp, z1);
+ felem_reduce(ftmp, tmp);
+
+ /* ftmp3 = z1^3 */
+ felem_mul(tmp, ftmp, z1);
+ felem_reduce(ftmp3, tmp);
+
+ /* tmp = z1^3*y2 */
+ felem_mul(tmp, ftmp3, y2);
+ /* tmp[i] < 4 * 2^57 * 2^57 = 2^116 */
+
+ /* ftmp3 = z1^3*y2 - z2^3*y1 */
+ felem_diff_128_64(tmp, ftmp4);
+ /* tmp[i] < 2^116 + 2^64 + 8 < 2^117 */
+ felem_reduce(ftmp3, tmp);
+
+ /* tmp = z1^2*x2 */
+ felem_mul(tmp, ftmp, x2);
+ /* tmp[i] < 4 * 2^57 * 2^57 = 2^116 */
+
+ /* ftmp = z1^2*x2 - z2^2*x1 */
+ felem_diff_128_64(tmp, ftmp2);
+ /* tmp[i] < 2^116 + 2^64 + 8 < 2^117 */
+ felem_reduce(ftmp, tmp);
+
+ /* the formulae are incorrect if the points are equal
+ * so we check for this and do doubling if this happens */
+ x_equal = felem_is_zero(ftmp);
+ y_equal = felem_is_zero(ftmp3);
+ z1_is_zero = felem_is_zero(z1);
+ z2_is_zero = felem_is_zero(z2);
+ /* In affine coordinates, (X_1, Y_1) == (X_2, Y_2) */
+ if (x_equal && y_equal && !z1_is_zero && !z2_is_zero)
+ {
+ point_double(x3, y3, z3, x1, y1, z1);
+ return;
+ }
+
+ /* ftmp5 = z1*z2 */
+ if (!mixed)
+ {
+ felem_mul(tmp, z1, z2);
+ felem_reduce(ftmp5, tmp);
+ }
+ else
+ {
+ /* special case z2 = 0 is handled later */
+ felem_assign(ftmp5, z1);
+ }
+
+ /* z_out = (z1^2*x2 - z2^2*x1)*(z1*z2) */
+ felem_mul(tmp, ftmp, ftmp5);
+ felem_reduce(z_out, tmp);
+
+ /* ftmp = (z1^2*x2 - z2^2*x1)^2 */
+ felem_assign(ftmp5, ftmp);
+ felem_square(tmp, ftmp);
+ felem_reduce(ftmp, tmp);
+
+ /* ftmp5 = (z1^2*x2 - z2^2*x1)^3 */
+ felem_mul(tmp, ftmp, ftmp5);
+ felem_reduce(ftmp5, tmp);
+
+ /* ftmp2 = z2^2*x1*(z1^2*x2 - z2^2*x1)^2 */
+ felem_mul(tmp, ftmp2, ftmp);
+ felem_reduce(ftmp2, tmp);
+
+ /* tmp = z2^3*y1*(z1^2*x2 - z2^2*x1)^3 */
+ felem_mul(tmp, ftmp4, ftmp5);
+ /* tmp[i] < 4 * 2^57 * 2^57 = 2^116 */
+
+ /* tmp2 = (z1^3*y2 - z2^3*y1)^2 */
+ felem_square(tmp2, ftmp3);
+ /* tmp2[i] < 4 * 2^57 * 2^57 < 2^116 */
+
+ /* tmp2 = (z1^3*y2 - z2^3*y1)^2 - (z1^2*x2 - z2^2*x1)^3 */
+ felem_diff_128_64(tmp2, ftmp5);
+ /* tmp2[i] < 2^116 + 2^64 + 8 < 2^117 */
+
+ /* ftmp5 = 2*z2^2*x1*(z1^2*x2 - z2^2*x1)^2 */
+ felem_assign(ftmp5, ftmp2);
+ felem_scalar(ftmp5, 2);
+ /* ftmp5[i] < 2 * 2^57 = 2^58 */
+
+ /* x_out = (z1^3*y2 - z2^3*y1)^2 - (z1^2*x2 - z2^2*x1)^3 -
+ 2*z2^2*x1*(z1^2*x2 - z2^2*x1)^2 */
+ felem_diff_128_64(tmp2, ftmp5);
+ /* tmp2[i] < 2^117 + 2^64 + 8 < 2^118 */
+ felem_reduce(x_out, tmp2);
+
+ /* ftmp2 = z2^2*x1*(z1^2*x2 - z2^2*x1)^2 - x_out */
+ felem_diff(ftmp2, x_out);
+ /* ftmp2[i] < 2^57 + 2^58 + 2 < 2^59 */
+
+ /* tmp2 = (z1^3*y2 - z2^3*y1)*(z2^2*x1*(z1^2*x2 - z2^2*x1)^2 - x_out) */
+ felem_mul(tmp2, ftmp3, ftmp2);
+ /* tmp2[i] < 4 * 2^57 * 2^59 = 2^118 */
+
+ /* y_out = (z1^3*y2 - z2^3*y1)*(z2^2*x1*(z1^2*x2 - z2^2*x1)^2 - x_out) -
+ z2^3*y1*(z1^2*x2 - z2^2*x1)^3 */
+ widefelem_diff(tmp2, tmp);
+ /* tmp2[i] < 2^118 + 2^120 < 2^121 */
+ felem_reduce(y_out, tmp2);
+
+ /* the result (x_out, y_out, z_out) is incorrect if one of the inputs is
+ * the point at infinity, so we need to check for this separately */
+
+ /* if point 1 is at infinity, copy point 2 to output, and vice versa */
+ copy_conditional(x_out, x2, z1_is_zero);
+ copy_conditional(x_out, x1, z2_is_zero);
+ copy_conditional(y_out, y2, z1_is_zero);
+ copy_conditional(y_out, y1, z2_is_zero);
+ copy_conditional(z_out, z2, z1_is_zero);
+ copy_conditional(z_out, z1, z2_is_zero);
+ felem_assign(x3, x_out);
+ felem_assign(y3, y_out);
+ felem_assign(z3, z_out);
+ }
+
+/* select_point selects the |idx|th point from a precomputation table and
+ * copies it to out. */
+static void select_point(const u64 idx, unsigned int size, const felem pre_comp[/*size*/][3], felem out[3])
+ {
+ unsigned i, j;
+ limb *outlimbs = &out[0][0];
+ memset(outlimbs, 0, 3 * sizeof(felem));
+
+ for (i = 0; i < size; i++)
+ {
+ const limb *inlimbs = &pre_comp[i][0][0];
+ u64 mask = i ^ idx;
+ mask |= mask >> 4;
+ mask |= mask >> 2;
+ mask |= mask >> 1;
+ mask &= 1;
+ mask--;
+ for (j = 0; j < 4 * 3; j++)
+ outlimbs[j] |= inlimbs[j] & mask;
+ }
+ }
+
+/* get_bit returns the |i|th bit in |in| */
+static char get_bit(const felem_bytearray in, unsigned i)
+ {
+ if (i >= 224)
+ return 0;
+ return (in[i >> 3] >> (i & 7)) & 1;
+ }
+
+/* Interleaved point multiplication using precomputed point multiples:
+ * The small point multiples 0*P, 1*P, ..., 16*P are in pre_comp[],
+ * the scalars in scalars[]. If g_scalar is non-NULL, we also add this multiple
+ * of the generator, using certain (large) precomputed multiples in g_pre_comp.
+ * Output point (X, Y, Z) is stored in x_out, y_out, z_out */
+static void batch_mul(felem x_out, felem y_out, felem z_out,
+ const felem_bytearray scalars[], const unsigned num_points, const u8 *g_scalar,
+ const int mixed, const felem pre_comp[][17][3], const felem g_pre_comp[2][16][3])
+ {
+ int i, skip;
+ unsigned num;
+ unsigned gen_mul = (g_scalar != NULL);
+ felem nq[3], tmp[4];
+ u64 bits;
+ u8 sign, digit;
+
+ /* set nq to the point at infinity */
+ memset(nq, 0, 3 * sizeof(felem));
+
+ /* Loop over all scalars msb-to-lsb, interleaving additions
+ * of multiples of the generator (two in each of the last 28 rounds)
+ * and additions of other points multiples (every 5th round).
+ */
+ skip = 1; /* save two point operations in the first round */
+ for (i = (num_points ? 220 : 27); i >= 0; --i)
+ {
+ /* double */
+ if (!skip)
+ point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]);
+
+ /* add multiples of the generator */
+ if (gen_mul && (i <= 27))
+ {
+ /* first, look 28 bits upwards */
+ bits = get_bit(g_scalar, i + 196) << 3;
+ bits |= get_bit(g_scalar, i + 140) << 2;
+ bits |= get_bit(g_scalar, i + 84) << 1;
+ bits |= get_bit(g_scalar, i + 28);
+ /* select the point to add, in constant time */
+ select_point(bits, 16, g_pre_comp[1], tmp);
+
+ if (!skip)
+ {
+ point_add(nq[0], nq[1], nq[2],
+ nq[0], nq[1], nq[2],
+ 1 /* mixed */, tmp[0], tmp[1], tmp[2]);
+ }
+ else
+ {
+ memcpy(nq, tmp, 3 * sizeof(felem));
+ skip = 0;
+ }
+
+ /* second, look at the current position */
+ bits = get_bit(g_scalar, i + 168) << 3;
+ bits |= get_bit(g_scalar, i + 112) << 2;
+ bits |= get_bit(g_scalar, i + 56) << 1;
+ bits |= get_bit(g_scalar, i);
+ /* select the point to add, in constant time */
+ select_point(bits, 16, g_pre_comp[0], tmp);
+ point_add(nq[0], nq[1], nq[2],
+ nq[0], nq[1], nq[2],
+ 1 /* mixed */, tmp[0], tmp[1], tmp[2]);
+ }
+
+ /* do other additions every 5 doublings */
+ if (num_points && (i % 5 == 0))
+ {
+ /* loop over all scalars */
+ for (num = 0; num < num_points; ++num)
+ {
+ bits = get_bit(scalars[num], i + 4) << 5;
+ bits |= get_bit(scalars[num], i + 3) << 4;
+ bits |= get_bit(scalars[num], i + 2) << 3;
+ bits |= get_bit(scalars[num], i + 1) << 2;
+ bits |= get_bit(scalars[num], i) << 1;
+ bits |= get_bit(scalars[num], i - 1);
+ ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits);
+
+ /* select the point to add or subtract */
+ select_point(digit, 17, pre_comp[num], tmp);
+ felem_neg(tmp[3], tmp[1]); /* (X, -Y, Z) is the negative point */
+ copy_conditional(tmp[1], tmp[3], sign);
+
+ if (!skip)
+ {
+ point_add(nq[0], nq[1], nq[2],
+ nq[0], nq[1], nq[2],
+ mixed, tmp[0], tmp[1], tmp[2]);
+ }
+ else
+ {
+ memcpy(nq, tmp, 3 * sizeof(felem));
+ skip = 0;
+ }
+ }
+ }
+ }
+ felem_assign(x_out, nq[0]);
+ felem_assign(y_out, nq[1]);
+ felem_assign(z_out, nq[2]);
+ }
+
+/******************************************************************************/
+/* FUNCTIONS TO MANAGE PRECOMPUTATION
+ */
+
+static NISTP224_PRE_COMP *nistp224_pre_comp_new()
+ {
+ NISTP224_PRE_COMP *ret = NULL;
+ ret = (NISTP224_PRE_COMP *) OPENSSL_malloc(sizeof *ret);
+ if (!ret)
+ {
+ ECerr(EC_F_NISTP224_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
+ return ret;
+ }
+ memset(ret->g_pre_comp, 0, sizeof(ret->g_pre_comp));
+ ret->references = 1;
+ return ret;
+ }
+
+static void *nistp224_pre_comp_dup(void *src_)
+ {
+ NISTP224_PRE_COMP *src = src_;
+
+ /* no need to actually copy, these objects never change! */
+ CRYPTO_add(&src->references, 1, CRYPTO_LOCK_EC_PRE_COMP);
+
+ return src_;
+ }
+
+static void nistp224_pre_comp_free(void *pre_)
+ {
+ int i;
+ NISTP224_PRE_COMP *pre = pre_;
+
+ if (!pre)
+ return;
+
+ i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
+ if (i > 0)
+ return;
+
+ OPENSSL_free(pre);
+ }
+
+static void nistp224_pre_comp_clear_free(void *pre_)
+ {
+ int i;
+ NISTP224_PRE_COMP *pre = pre_;
+
+ if (!pre)
+ return;
+
+ i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
+ if (i > 0)
+ return;
+
+ OPENSSL_cleanse(pre, sizeof *pre);
+ OPENSSL_free(pre);
+ }
+
+/******************************************************************************/
+/* OPENSSL EC_METHOD FUNCTIONS
+ */
+
+int ec_GFp_nistp224_group_init(EC_GROUP *group)
+ {
+ int ret;
+ ret = ec_GFp_simple_group_init(group);
+ group->a_is_minus3 = 1;
+ return ret;
+ }
+
+int ec_GFp_nistp224_group_set_curve(EC_GROUP *group, const BIGNUM *p,
+ const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
+ {
+ int ret = 0;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *curve_p, *curve_a, *curve_b;
+
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((curve_p = BN_CTX_get(ctx)) == NULL) ||
+ ((curve_a = BN_CTX_get(ctx)) == NULL) ||
+ ((curve_b = BN_CTX_get(ctx)) == NULL)) goto err;
+ BN_bin2bn(nistp224_curve_params[0], sizeof(felem_bytearray), curve_p);
+ BN_bin2bn(nistp224_curve_params[1], sizeof(felem_bytearray), curve_a);
+ BN_bin2bn(nistp224_curve_params[2], sizeof(felem_bytearray), curve_b);
+ if ((BN_cmp(curve_p, p)) || (BN_cmp(curve_a, a)) ||
+ (BN_cmp(curve_b, b)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP224_GROUP_SET_CURVE,
+ EC_R_WRONG_CURVE_PARAMETERS);
+ goto err;
+ }
+ group->field_mod_func = BN_nist_mod_224;
+ ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+ }
+
+/* Takes the Jacobian coordinates (X, Y, Z) of a point and returns
+ * (X', Y') = (X/Z^2, Y/Z^3) */
+int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
+ {
+ felem z1, z2, x_in, y_in, x_out, y_out;
+ widefelem tmp;
+
+ if (EC_POINT_is_at_infinity(group, point))
+ {
+ ECerr(EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES,
+ EC_R_POINT_AT_INFINITY);
+ return 0;
+ }
+ if ((!BN_to_felem(x_in, &point->X)) || (!BN_to_felem(y_in, &point->Y)) ||
+ (!BN_to_felem(z1, &point->Z))) return 0;
+ felem_inv(z2, z1);
+ felem_square(tmp, z2); felem_reduce(z1, tmp);
+ felem_mul(tmp, x_in, z1); felem_reduce(x_in, tmp);
+ felem_contract(x_out, x_in);
+ if (x != NULL)
+ {
+ if (!felem_to_BN(x, x_out)) {
+ ECerr(EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES,
+ ERR_R_BN_LIB);
+ return 0;
+ }
+ }
+ felem_mul(tmp, z1, z2); felem_reduce(z1, tmp);
+ felem_mul(tmp, y_in, z1); felem_reduce(y_in, tmp);
+ felem_contract(y_out, y_in);
+ if (y != NULL)
+ {
+ if (!felem_to_BN(y, y_out)) {
+ ECerr(EC_F_EC_GFP_NISTP224_POINT_GET_AFFINE_COORDINATES,
+ ERR_R_BN_LIB);
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+static void make_points_affine(size_t num, felem points[/*num*/][3], felem tmp_felems[/*num+1*/])
+ {
+ /* Runs in constant time, unless an input is the point at infinity
+ * (which normally shouldn't happen). */
+ ec_GFp_nistp_points_make_affine_internal(
+ num,
+ points,
+ sizeof(felem),
+ tmp_felems,
+ (void (*)(void *)) felem_one,
+ (int (*)(const void *)) felem_is_zero_int,
+ (void (*)(void *, const void *)) felem_assign,
+ (void (*)(void *, const void *)) felem_square_reduce,
+ (void (*)(void *, const void *, const void *)) felem_mul_reduce,
+ (void (*)(void *, const void *)) felem_inv,
+ (void (*)(void *, const void *)) felem_contract);
+ }
+
+/* Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL values
+ * Result is stored in r (r can equal one of the inputs). */
+int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
+ const BIGNUM *scalar, size_t num, const EC_POINT *points[],
+ const BIGNUM *scalars[], BN_CTX *ctx)
+ {
+ int ret = 0;
+ int j;
+ unsigned i;
+ int mixed = 0;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y, *z, *tmp_scalar;
+ felem_bytearray g_secret;
+ felem_bytearray *secrets = NULL;
+ felem (*pre_comp)[17][3] = NULL;
+ felem *tmp_felems = NULL;
+ felem_bytearray tmp;
+ unsigned num_bytes;
+ int have_pre_comp = 0;
+ size_t num_points = num;
+ felem x_in, y_in, z_in, x_out, y_out, z_out;
+ NISTP224_PRE_COMP *pre = NULL;
+ const felem (*g_pre_comp)[16][3] = NULL;
+ EC_POINT *generator = NULL;
+ const EC_POINT *p = NULL;
+ const BIGNUM *p_scalar = NULL;
+
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((x = BN_CTX_get(ctx)) == NULL) ||
+ ((y = BN_CTX_get(ctx)) == NULL) ||
+ ((z = BN_CTX_get(ctx)) == NULL) ||
+ ((tmp_scalar = BN_CTX_get(ctx)) == NULL))
+ goto err;
+
+ if (scalar != NULL)
+ {
+ pre = EC_EX_DATA_get_data(group->extra_data,
+ nistp224_pre_comp_dup, nistp224_pre_comp_free,
+ nistp224_pre_comp_clear_free);
+ if (pre)
+ /* we have precomputation, try to use it */
+ g_pre_comp = (const felem (*)[16][3]) pre->g_pre_comp;
+ else
+ /* try to use the standard precomputation */
+ g_pre_comp = &gmul[0];
+ generator = EC_POINT_new(group);
+ if (generator == NULL)
+ goto err;
+ /* get the generator from precomputation */
+ if (!felem_to_BN(x, g_pre_comp[0][1][0]) ||
+ !felem_to_BN(y, g_pre_comp[0][1][1]) ||
+ !felem_to_BN(z, g_pre_comp[0][1][2]))
+ {
+ ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ if (!EC_POINT_set_Jprojective_coordinates_GFp(group,
+ generator, x, y, z, ctx))
+ goto err;
+ if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
+ /* precomputation matches generator */
+ have_pre_comp = 1;
+ else
+ /* we don't have valid precomputation:
+ * treat the generator as a random point */
+ num_points = num_points + 1;
+ }
+
+ if (num_points > 0)
+ {
+ if (num_points >= 3)
+ {
+ /* unless we precompute multiples for just one or two points,
+ * converting those into affine form is time well spent */
+ mixed = 1;
+ }
+ secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray));
+ pre_comp = OPENSSL_malloc(num_points * 17 * 3 * sizeof(felem));
+ if (mixed)
+ tmp_felems = OPENSSL_malloc((num_points * 17 + 1) * sizeof(felem));
+ if ((secrets == NULL) || (pre_comp == NULL) || (mixed && (tmp_felems == NULL)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* we treat NULL scalars as 0, and NULL points as points at infinity,
+ * i.e., they contribute nothing to the linear combination */
+ memset(secrets, 0, num_points * sizeof(felem_bytearray));
+ memset(pre_comp, 0, num_points * 17 * 3 * sizeof(felem));
+ for (i = 0; i < num_points; ++i)
+ {
+ if (i == num)
+ /* the generator */
+ {
+ p = EC_GROUP_get0_generator(group);
+ p_scalar = scalar;
+ }
+ else
+ /* the i^th point */
+ {
+ p = points[i];
+ p_scalar = scalars[i];
+ }
+ if ((p_scalar != NULL) && (p != NULL))
+ {
+ /* reduce scalar to 0 <= scalar < 2^224 */
+ if ((BN_num_bits(p_scalar) > 224) || (BN_is_negative(p_scalar)))
+ {
+ /* this is an unusual input, and we don't guarantee
+ * constant-timeness */
+ if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx))
+ {
+ ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ num_bytes = BN_bn2bin(tmp_scalar, tmp);
+ }
+ else
+ num_bytes = BN_bn2bin(p_scalar, tmp);
+ flip_endian(secrets[i], tmp, num_bytes);
+ /* precompute multiples */
+ if ((!BN_to_felem(x_out, &p->X)) ||
+ (!BN_to_felem(y_out, &p->Y)) ||
+ (!BN_to_felem(z_out, &p->Z))) goto err;
+ felem_assign(pre_comp[i][1][0], x_out);
+ felem_assign(pre_comp[i][1][1], y_out);
+ felem_assign(pre_comp[i][1][2], z_out);
+ for (j = 2; j <= 16; ++j)
+ {
+ if (j & 1)
+ {
+ point_add(
+ pre_comp[i][j][0], pre_comp[i][j][1], pre_comp[i][j][2],
+ pre_comp[i][1][0], pre_comp[i][1][1], pre_comp[i][1][2],
+ 0, pre_comp[i][j-1][0], pre_comp[i][j-1][1], pre_comp[i][j-1][2]);
+ }
+ else
+ {
+ point_double(
+ pre_comp[i][j][0], pre_comp[i][j][1], pre_comp[i][j][2],
+ pre_comp[i][j/2][0], pre_comp[i][j/2][1], pre_comp[i][j/2][2]);
+ }
+ }
+ }
+ }
+ if (mixed)
+ make_points_affine(num_points * 17, pre_comp[0], tmp_felems);
+ }
+
+ /* the scalar for the generator */
+ if ((scalar != NULL) && (have_pre_comp))
+ {
+ memset(g_secret, 0, sizeof g_secret);
+ /* reduce scalar to 0 <= scalar < 2^224 */
+ if ((BN_num_bits(scalar) > 224) || (BN_is_negative(scalar)))
+ {
+ /* this is an unusual input, and we don't guarantee
+ * constant-timeness */
+ if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx))
+ {
+ ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ num_bytes = BN_bn2bin(tmp_scalar, tmp);
+ }
+ else
+ num_bytes = BN_bn2bin(scalar, tmp);
+ flip_endian(g_secret, tmp, num_bytes);
+ /* do the multiplication with generator precomputation*/
+ batch_mul(x_out, y_out, z_out,
+ (const felem_bytearray (*)) secrets, num_points,
+ g_secret,
+ mixed, (const felem (*)[17][3]) pre_comp,
+ g_pre_comp);
+ }
+ else
+ /* do the multiplication without generator precomputation */
+ batch_mul(x_out, y_out, z_out,
+ (const felem_bytearray (*)) secrets, num_points,
+ NULL, mixed, (const felem (*)[17][3]) pre_comp, NULL);
+ /* reduce the output to its unique minimal representation */
+ felem_contract(x_in, x_out);
+ felem_contract(y_in, y_out);
+ felem_contract(z_in, z_out);
+ if ((!felem_to_BN(x, x_in)) || (!felem_to_BN(y, y_in)) ||
+ (!felem_to_BN(z, z_in)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP224_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ ret = EC_POINT_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx);
+
+err:
+ BN_CTX_end(ctx);
+ if (generator != NULL)
+ EC_POINT_free(generator);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (secrets != NULL)
+ OPENSSL_free(secrets);
+ if (pre_comp != NULL)
+ OPENSSL_free(pre_comp);
+ if (tmp_felems != NULL)
+ OPENSSL_free(tmp_felems);
+ return ret;
+ }
+
+int ec_GFp_nistp224_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
+ {
+ int ret = 0;
+ NISTP224_PRE_COMP *pre = NULL;
+ int i, j;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y;
+ EC_POINT *generator = NULL;
+ felem tmp_felems[32];
+
+ /* throw away old precomputation */
+ EC_EX_DATA_free_data(&group->extra_data, nistp224_pre_comp_dup,
+ nistp224_pre_comp_free, nistp224_pre_comp_clear_free);
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((x = BN_CTX_get(ctx)) == NULL) ||
+ ((y = BN_CTX_get(ctx)) == NULL))
+ goto err;
+ /* get the generator */
+ if (group->generator == NULL) goto err;
+ generator = EC_POINT_new(group);
+ if (generator == NULL)
+ goto err;
+ BN_bin2bn(nistp224_curve_params[3], sizeof (felem_bytearray), x);
+ BN_bin2bn(nistp224_curve_params[4], sizeof (felem_bytearray), y);
+ if (!EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, ctx))
+ goto err;
+ if ((pre = nistp224_pre_comp_new()) == NULL)
+ goto err;
+ /* if the generator is the standard one, use built-in precomputation */
+ if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
+ {
+ memcpy(pre->g_pre_comp, gmul, sizeof(pre->g_pre_comp));
+ ret = 1;
+ goto err;
+ }
+ if ((!BN_to_felem(pre->g_pre_comp[0][1][0], &group->generator->X)) ||
+ (!BN_to_felem(pre->g_pre_comp[0][1][1], &group->generator->Y)) ||
+ (!BN_to_felem(pre->g_pre_comp[0][1][2], &group->generator->Z)))
+ goto err;
+ /* compute 2^56*G, 2^112*G, 2^168*G for the first table,
+ * 2^28*G, 2^84*G, 2^140*G, 2^196*G for the second one
+ */
+ for (i = 1; i <= 8; i <<= 1)
+ {
+ point_double(
+ pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2],
+ pre->g_pre_comp[0][i][0], pre->g_pre_comp[0][i][1], pre->g_pre_comp[0][i][2]);
+ for (j = 0; j < 27; ++j)
+ {
+ point_double(
+ pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2],
+ pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2]);
+ }
+ if (i == 8)
+ break;
+ point_double(
+ pre->g_pre_comp[0][2*i][0], pre->g_pre_comp[0][2*i][1], pre->g_pre_comp[0][2*i][2],
+ pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2]);
+ for (j = 0; j < 27; ++j)
+ {
+ point_double(
+ pre->g_pre_comp[0][2*i][0], pre->g_pre_comp[0][2*i][1], pre->g_pre_comp[0][2*i][2],
+ pre->g_pre_comp[0][2*i][0], pre->g_pre_comp[0][2*i][1], pre->g_pre_comp[0][2*i][2]);
+ }
+ }
+ for (i = 0; i < 2; i++)
+ {
+ /* g_pre_comp[i][0] is the point at infinity */
+ memset(pre->g_pre_comp[i][0], 0, sizeof(pre->g_pre_comp[i][0]));
+ /* the remaining multiples */
+ /* 2^56*G + 2^112*G resp. 2^84*G + 2^140*G */
+ point_add(
+ pre->g_pre_comp[i][6][0], pre->g_pre_comp[i][6][1],
+ pre->g_pre_comp[i][6][2], pre->g_pre_comp[i][4][0],
+ pre->g_pre_comp[i][4][1], pre->g_pre_comp[i][4][2],
+ 0, pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
+ pre->g_pre_comp[i][2][2]);
+ /* 2^56*G + 2^168*G resp. 2^84*G + 2^196*G */
+ point_add(
+ pre->g_pre_comp[i][10][0], pre->g_pre_comp[i][10][1],
+ pre->g_pre_comp[i][10][2], pre->g_pre_comp[i][8][0],
+ pre->g_pre_comp[i][8][1], pre->g_pre_comp[i][8][2],
+ 0, pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
+ pre->g_pre_comp[i][2][2]);
+ /* 2^112*G + 2^168*G resp. 2^140*G + 2^196*G */
+ point_add(
+ pre->g_pre_comp[i][12][0], pre->g_pre_comp[i][12][1],
+ pre->g_pre_comp[i][12][2], pre->g_pre_comp[i][8][0],
+ pre->g_pre_comp[i][8][1], pre->g_pre_comp[i][8][2],
+ 0, pre->g_pre_comp[i][4][0], pre->g_pre_comp[i][4][1],
+ pre->g_pre_comp[i][4][2]);
+ /* 2^56*G + 2^112*G + 2^168*G resp. 2^84*G + 2^140*G + 2^196*G */
+ point_add(
+ pre->g_pre_comp[i][14][0], pre->g_pre_comp[i][14][1],
+ pre->g_pre_comp[i][14][2], pre->g_pre_comp[i][12][0],
+ pre->g_pre_comp[i][12][1], pre->g_pre_comp[i][12][2],
+ 0, pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1],
+ pre->g_pre_comp[i][2][2]);
+ for (j = 1; j < 8; ++j)
+ {
+ /* odd multiples: add G resp. 2^28*G */
+ point_add(
+ pre->g_pre_comp[i][2*j+1][0], pre->g_pre_comp[i][2*j+1][1],
+ pre->g_pre_comp[i][2*j+1][2], pre->g_pre_comp[i][2*j][0],
+ pre->g_pre_comp[i][2*j][1], pre->g_pre_comp[i][2*j][2],
+ 0, pre->g_pre_comp[i][1][0], pre->g_pre_comp[i][1][1],
+ pre->g_pre_comp[i][1][2]);
+ }
+ }
+ make_points_affine(31, &(pre->g_pre_comp[0][1]), tmp_felems);
+
+ if (!EC_EX_DATA_set_data(&group->extra_data, pre, nistp224_pre_comp_dup,
+ nistp224_pre_comp_free, nistp224_pre_comp_clear_free))
+ goto err;
+ ret = 1;
+ pre = NULL;
+ err:
+ BN_CTX_end(ctx);
+ if (generator != NULL)
+ EC_POINT_free(generator);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (pre)
+ nistp224_pre_comp_free(pre);
+ return ret;
+ }
+
+int ec_GFp_nistp224_have_precompute_mult(const EC_GROUP *group)
+ {
+ if (EC_EX_DATA_get_data(group->extra_data, nistp224_pre_comp_dup,
+ nistp224_pre_comp_free, nistp224_pre_comp_clear_free)
+ != NULL)
+ return 1;
+ else
+ return 0;
+ }
+
+#else
+static void *dummy=&dummy;
+#endif
diff --git a/crypto/ec/ecp_nistp256.c b/crypto/ec/ecp_nistp256.c
new file mode 100644
index 0000000000000..4bc0f5dce0221
--- /dev/null
+++ b/crypto/ec/ecp_nistp256.c
@@ -0,0 +1,2171 @@
+/* crypto/ec/ecp_nistp256.c */
+/*
+ * Written by Adam Langley (Google) for the OpenSSL project
+ */
+/* Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ *
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A 64-bit implementation of the NIST P-256 elliptic curve point multiplication
+ *
+ * OpenSSL integration was taken from Emilia Kasper's work in ecp_nistp224.c.
+ * Otherwise based on Emilia's P224 work, which was inspired by my curve25519
+ * work which got its smarts from Daniel J. Bernstein's work on the same.
+ */
+
+#include <openssl/opensslconf.h>
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+
+#ifndef OPENSSL_SYS_VMS
+#include <stdint.h>
+#else
+#include <inttypes.h>
+#endif
+
+#include <string.h>
+#include <openssl/err.h>
+#include "ec_lcl.h"
+
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+ /* even with gcc, the typedef won't work for 32-bit platforms */
+ typedef __uint128_t uint128_t; /* nonstandard; implemented by gcc on 64-bit platforms */
+ typedef __int128_t int128_t;
+#else
+ #error "Need GCC 3.1 or later to define type uint128_t"
+#endif
+
+typedef uint8_t u8;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef int64_t s64;
+
+/* The underlying field.
+ *
+ * P256 operates over GF(2^256-2^224+2^192+2^96-1). We can serialise an element
+ * of this field into 32 bytes. We call this an felem_bytearray. */
+
+typedef u8 felem_bytearray[32];
+
+/* These are the parameters of P256, taken from FIPS 186-3, page 86. These
+ * values are big-endian. */
+static const felem_bytearray nistp256_curve_params[5] = {
+ {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, /* p */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, /* a = -3 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc}, /* b */
+ {0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7,
+ 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc,
+ 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6,
+ 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b},
+ {0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, /* x */
+ 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2,
+ 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
+ 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96},
+ {0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, /* y */
+ 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
+ 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
+ 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5}
+};
+
+/* The representation of field elements.
+ * ------------------------------------
+ *
+ * We represent field elements with either four 128-bit values, eight 128-bit
+ * values, or four 64-bit values. The field element represented is:
+ * v[0]*2^0 + v[1]*2^64 + v[2]*2^128 + v[3]*2^192 (mod p)
+ * or:
+ * v[0]*2^0 + v[1]*2^64 + v[2]*2^128 + ... + v[8]*2^512 (mod p)
+ *
+ * 128-bit values are called 'limbs'. Since the limbs are spaced only 64 bits
+ * apart, but are 128-bits wide, the most significant bits of each limb overlap
+ * with the least significant bits of the next.
+ *
+ * A field element with four limbs is an 'felem'. One with eight limbs is a
+ * 'longfelem'
+ *
+ * A field element with four, 64-bit values is called a 'smallfelem'. Small
+ * values are used as intermediate values before multiplication.
+ */
+
+#define NLIMBS 4
+
+typedef uint128_t limb;
+typedef limb felem[NLIMBS];
+typedef limb longfelem[NLIMBS * 2];
+typedef u64 smallfelem[NLIMBS];
+
+/* This is the value of the prime as four 64-bit words, little-endian. */
+static const u64 kPrime[4] = { 0xfffffffffffffffful, 0xffffffff, 0, 0xffffffff00000001ul };
+static const limb bottom32bits = 0xffffffff;
+static const u64 bottom63bits = 0x7ffffffffffffffful;
+
+/* bin32_to_felem takes a little-endian byte array and converts it into felem
+ * form. This assumes that the CPU is little-endian. */
+static void bin32_to_felem(felem out, const u8 in[32])
+ {
+ out[0] = *((u64*) &in[0]);
+ out[1] = *((u64*) &in[8]);
+ out[2] = *((u64*) &in[16]);
+ out[3] = *((u64*) &in[24]);
+ }
+
+/* smallfelem_to_bin32 takes a smallfelem and serialises into a little endian,
+ * 32 byte array. This assumes that the CPU is little-endian. */
+static void smallfelem_to_bin32(u8 out[32], const smallfelem in)
+ {
+ *((u64*) &out[0]) = in[0];
+ *((u64*) &out[8]) = in[1];
+ *((u64*) &out[16]) = in[2];
+ *((u64*) &out[24]) = in[3];
+ }
+
+/* To preserve endianness when using BN_bn2bin and BN_bin2bn */
+static void flip_endian(u8 *out, const u8 *in, unsigned len)
+ {
+ unsigned i;
+ for (i = 0; i < len; ++i)
+ out[i] = in[len-1-i];
+ }
+
+/* BN_to_felem converts an OpenSSL BIGNUM into an felem */
+static int BN_to_felem(felem out, const BIGNUM *bn)
+ {
+ felem_bytearray b_in;
+ felem_bytearray b_out;
+ unsigned num_bytes;
+
+ /* BN_bn2bin eats leading zeroes */
+ memset(b_out, 0, sizeof b_out);
+ num_bytes = BN_num_bytes(bn);
+ if (num_bytes > sizeof b_out)
+ {
+ ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
+ return 0;
+ }
+ if (BN_is_negative(bn))
+ {
+ ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
+ return 0;
+ }
+ num_bytes = BN_bn2bin(bn, b_in);
+ flip_endian(b_out, b_in, num_bytes);
+ bin32_to_felem(out, b_out);
+ return 1;
+ }
+
+/* felem_to_BN converts an felem into an OpenSSL BIGNUM */
+static BIGNUM *smallfelem_to_BN(BIGNUM *out, const smallfelem in)
+ {
+ felem_bytearray b_in, b_out;
+ smallfelem_to_bin32(b_in, in);
+ flip_endian(b_out, b_in, sizeof b_out);
+ return BN_bin2bn(b_out, sizeof b_out, out);
+ }
+
+
+/* Field operations
+ * ---------------- */
+
+static void smallfelem_one(smallfelem out)
+ {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ }
+
+static void smallfelem_assign(smallfelem out, const smallfelem in)
+ {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ }
+
+static void felem_assign(felem out, const felem in)
+ {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ }
+
+/* felem_sum sets out = out + in. */
+static void felem_sum(felem out, const felem in)
+ {
+ out[0] += in[0];
+ out[1] += in[1];
+ out[2] += in[2];
+ out[3] += in[3];
+ }
+
+/* felem_small_sum sets out = out + in. */
+static void felem_small_sum(felem out, const smallfelem in)
+ {
+ out[0] += in[0];
+ out[1] += in[1];
+ out[2] += in[2];
+ out[3] += in[3];
+ }
+
+/* felem_scalar sets out = out * scalar */
+static void felem_scalar(felem out, const u64 scalar)
+ {
+ out[0] *= scalar;
+ out[1] *= scalar;
+ out[2] *= scalar;
+ out[3] *= scalar;
+ }
+
+/* longfelem_scalar sets out = out * scalar */
+static void longfelem_scalar(longfelem out, const u64 scalar)
+ {
+ out[0] *= scalar;
+ out[1] *= scalar;
+ out[2] *= scalar;
+ out[3] *= scalar;
+ out[4] *= scalar;
+ out[5] *= scalar;
+ out[6] *= scalar;
+ out[7] *= scalar;
+ }
+
+#define two105m41m9 (((limb)1) << 105) - (((limb)1) << 41) - (((limb)1) << 9)
+#define two105 (((limb)1) << 105)
+#define two105m41p9 (((limb)1) << 105) - (((limb)1) << 41) + (((limb)1) << 9)
+
+/* zero105 is 0 mod p */
+static const felem zero105 = { two105m41m9, two105, two105m41p9, two105m41p9 };
+
+/* smallfelem_neg sets |out| to |-small|
+ * On exit:
+ * out[i] < out[i] + 2^105
+ */
+static void smallfelem_neg(felem out, const smallfelem small)
+ {
+ /* In order to prevent underflow, we subtract from 0 mod p. */
+ out[0] = zero105[0] - small[0];
+ out[1] = zero105[1] - small[1];
+ out[2] = zero105[2] - small[2];
+ out[3] = zero105[3] - small[3];
+ }
+
+/* felem_diff subtracts |in| from |out|
+ * On entry:
+ * in[i] < 2^104
+ * On exit:
+ * out[i] < out[i] + 2^105
+ */
+static void felem_diff(felem out, const felem in)
+ {
+ /* In order to prevent underflow, we add 0 mod p before subtracting. */
+ out[0] += zero105[0];
+ out[1] += zero105[1];
+ out[2] += zero105[2];
+ out[3] += zero105[3];
+
+ out[0] -= in[0];
+ out[1] -= in[1];
+ out[2] -= in[2];
+ out[3] -= in[3];
+ }
+
+#define two107m43m11 (((limb)1) << 107) - (((limb)1) << 43) - (((limb)1) << 11)
+#define two107 (((limb)1) << 107)
+#define two107m43p11 (((limb)1) << 107) - (((limb)1) << 43) + (((limb)1) << 11)
+
+/* zero107 is 0 mod p */
+static const felem zero107 = { two107m43m11, two107, two107m43p11, two107m43p11 };
+
+/* An alternative felem_diff for larger inputs |in|
+ * felem_diff_zero107 subtracts |in| from |out|
+ * On entry:
+ * in[i] < 2^106
+ * On exit:
+ * out[i] < out[i] + 2^107
+ */
+static void felem_diff_zero107(felem out, const felem in)
+ {
+ /* In order to prevent underflow, we add 0 mod p before subtracting. */
+ out[0] += zero107[0];
+ out[1] += zero107[1];
+ out[2] += zero107[2];
+ out[3] += zero107[3];
+
+ out[0] -= in[0];
+ out[1] -= in[1];
+ out[2] -= in[2];
+ out[3] -= in[3];
+ }
+
+/* longfelem_diff subtracts |in| from |out|
+ * On entry:
+ * in[i] < 7*2^67
+ * On exit:
+ * out[i] < out[i] + 2^70 + 2^40
+ */
+static void longfelem_diff(longfelem out, const longfelem in)
+ {
+ static const limb two70m8p6 = (((limb)1) << 70) - (((limb)1) << 8) + (((limb)1) << 6);
+ static const limb two70p40 = (((limb)1) << 70) + (((limb)1) << 40);
+ static const limb two70 = (((limb)1) << 70);
+ static const limb two70m40m38p6 = (((limb)1) << 70) - (((limb)1) << 40) - (((limb)1) << 38) + (((limb)1) << 6);
+ static const limb two70m6 = (((limb)1) << 70) - (((limb)1) << 6);
+
+ /* add 0 mod p to avoid underflow */
+ out[0] += two70m8p6;
+ out[1] += two70p40;
+ out[2] += two70;
+ out[3] += two70m40m38p6;
+ out[4] += two70m6;
+ out[5] += two70m6;
+ out[6] += two70m6;
+ out[7] += two70m6;
+
+ /* in[i] < 7*2^67 < 2^70 - 2^40 - 2^38 + 2^6 */
+ out[0] -= in[0];
+ out[1] -= in[1];
+ out[2] -= in[2];
+ out[3] -= in[3];
+ out[4] -= in[4];
+ out[5] -= in[5];
+ out[6] -= in[6];
+ out[7] -= in[7];
+ }
+
+#define two64m0 (((limb)1) << 64) - 1
+#define two110p32m0 (((limb)1) << 110) + (((limb)1) << 32) - 1
+#define two64m46 (((limb)1) << 64) - (((limb)1) << 46)
+#define two64m32 (((limb)1) << 64) - (((limb)1) << 32)
+
+/* zero110 is 0 mod p */
+static const felem zero110 = { two64m0, two110p32m0, two64m46, two64m32 };
+
+/* felem_shrink converts an felem into a smallfelem. The result isn't quite
+ * minimal as the value may be greater than p.
+ *
+ * On entry:
+ * in[i] < 2^109
+ * On exit:
+ * out[i] < 2^64
+ */
+static void felem_shrink(smallfelem out, const felem in)
+ {
+ felem tmp;
+ u64 a, b, mask;
+ s64 high, low;
+ static const u64 kPrime3Test = 0x7fffffff00000001ul; /* 2^63 - 2^32 + 1 */
+
+ /* Carry 2->3 */
+ tmp[3] = zero110[3] + in[3] + ((u64) (in[2] >> 64));
+ /* tmp[3] < 2^110 */
+
+ tmp[2] = zero110[2] + (u64) in[2];
+ tmp[0] = zero110[0] + in[0];
+ tmp[1] = zero110[1] + in[1];
+ /* tmp[0] < 2**110, tmp[1] < 2^111, tmp[2] < 2**65 */
+
+ /* We perform two partial reductions where we eliminate the
+ * high-word of tmp[3]. We don't update the other words till the end.
+ */
+ a = tmp[3] >> 64; /* a < 2^46 */
+ tmp[3] = (u64) tmp[3];
+ tmp[3] -= a;
+ tmp[3] += ((limb)a) << 32;
+ /* tmp[3] < 2^79 */
+
+ b = a;
+ a = tmp[3] >> 64; /* a < 2^15 */
+ b += a; /* b < 2^46 + 2^15 < 2^47 */
+ tmp[3] = (u64) tmp[3];
+ tmp[3] -= a;
+ tmp[3] += ((limb)a) << 32;
+ /* tmp[3] < 2^64 + 2^47 */
+
+ /* This adjusts the other two words to complete the two partial
+ * reductions. */
+ tmp[0] += b;
+ tmp[1] -= (((limb)b) << 32);
+
+ /* In order to make space in tmp[3] for the carry from 2 -> 3, we
+ * conditionally subtract kPrime if tmp[3] is large enough. */
+ high = tmp[3] >> 64;
+ /* As tmp[3] < 2^65, high is either 1 or 0 */
+ high <<= 63;
+ high >>= 63;
+ /* high is:
+ * all ones if the high word of tmp[3] is 1
+ * all zeros if the high word of tmp[3] if 0 */
+ low = tmp[3];
+ mask = low >> 63;
+ /* mask is:
+ * all ones if the MSB of low is 1
+ * all zeros if the MSB of low if 0 */
+ low &= bottom63bits;
+ low -= kPrime3Test;
+ /* if low was greater than kPrime3Test then the MSB is zero */
+ low = ~low;
+ low >>= 63;
+ /* low is:
+ * all ones if low was > kPrime3Test
+ * all zeros if low was <= kPrime3Test */
+ mask = (mask & low) | high;
+ tmp[0] -= mask & kPrime[0];
+ tmp[1] -= mask & kPrime[1];
+ /* kPrime[2] is zero, so omitted */
+ tmp[3] -= mask & kPrime[3];
+ /* tmp[3] < 2**64 - 2**32 + 1 */
+
+ tmp[1] += ((u64) (tmp[0] >> 64)); tmp[0] = (u64) tmp[0];
+ tmp[2] += ((u64) (tmp[1] >> 64)); tmp[1] = (u64) tmp[1];
+ tmp[3] += ((u64) (tmp[2] >> 64)); tmp[2] = (u64) tmp[2];
+ /* tmp[i] < 2^64 */
+
+ out[0] = tmp[0];
+ out[1] = tmp[1];
+ out[2] = tmp[2];
+ out[3] = tmp[3];
+ }
+
+/* smallfelem_expand converts a smallfelem to an felem */
+static void smallfelem_expand(felem out, const smallfelem in)
+ {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ }
+
+/* smallfelem_square sets |out| = |small|^2
+ * On entry:
+ * small[i] < 2^64
+ * On exit:
+ * out[i] < 7 * 2^64 < 2^67
+ */
+static void smallfelem_square(longfelem out, const smallfelem small)
+ {
+ limb a;
+ u64 high, low;
+
+ a = ((uint128_t) small[0]) * small[0];
+ low = a;
+ high = a >> 64;
+ out[0] = low;
+ out[1] = high;
+
+ a = ((uint128_t) small[0]) * small[1];
+ low = a;
+ high = a >> 64;
+ out[1] += low;
+ out[1] += low;
+ out[2] = high;
+
+ a = ((uint128_t) small[0]) * small[2];
+ low = a;
+ high = a >> 64;
+ out[2] += low;
+ out[2] *= 2;
+ out[3] = high;
+
+ a = ((uint128_t) small[0]) * small[3];
+ low = a;
+ high = a >> 64;
+ out[3] += low;
+ out[4] = high;
+
+ a = ((uint128_t) small[1]) * small[2];
+ low = a;
+ high = a >> 64;
+ out[3] += low;
+ out[3] *= 2;
+ out[4] += high;
+
+ a = ((uint128_t) small[1]) * small[1];
+ low = a;
+ high = a >> 64;
+ out[2] += low;
+ out[3] += high;
+
+ a = ((uint128_t) small[1]) * small[3];
+ low = a;
+ high = a >> 64;
+ out[4] += low;
+ out[4] *= 2;
+ out[5] = high;
+
+ a = ((uint128_t) small[2]) * small[3];
+ low = a;
+ high = a >> 64;
+ out[5] += low;
+ out[5] *= 2;
+ out[6] = high;
+ out[6] += high;
+
+ a = ((uint128_t) small[2]) * small[2];
+ low = a;
+ high = a >> 64;
+ out[4] += low;
+ out[5] += high;
+
+ a = ((uint128_t) small[3]) * small[3];
+ low = a;
+ high = a >> 64;
+ out[6] += low;
+ out[7] = high;
+ }
+
+/* felem_square sets |out| = |in|^2
+ * On entry:
+ * in[i] < 2^109
+ * On exit:
+ * out[i] < 7 * 2^64 < 2^67
+ */
+static void felem_square(longfelem out, const felem in)
+ {
+ u64 small[4];
+ felem_shrink(small, in);
+ smallfelem_square(out, small);
+ }
+
+/* smallfelem_mul sets |out| = |small1| * |small2|
+ * On entry:
+ * small1[i] < 2^64
+ * small2[i] < 2^64
+ * On exit:
+ * out[i] < 7 * 2^64 < 2^67
+ */
+static void smallfelem_mul(longfelem out, const smallfelem small1, const smallfelem small2)
+ {
+ limb a;
+ u64 high, low;
+
+ a = ((uint128_t) small1[0]) * small2[0];
+ low = a;
+ high = a >> 64;
+ out[0] = low;
+ out[1] = high;
+
+
+ a = ((uint128_t) small1[0]) * small2[1];
+ low = a;
+ high = a >> 64;
+ out[1] += low;
+ out[2] = high;
+
+ a = ((uint128_t) small1[1]) * small2[0];
+ low = a;
+ high = a >> 64;
+ out[1] += low;
+ out[2] += high;
+
+
+ a = ((uint128_t) small1[0]) * small2[2];
+ low = a;
+ high = a >> 64;
+ out[2] += low;
+ out[3] = high;
+
+ a = ((uint128_t) small1[1]) * small2[1];
+ low = a;
+ high = a >> 64;
+ out[2] += low;
+ out[3] += high;
+
+ a = ((uint128_t) small1[2]) * small2[0];
+ low = a;
+ high = a >> 64;
+ out[2] += low;
+ out[3] += high;
+
+
+ a = ((uint128_t) small1[0]) * small2[3];
+ low = a;
+ high = a >> 64;
+ out[3] += low;
+ out[4] = high;
+
+ a = ((uint128_t) small1[1]) * small2[2];
+ low = a;
+ high = a >> 64;
+ out[3] += low;
+ out[4] += high;
+
+ a = ((uint128_t) small1[2]) * small2[1];
+ low = a;
+ high = a >> 64;
+ out[3] += low;
+ out[4] += high;
+
+ a = ((uint128_t) small1[3]) * small2[0];
+ low = a;
+ high = a >> 64;
+ out[3] += low;
+ out[4] += high;
+
+
+ a = ((uint128_t) small1[1]) * small2[3];
+ low = a;
+ high = a >> 64;
+ out[4] += low;
+ out[5] = high;
+
+ a = ((uint128_t) small1[2]) * small2[2];
+ low = a;
+ high = a >> 64;
+ out[4] += low;
+ out[5] += high;
+
+ a = ((uint128_t) small1[3]) * small2[1];
+ low = a;
+ high = a >> 64;
+ out[4] += low;
+ out[5] += high;
+
+
+ a = ((uint128_t) small1[2]) * small2[3];
+ low = a;
+ high = a >> 64;
+ out[5] += low;
+ out[6] = high;
+
+ a = ((uint128_t) small1[3]) * small2[2];
+ low = a;
+ high = a >> 64;
+ out[5] += low;
+ out[6] += high;
+
+
+ a = ((uint128_t) small1[3]) * small2[3];
+ low = a;
+ high = a >> 64;
+ out[6] += low;
+ out[7] = high;
+ }
+
+/* felem_mul sets |out| = |in1| * |in2|
+ * On entry:
+ * in1[i] < 2^109
+ * in2[i] < 2^109
+ * On exit:
+ * out[i] < 7 * 2^64 < 2^67
+ */
+static void felem_mul(longfelem out, const felem in1, const felem in2)
+ {
+ smallfelem small1, small2;
+ felem_shrink(small1, in1);
+ felem_shrink(small2, in2);
+ smallfelem_mul(out, small1, small2);
+ }
+
+/* felem_small_mul sets |out| = |small1| * |in2|
+ * On entry:
+ * small1[i] < 2^64
+ * in2[i] < 2^109
+ * On exit:
+ * out[i] < 7 * 2^64 < 2^67
+ */
+static void felem_small_mul(longfelem out, const smallfelem small1, const felem in2)
+ {
+ smallfelem small2;
+ felem_shrink(small2, in2);
+ smallfelem_mul(out, small1, small2);
+ }
+
+#define two100m36m4 (((limb)1) << 100) - (((limb)1) << 36) - (((limb)1) << 4)
+#define two100 (((limb)1) << 100)
+#define two100m36p4 (((limb)1) << 100) - (((limb)1) << 36) + (((limb)1) << 4)
+/* zero100 is 0 mod p */
+static const felem zero100 = { two100m36m4, two100, two100m36p4, two100m36p4 };
+
+/* Internal function for the different flavours of felem_reduce.
+ * felem_reduce_ reduces the higher coefficients in[4]-in[7].
+ * On entry:
+ * out[0] >= in[6] + 2^32*in[6] + in[7] + 2^32*in[7]
+ * out[1] >= in[7] + 2^32*in[4]
+ * out[2] >= in[5] + 2^32*in[5]
+ * out[3] >= in[4] + 2^32*in[5] + 2^32*in[6]
+ * On exit:
+ * out[0] <= out[0] + in[4] + 2^32*in[5]
+ * out[1] <= out[1] + in[5] + 2^33*in[6]
+ * out[2] <= out[2] + in[7] + 2*in[6] + 2^33*in[7]
+ * out[3] <= out[3] + 2^32*in[4] + 3*in[7]
+ */
+static void felem_reduce_(felem out, const longfelem in)
+ {
+ int128_t c;
+ /* combine common terms from below */
+ c = in[4] + (in[5] << 32);
+ out[0] += c;
+ out[3] -= c;
+
+ c = in[5] - in[7];
+ out[1] += c;
+ out[2] -= c;
+
+ /* the remaining terms */
+ /* 256: [(0,1),(96,-1),(192,-1),(224,1)] */
+ out[1] -= (in[4] << 32);
+ out[3] += (in[4] << 32);
+
+ /* 320: [(32,1),(64,1),(128,-1),(160,-1),(224,-1)] */
+ out[2] -= (in[5] << 32);
+
+ /* 384: [(0,-1),(32,-1),(96,2),(128,2),(224,-1)] */
+ out[0] -= in[6];
+ out[0] -= (in[6] << 32);
+ out[1] += (in[6] << 33);
+ out[2] += (in[6] * 2);
+ out[3] -= (in[6] << 32);
+
+ /* 448: [(0,-1),(32,-1),(64,-1),(128,1),(160,2),(192,3)] */
+ out[0] -= in[7];
+ out[0] -= (in[7] << 32);
+ out[2] += (in[7] << 33);
+ out[3] += (in[7] * 3);
+ }
+
+/* felem_reduce converts a longfelem into an felem.
+ * To be called directly after felem_square or felem_mul.
+ * On entry:
+ * in[0] < 2^64, in[1] < 3*2^64, in[2] < 5*2^64, in[3] < 7*2^64
+ * in[4] < 7*2^64, in[5] < 5*2^64, in[6] < 3*2^64, in[7] < 2*64
+ * On exit:
+ * out[i] < 2^101
+ */
+static void felem_reduce(felem out, const longfelem in)
+ {
+ out[0] = zero100[0] + in[0];
+ out[1] = zero100[1] + in[1];
+ out[2] = zero100[2] + in[2];
+ out[3] = zero100[3] + in[3];
+
+ felem_reduce_(out, in);
+
+ /* out[0] > 2^100 - 2^36 - 2^4 - 3*2^64 - 3*2^96 - 2^64 - 2^96 > 0
+ * out[1] > 2^100 - 2^64 - 7*2^96 > 0
+ * out[2] > 2^100 - 2^36 + 2^4 - 5*2^64 - 5*2^96 > 0
+ * out[3] > 2^100 - 2^36 + 2^4 - 7*2^64 - 5*2^96 - 3*2^96 > 0
+ *
+ * out[0] < 2^100 + 2^64 + 7*2^64 + 5*2^96 < 2^101
+ * out[1] < 2^100 + 3*2^64 + 5*2^64 + 3*2^97 < 2^101
+ * out[2] < 2^100 + 5*2^64 + 2^64 + 3*2^65 + 2^97 < 2^101
+ * out[3] < 2^100 + 7*2^64 + 7*2^96 + 3*2^64 < 2^101
+ */
+ }
+
+/* felem_reduce_zero105 converts a larger longfelem into an felem.
+ * On entry:
+ * in[0] < 2^71
+ * On exit:
+ * out[i] < 2^106
+ */
+static void felem_reduce_zero105(felem out, const longfelem in)
+ {
+ out[0] = zero105[0] + in[0];
+ out[1] = zero105[1] + in[1];
+ out[2] = zero105[2] + in[2];
+ out[3] = zero105[3] + in[3];
+
+ felem_reduce_(out, in);
+
+ /* out[0] > 2^105 - 2^41 - 2^9 - 2^71 - 2^103 - 2^71 - 2^103 > 0
+ * out[1] > 2^105 - 2^71 - 2^103 > 0
+ * out[2] > 2^105 - 2^41 + 2^9 - 2^71 - 2^103 > 0
+ * out[3] > 2^105 - 2^41 + 2^9 - 2^71 - 2^103 - 2^103 > 0
+ *
+ * out[0] < 2^105 + 2^71 + 2^71 + 2^103 < 2^106
+ * out[1] < 2^105 + 2^71 + 2^71 + 2^103 < 2^106
+ * out[2] < 2^105 + 2^71 + 2^71 + 2^71 + 2^103 < 2^106
+ * out[3] < 2^105 + 2^71 + 2^103 + 2^71 < 2^106
+ */
+ }
+
+/* subtract_u64 sets *result = *result - v and *carry to one if the subtraction
+ * underflowed. */
+static void subtract_u64(u64* result, u64* carry, u64 v)
+ {
+ uint128_t r = *result;
+ r -= v;
+ *carry = (r >> 64) & 1;
+ *result = (u64) r;
+ }
+
+/* felem_contract converts |in| to its unique, minimal representation.
+ * On entry:
+ * in[i] < 2^109
+ */
+static void felem_contract(smallfelem out, const felem in)
+ {
+ unsigned i;
+ u64 all_equal_so_far = 0, result = 0, carry;
+
+ felem_shrink(out, in);
+ /* small is minimal except that the value might be > p */
+
+ all_equal_so_far--;
+ /* We are doing a constant time test if out >= kPrime. We need to
+ * compare each u64, from most-significant to least significant. For
+ * each one, if all words so far have been equal (m is all ones) then a
+ * non-equal result is the answer. Otherwise we continue. */
+ for (i = 3; i < 4; i--)
+ {
+ u64 equal;
+ uint128_t a = ((uint128_t) kPrime[i]) - out[i];
+ /* if out[i] > kPrime[i] then a will underflow and the high
+ * 64-bits will all be set. */
+ result |= all_equal_so_far & ((u64) (a >> 64));
+
+ /* if kPrime[i] == out[i] then |equal| will be all zeros and
+ * the decrement will make it all ones. */
+ equal = kPrime[i] ^ out[i];
+ equal--;
+ equal &= equal << 32;
+ equal &= equal << 16;
+ equal &= equal << 8;
+ equal &= equal << 4;
+ equal &= equal << 2;
+ equal &= equal << 1;
+ equal = ((s64) equal) >> 63;
+
+ all_equal_so_far &= equal;
+ }
+
+ /* if all_equal_so_far is still all ones then the two values are equal
+ * and so out >= kPrime is true. */
+ result |= all_equal_so_far;
+
+ /* if out >= kPrime then we subtract kPrime. */
+ subtract_u64(&out[0], &carry, result & kPrime[0]);
+ subtract_u64(&out[1], &carry, carry);
+ subtract_u64(&out[2], &carry, carry);
+ subtract_u64(&out[3], &carry, carry);
+
+ subtract_u64(&out[1], &carry, result & kPrime[1]);
+ subtract_u64(&out[2], &carry, carry);
+ subtract_u64(&out[3], &carry, carry);
+
+ subtract_u64(&out[2], &carry, result & kPrime[2]);
+ subtract_u64(&out[3], &carry, carry);
+
+ subtract_u64(&out[3], &carry, result & kPrime[3]);
+ }
+
+static void smallfelem_square_contract(smallfelem out, const smallfelem in)
+ {
+ longfelem longtmp;
+ felem tmp;
+
+ smallfelem_square(longtmp, in);
+ felem_reduce(tmp, longtmp);
+ felem_contract(out, tmp);
+ }
+
+static void smallfelem_mul_contract(smallfelem out, const smallfelem in1, const smallfelem in2)
+ {
+ longfelem longtmp;
+ felem tmp;
+
+ smallfelem_mul(longtmp, in1, in2);
+ felem_reduce(tmp, longtmp);
+ felem_contract(out, tmp);
+ }
+
+/* felem_is_zero returns a limb with all bits set if |in| == 0 (mod p) and 0
+ * otherwise.
+ * On entry:
+ * small[i] < 2^64
+ */
+static limb smallfelem_is_zero(const smallfelem small)
+ {
+ limb result;
+ u64 is_p;
+
+ u64 is_zero = small[0] | small[1] | small[2] | small[3];
+ is_zero--;
+ is_zero &= is_zero << 32;
+ is_zero &= is_zero << 16;
+ is_zero &= is_zero << 8;
+ is_zero &= is_zero << 4;
+ is_zero &= is_zero << 2;
+ is_zero &= is_zero << 1;
+ is_zero = ((s64) is_zero) >> 63;
+
+ is_p = (small[0] ^ kPrime[0]) |
+ (small[1] ^ kPrime[1]) |
+ (small[2] ^ kPrime[2]) |
+ (small[3] ^ kPrime[3]);
+ is_p--;
+ is_p &= is_p << 32;
+ is_p &= is_p << 16;
+ is_p &= is_p << 8;
+ is_p &= is_p << 4;
+ is_p &= is_p << 2;
+ is_p &= is_p << 1;
+ is_p = ((s64) is_p) >> 63;
+
+ is_zero |= is_p;
+
+ result = is_zero;
+ result |= ((limb) is_zero) << 64;
+ return result;
+ }
+
+static int smallfelem_is_zero_int(const smallfelem small)
+ {
+ return (int) (smallfelem_is_zero(small) & ((limb)1));
+ }
+
+/* felem_inv calculates |out| = |in|^{-1}
+ *
+ * Based on Fermat's Little Theorem:
+ * a^p = a (mod p)
+ * a^{p-1} = 1 (mod p)
+ * a^{p-2} = a^{-1} (mod p)
+ */
+static void felem_inv(felem out, const felem in)
+ {
+ felem ftmp, ftmp2;
+ /* each e_I will hold |in|^{2^I - 1} */
+ felem e2, e4, e8, e16, e32, e64;
+ longfelem tmp;
+ unsigned i;
+
+ felem_square(tmp, in); felem_reduce(ftmp, tmp); /* 2^1 */
+ felem_mul(tmp, in, ftmp); felem_reduce(ftmp, tmp); /* 2^2 - 2^0 */
+ felem_assign(e2, ftmp);
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^3 - 2^1 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^4 - 2^2 */
+ felem_mul(tmp, ftmp, e2); felem_reduce(ftmp, tmp); /* 2^4 - 2^0 */
+ felem_assign(e4, ftmp);
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^5 - 2^1 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^6 - 2^2 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^7 - 2^3 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^8 - 2^4 */
+ felem_mul(tmp, ftmp, e4); felem_reduce(ftmp, tmp); /* 2^8 - 2^0 */
+ felem_assign(e8, ftmp);
+ for (i = 0; i < 8; i++) {
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp);
+ } /* 2^16 - 2^8 */
+ felem_mul(tmp, ftmp, e8); felem_reduce(ftmp, tmp); /* 2^16 - 2^0 */
+ felem_assign(e16, ftmp);
+ for (i = 0; i < 16; i++) {
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp);
+ } /* 2^32 - 2^16 */
+ felem_mul(tmp, ftmp, e16); felem_reduce(ftmp, tmp); /* 2^32 - 2^0 */
+ felem_assign(e32, ftmp);
+ for (i = 0; i < 32; i++) {
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp);
+ } /* 2^64 - 2^32 */
+ felem_assign(e64, ftmp);
+ felem_mul(tmp, ftmp, in); felem_reduce(ftmp, tmp); /* 2^64 - 2^32 + 2^0 */
+ for (i = 0; i < 192; i++) {
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp);
+ } /* 2^256 - 2^224 + 2^192 */
+
+ felem_mul(tmp, e64, e32); felem_reduce(ftmp2, tmp); /* 2^64 - 2^0 */
+ for (i = 0; i < 16; i++) {
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp);
+ } /* 2^80 - 2^16 */
+ felem_mul(tmp, ftmp2, e16); felem_reduce(ftmp2, tmp); /* 2^80 - 2^0 */
+ for (i = 0; i < 8; i++) {
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp);
+ } /* 2^88 - 2^8 */
+ felem_mul(tmp, ftmp2, e8); felem_reduce(ftmp2, tmp); /* 2^88 - 2^0 */
+ for (i = 0; i < 4; i++) {
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp);
+ } /* 2^92 - 2^4 */
+ felem_mul(tmp, ftmp2, e4); felem_reduce(ftmp2, tmp); /* 2^92 - 2^0 */
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); /* 2^93 - 2^1 */
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); /* 2^94 - 2^2 */
+ felem_mul(tmp, ftmp2, e2); felem_reduce(ftmp2, tmp); /* 2^94 - 2^0 */
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); /* 2^95 - 2^1 */
+ felem_square(tmp, ftmp2); felem_reduce(ftmp2, tmp); /* 2^96 - 2^2 */
+ felem_mul(tmp, ftmp2, in); felem_reduce(ftmp2, tmp); /* 2^96 - 3 */
+
+ felem_mul(tmp, ftmp2, ftmp); felem_reduce(out, tmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
+ }
+
+static void smallfelem_inv_contract(smallfelem out, const smallfelem in)
+ {
+ felem tmp;
+
+ smallfelem_expand(tmp, in);
+ felem_inv(tmp, tmp);
+ felem_contract(out, tmp);
+ }
+
+/* Group operations
+ * ----------------
+ *
+ * Building on top of the field operations we have the operations on the
+ * elliptic curve group itself. Points on the curve are represented in Jacobian
+ * coordinates */
+
+/* point_double calculates 2*(x_in, y_in, z_in)
+ *
+ * The method is taken from:
+ * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
+ *
+ * Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed.
+ * while x_out == y_in is not (maybe this works, but it's not tested). */
+static void
+point_double(felem x_out, felem y_out, felem z_out,
+ const felem x_in, const felem y_in, const felem z_in)
+ {
+ longfelem tmp, tmp2;
+ felem delta, gamma, beta, alpha, ftmp, ftmp2;
+ smallfelem small1, small2;
+
+ felem_assign(ftmp, x_in);
+ /* ftmp[i] < 2^106 */
+ felem_assign(ftmp2, x_in);
+ /* ftmp2[i] < 2^106 */
+
+ /* delta = z^2 */
+ felem_square(tmp, z_in);
+ felem_reduce(delta, tmp);
+ /* delta[i] < 2^101 */
+
+ /* gamma = y^2 */
+ felem_square(tmp, y_in);
+ felem_reduce(gamma, tmp);
+ /* gamma[i] < 2^101 */
+ felem_shrink(small1, gamma);
+
+ /* beta = x*gamma */
+ felem_small_mul(tmp, small1, x_in);
+ felem_reduce(beta, tmp);
+ /* beta[i] < 2^101 */
+
+ /* alpha = 3*(x-delta)*(x+delta) */
+ felem_diff(ftmp, delta);
+ /* ftmp[i] < 2^105 + 2^106 < 2^107 */
+ felem_sum(ftmp2, delta);
+ /* ftmp2[i] < 2^105 + 2^106 < 2^107 */
+ felem_scalar(ftmp2, 3);
+ /* ftmp2[i] < 3 * 2^107 < 2^109 */
+ felem_mul(tmp, ftmp, ftmp2);
+ felem_reduce(alpha, tmp);
+ /* alpha[i] < 2^101 */
+ felem_shrink(small2, alpha);
+
+ /* x' = alpha^2 - 8*beta */
+ smallfelem_square(tmp, small2);
+ felem_reduce(x_out, tmp);
+ felem_assign(ftmp, beta);
+ felem_scalar(ftmp, 8);
+ /* ftmp[i] < 8 * 2^101 = 2^104 */
+ felem_diff(x_out, ftmp);
+ /* x_out[i] < 2^105 + 2^101 < 2^106 */
+
+ /* z' = (y + z)^2 - gamma - delta */
+ felem_sum(delta, gamma);
+ /* delta[i] < 2^101 + 2^101 = 2^102 */
+ felem_assign(ftmp, y_in);
+ felem_sum(ftmp, z_in);
+ /* ftmp[i] < 2^106 + 2^106 = 2^107 */
+ felem_square(tmp, ftmp);
+ felem_reduce(z_out, tmp);
+ felem_diff(z_out, delta);
+ /* z_out[i] < 2^105 + 2^101 < 2^106 */
+
+ /* y' = alpha*(4*beta - x') - 8*gamma^2 */
+ felem_scalar(beta, 4);
+ /* beta[i] < 4 * 2^101 = 2^103 */
+ felem_diff_zero107(beta, x_out);
+ /* beta[i] < 2^107 + 2^103 < 2^108 */
+ felem_small_mul(tmp, small2, beta);
+ /* tmp[i] < 7 * 2^64 < 2^67 */
+ smallfelem_square(tmp2, small1);
+ /* tmp2[i] < 7 * 2^64 */
+ longfelem_scalar(tmp2, 8);
+ /* tmp2[i] < 8 * 7 * 2^64 = 7 * 2^67 */
+ longfelem_diff(tmp, tmp2);
+ /* tmp[i] < 2^67 + 2^70 + 2^40 < 2^71 */
+ felem_reduce_zero105(y_out, tmp);
+ /* y_out[i] < 2^106 */
+ }
+
+/* point_double_small is the same as point_double, except that it operates on
+ * smallfelems */
+static void
+point_double_small(smallfelem x_out, smallfelem y_out, smallfelem z_out,
+ const smallfelem x_in, const smallfelem y_in, const smallfelem z_in)
+ {
+ felem felem_x_out, felem_y_out, felem_z_out;
+ felem felem_x_in, felem_y_in, felem_z_in;
+
+ smallfelem_expand(felem_x_in, x_in);
+ smallfelem_expand(felem_y_in, y_in);
+ smallfelem_expand(felem_z_in, z_in);
+ point_double(felem_x_out, felem_y_out, felem_z_out,
+ felem_x_in, felem_y_in, felem_z_in);
+ felem_shrink(x_out, felem_x_out);
+ felem_shrink(y_out, felem_y_out);
+ felem_shrink(z_out, felem_z_out);
+ }
+
+/* copy_conditional copies in to out iff mask is all ones. */
+static void
+copy_conditional(felem out, const felem in, limb mask)
+ {
+ unsigned i;
+ for (i = 0; i < NLIMBS; ++i)
+ {
+ const limb tmp = mask & (in[i] ^ out[i]);
+ out[i] ^= tmp;
+ }
+ }
+
+/* copy_small_conditional copies in to out iff mask is all ones. */
+static void
+copy_small_conditional(felem out, const smallfelem in, limb mask)
+ {
+ unsigned i;
+ const u64 mask64 = mask;
+ for (i = 0; i < NLIMBS; ++i)
+ {
+ out[i] = ((limb) (in[i] & mask64)) | (out[i] & ~mask);
+ }
+ }
+
+/* point_add calcuates (x1, y1, z1) + (x2, y2, z2)
+ *
+ * The method is taken from:
+ * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl,
+ * adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity).
+ *
+ * This function includes a branch for checking whether the two input points
+ * are equal, (while not equal to the point at infinity). This case never
+ * happens during single point multiplication, so there is no timing leak for
+ * ECDH or ECDSA signing. */
+static void point_add(felem x3, felem y3, felem z3,
+ const felem x1, const felem y1, const felem z1,
+ const int mixed, const smallfelem x2, const smallfelem y2, const smallfelem z2)
+ {
+ felem ftmp, ftmp2, ftmp3, ftmp4, ftmp5, ftmp6, x_out, y_out, z_out;
+ longfelem tmp, tmp2;
+ smallfelem small1, small2, small3, small4, small5;
+ limb x_equal, y_equal, z1_is_zero, z2_is_zero;
+
+ felem_shrink(small3, z1);
+
+ z1_is_zero = smallfelem_is_zero(small3);
+ z2_is_zero = smallfelem_is_zero(z2);
+
+ /* ftmp = z1z1 = z1**2 */
+ smallfelem_square(tmp, small3);
+ felem_reduce(ftmp, tmp);
+ /* ftmp[i] < 2^101 */
+ felem_shrink(small1, ftmp);
+
+ if(!mixed)
+ {
+ /* ftmp2 = z2z2 = z2**2 */
+ smallfelem_square(tmp, z2);
+ felem_reduce(ftmp2, tmp);
+ /* ftmp2[i] < 2^101 */
+ felem_shrink(small2, ftmp2);
+
+ felem_shrink(small5, x1);
+
+ /* u1 = ftmp3 = x1*z2z2 */
+ smallfelem_mul(tmp, small5, small2);
+ felem_reduce(ftmp3, tmp);
+ /* ftmp3[i] < 2^101 */
+
+ /* ftmp5 = z1 + z2 */
+ felem_assign(ftmp5, z1);
+ felem_small_sum(ftmp5, z2);
+ /* ftmp5[i] < 2^107 */
+
+ /* ftmp5 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2 */
+ felem_square(tmp, ftmp5);
+ felem_reduce(ftmp5, tmp);
+ /* ftmp2 = z2z2 + z1z1 */
+ felem_sum(ftmp2, ftmp);
+ /* ftmp2[i] < 2^101 + 2^101 = 2^102 */
+ felem_diff(ftmp5, ftmp2);
+ /* ftmp5[i] < 2^105 + 2^101 < 2^106 */
+
+ /* ftmp2 = z2 * z2z2 */
+ smallfelem_mul(tmp, small2, z2);
+ felem_reduce(ftmp2, tmp);
+
+ /* s1 = ftmp2 = y1 * z2**3 */
+ felem_mul(tmp, y1, ftmp2);
+ felem_reduce(ftmp6, tmp);
+ /* ftmp6[i] < 2^101 */
+ }
+ else
+ {
+ /* We'll assume z2 = 1 (special case z2 = 0 is handled later) */
+
+ /* u1 = ftmp3 = x1*z2z2 */
+ felem_assign(ftmp3, x1);
+ /* ftmp3[i] < 2^106 */
+
+ /* ftmp5 = 2z1z2 */
+ felem_assign(ftmp5, z1);
+ felem_scalar(ftmp5, 2);
+ /* ftmp5[i] < 2*2^106 = 2^107 */
+
+ /* s1 = ftmp2 = y1 * z2**3 */
+ felem_assign(ftmp6, y1);
+ /* ftmp6[i] < 2^106 */
+ }
+
+ /* u2 = x2*z1z1 */
+ smallfelem_mul(tmp, x2, small1);
+ felem_reduce(ftmp4, tmp);
+
+ /* h = ftmp4 = u2 - u1 */
+ felem_diff_zero107(ftmp4, ftmp3);
+ /* ftmp4[i] < 2^107 + 2^101 < 2^108 */
+ felem_shrink(small4, ftmp4);
+
+ x_equal = smallfelem_is_zero(small4);
+
+ /* z_out = ftmp5 * h */
+ felem_small_mul(tmp, small4, ftmp5);
+ felem_reduce(z_out, tmp);
+ /* z_out[i] < 2^101 */
+
+ /* ftmp = z1 * z1z1 */
+ smallfelem_mul(tmp, small1, small3);
+ felem_reduce(ftmp, tmp);
+
+ /* s2 = tmp = y2 * z1**3 */
+ felem_small_mul(tmp, y2, ftmp);
+ felem_reduce(ftmp5, tmp);
+
+ /* r = ftmp5 = (s2 - s1)*2 */
+ felem_diff_zero107(ftmp5, ftmp6);
+ /* ftmp5[i] < 2^107 + 2^107 = 2^108*/
+ felem_scalar(ftmp5, 2);
+ /* ftmp5[i] < 2^109 */
+ felem_shrink(small1, ftmp5);
+ y_equal = smallfelem_is_zero(small1);
+
+ if (x_equal && y_equal && !z1_is_zero && !z2_is_zero)
+ {
+ point_double(x3, y3, z3, x1, y1, z1);
+ return;
+ }
+
+ /* I = ftmp = (2h)**2 */
+ felem_assign(ftmp, ftmp4);
+ felem_scalar(ftmp, 2);
+ /* ftmp[i] < 2*2^108 = 2^109 */
+ felem_square(tmp, ftmp);
+ felem_reduce(ftmp, tmp);
+
+ /* J = ftmp2 = h * I */
+ felem_mul(tmp, ftmp4, ftmp);
+ felem_reduce(ftmp2, tmp);
+
+ /* V = ftmp4 = U1 * I */
+ felem_mul(tmp, ftmp3, ftmp);
+ felem_reduce(ftmp4, tmp);
+
+ /* x_out = r**2 - J - 2V */
+ smallfelem_square(tmp, small1);
+ felem_reduce(x_out, tmp);
+ felem_assign(ftmp3, ftmp4);
+ felem_scalar(ftmp4, 2);
+ felem_sum(ftmp4, ftmp2);
+ /* ftmp4[i] < 2*2^101 + 2^101 < 2^103 */
+ felem_diff(x_out, ftmp4);
+ /* x_out[i] < 2^105 + 2^101 */
+
+ /* y_out = r(V-x_out) - 2 * s1 * J */
+ felem_diff_zero107(ftmp3, x_out);
+ /* ftmp3[i] < 2^107 + 2^101 < 2^108 */
+ felem_small_mul(tmp, small1, ftmp3);
+ felem_mul(tmp2, ftmp6, ftmp2);
+ longfelem_scalar(tmp2, 2);
+ /* tmp2[i] < 2*2^67 = 2^68 */
+ longfelem_diff(tmp, tmp2);
+ /* tmp[i] < 2^67 + 2^70 + 2^40 < 2^71 */
+ felem_reduce_zero105(y_out, tmp);
+ /* y_out[i] < 2^106 */
+
+ copy_small_conditional(x_out, x2, z1_is_zero);
+ copy_conditional(x_out, x1, z2_is_zero);
+ copy_small_conditional(y_out, y2, z1_is_zero);
+ copy_conditional(y_out, y1, z2_is_zero);
+ copy_small_conditional(z_out, z2, z1_is_zero);
+ copy_conditional(z_out, z1, z2_is_zero);
+ felem_assign(x3, x_out);
+ felem_assign(y3, y_out);
+ felem_assign(z3, z_out);
+ }
+
+/* point_add_small is the same as point_add, except that it operates on
+ * smallfelems */
+static void point_add_small(smallfelem x3, smallfelem y3, smallfelem z3,
+ smallfelem x1, smallfelem y1, smallfelem z1,
+ smallfelem x2, smallfelem y2, smallfelem z2)
+ {
+ felem felem_x3, felem_y3, felem_z3;
+ felem felem_x1, felem_y1, felem_z1;
+ smallfelem_expand(felem_x1, x1);
+ smallfelem_expand(felem_y1, y1);
+ smallfelem_expand(felem_z1, z1);
+ point_add(felem_x3, felem_y3, felem_z3, felem_x1, felem_y1, felem_z1, 0, x2, y2, z2);
+ felem_shrink(x3, felem_x3);
+ felem_shrink(y3, felem_y3);
+ felem_shrink(z3, felem_z3);
+ }
+
+/* Base point pre computation
+ * --------------------------
+ *
+ * Two different sorts of precomputed tables are used in the following code.
+ * Each contain various points on the curve, where each point is three field
+ * elements (x, y, z).
+ *
+ * For the base point table, z is usually 1 (0 for the point at infinity).
+ * This table has 2 * 16 elements, starting with the following:
+ * index | bits | point
+ * ------+---------+------------------------------
+ * 0 | 0 0 0 0 | 0G
+ * 1 | 0 0 0 1 | 1G
+ * 2 | 0 0 1 0 | 2^64G
+ * 3 | 0 0 1 1 | (2^64 + 1)G
+ * 4 | 0 1 0 0 | 2^128G
+ * 5 | 0 1 0 1 | (2^128 + 1)G
+ * 6 | 0 1 1 0 | (2^128 + 2^64)G
+ * 7 | 0 1 1 1 | (2^128 + 2^64 + 1)G
+ * 8 | 1 0 0 0 | 2^192G
+ * 9 | 1 0 0 1 | (2^192 + 1)G
+ * 10 | 1 0 1 0 | (2^192 + 2^64)G
+ * 11 | 1 0 1 1 | (2^192 + 2^64 + 1)G
+ * 12 | 1 1 0 0 | (2^192 + 2^128)G
+ * 13 | 1 1 0 1 | (2^192 + 2^128 + 1)G
+ * 14 | 1 1 1 0 | (2^192 + 2^128 + 2^64)G
+ * 15 | 1 1 1 1 | (2^192 + 2^128 + 2^64 + 1)G
+ * followed by a copy of this with each element multiplied by 2^32.
+ *
+ * The reason for this is so that we can clock bits into four different
+ * locations when doing simple scalar multiplies against the base point,
+ * and then another four locations using the second 16 elements.
+ *
+ * Tables for other points have table[i] = iG for i in 0 .. 16. */
+
+/* gmul is the table of precomputed base points */
+static const smallfelem gmul[2][16][3] =
+{{{{0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}},
+ {{0xf4a13945d898c296, 0x77037d812deb33a0, 0xf8bce6e563a440f2, 0x6b17d1f2e12c4247},
+ {0xcbb6406837bf51f5, 0x2bce33576b315ece, 0x8ee7eb4a7c0f9e16, 0x4fe342e2fe1a7f9b},
+ {1, 0, 0, 0}},
+ {{0x90e75cb48e14db63, 0x29493baaad651f7e, 0x8492592e326e25de, 0x0fa822bc2811aaa5},
+ {0xe41124545f462ee7, 0x34b1a65050fe82f5, 0x6f4ad4bcb3df188b, 0xbff44ae8f5dba80d},
+ {1, 0, 0, 0}},
+ {{0x93391ce2097992af, 0xe96c98fd0d35f1fa, 0xb257c0de95e02789, 0x300a4bbc89d6726f},
+ {0xaa54a291c08127a0, 0x5bb1eeada9d806a5, 0x7f1ddb25ff1e3c6f, 0x72aac7e0d09b4644},
+ {1, 0, 0, 0}},
+ {{0x57c84fc9d789bd85, 0xfc35ff7dc297eac3, 0xfb982fd588c6766e, 0x447d739beedb5e67},
+ {0x0c7e33c972e25b32, 0x3d349b95a7fae500, 0xe12e9d953a4aaff7, 0x2d4825ab834131ee},
+ {1, 0, 0, 0}},
+ {{0x13949c932a1d367f, 0xef7fbd2b1a0a11b7, 0xddc6068bb91dfc60, 0xef9519328a9c72ff},
+ {0x196035a77376d8a8, 0x23183b0895ca1740, 0xc1ee9807022c219c, 0x611e9fc37dbb2c9b},
+ {1, 0, 0, 0}},
+ {{0xcae2b1920b57f4bc, 0x2936df5ec6c9bc36, 0x7dea6482e11238bf, 0x550663797b51f5d8},
+ {0x44ffe216348a964c, 0x9fb3d576dbdefbe1, 0x0afa40018d9d50e5, 0x157164848aecb851},
+ {1, 0, 0, 0}},
+ {{0xe48ecafffc5cde01, 0x7ccd84e70d715f26, 0xa2e8f483f43e4391, 0xeb5d7745b21141ea},
+ {0xcac917e2731a3479, 0x85f22cfe2844b645, 0x0990e6a158006cee, 0xeafd72ebdbecc17b},
+ {1, 0, 0, 0}},
+ {{0x6cf20ffb313728be, 0x96439591a3c6b94a, 0x2736ff8344315fc5, 0xa6d39677a7849276},
+ {0xf2bab833c357f5f4, 0x824a920c2284059b, 0x66b8babd2d27ecdf, 0x674f84749b0b8816},
+ {1, 0, 0, 0}},
+ {{0x2df48c04677c8a3e, 0x74e02f080203a56b, 0x31855f7db8c7fedb, 0x4e769e7672c9ddad},
+ {0xa4c36165b824bbb0, 0xfb9ae16f3b9122a5, 0x1ec0057206947281, 0x42b99082de830663},
+ {1, 0, 0, 0}},
+ {{0x6ef95150dda868b9, 0xd1f89e799c0ce131, 0x7fdc1ca008a1c478, 0x78878ef61c6ce04d},
+ {0x9c62b9121fe0d976, 0x6ace570ebde08d4f, 0xde53142c12309def, 0xb6cb3f5d7b72c321},
+ {1, 0, 0, 0}},
+ {{0x7f991ed2c31a3573, 0x5b82dd5bd54fb496, 0x595c5220812ffcae, 0x0c88bc4d716b1287},
+ {0x3a57bf635f48aca8, 0x7c8181f4df2564f3, 0x18d1b5b39c04e6aa, 0xdd5ddea3f3901dc6},
+ {1, 0, 0, 0}},
+ {{0xe96a79fb3e72ad0c, 0x43a0a28c42ba792f, 0xefe0a423083e49f3, 0x68f344af6b317466},
+ {0xcdfe17db3fb24d4a, 0x668bfc2271f5c626, 0x604ed93c24d67ff3, 0x31b9c405f8540a20},
+ {1, 0, 0, 0}},
+ {{0xd36b4789a2582e7f, 0x0d1a10144ec39c28, 0x663c62c3edbad7a0, 0x4052bf4b6f461db9},
+ {0x235a27c3188d25eb, 0xe724f33999bfcc5b, 0x862be6bd71d70cc8, 0xfecf4d5190b0fc61},
+ {1, 0, 0, 0}},
+ {{0x74346c10a1d4cfac, 0xafdf5cc08526a7a4, 0x123202a8f62bff7a, 0x1eddbae2c802e41a},
+ {0x8fa0af2dd603f844, 0x36e06b7e4c701917, 0x0c45f45273db33a0, 0x43104d86560ebcfc},
+ {1, 0, 0, 0}},
+ {{0x9615b5110d1d78e5, 0x66b0de3225c4744b, 0x0a4a46fb6aaf363a, 0xb48e26b484f7a21c},
+ {0x06ebb0f621a01b2d, 0xc004e4048b7b0f98, 0x64131bcdfed6f668, 0xfac015404d4d3dab},
+ {1, 0, 0, 0}}},
+ {{{0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}},
+ {{0x3a5a9e22185a5943, 0x1ab919365c65dfb6, 0x21656b32262c71da, 0x7fe36b40af22af89},
+ {0xd50d152c699ca101, 0x74b3d5867b8af212, 0x9f09f40407dca6f1, 0xe697d45825b63624},
+ {1, 0, 0, 0}},
+ {{0xa84aa9397512218e, 0xe9a521b074ca0141, 0x57880b3a18a2e902, 0x4a5b506612a677a6},
+ {0x0beada7a4c4f3840, 0x626db15419e26d9d, 0xc42604fbe1627d40, 0xeb13461ceac089f1},
+ {1, 0, 0, 0}},
+ {{0xf9faed0927a43281, 0x5e52c4144103ecbc, 0xc342967aa815c857, 0x0781b8291c6a220a},
+ {0x5a8343ceeac55f80, 0x88f80eeee54a05e3, 0x97b2a14f12916434, 0x690cde8df0151593},
+ {1, 0, 0, 0}},
+ {{0xaee9c75df7f82f2a, 0x9e4c35874afdf43a, 0xf5622df437371326, 0x8a535f566ec73617},
+ {0xc5f9a0ac223094b7, 0xcde533864c8c7669, 0x37e02819085a92bf, 0x0455c08468b08bd7},
+ {1, 0, 0, 0}},
+ {{0x0c0a6e2c9477b5d9, 0xf9a4bf62876dc444, 0x5050a949b6cdc279, 0x06bada7ab77f8276},
+ {0xc8b4aed1ea48dac9, 0xdebd8a4b7ea1070f, 0x427d49101366eb70, 0x5b476dfd0e6cb18a},
+ {1, 0, 0, 0}},
+ {{0x7c5c3e44278c340a, 0x4d54606812d66f3b, 0x29a751b1ae23c5d8, 0x3e29864e8a2ec908},
+ {0x142d2a6626dbb850, 0xad1744c4765bd780, 0x1f150e68e322d1ed, 0x239b90ea3dc31e7e},
+ {1, 0, 0, 0}},
+ {{0x78c416527a53322a, 0x305dde6709776f8e, 0xdbcab759f8862ed4, 0x820f4dd949f72ff7},
+ {0x6cc544a62b5debd4, 0x75be5d937b4e8cc4, 0x1b481b1b215c14d3, 0x140406ec783a05ec},
+ {1, 0, 0, 0}},
+ {{0x6a703f10e895df07, 0xfd75f3fa01876bd8, 0xeb5b06e70ce08ffe, 0x68f6b8542783dfee},
+ {0x90c76f8a78712655, 0xcf5293d2f310bf7f, 0xfbc8044dfda45028, 0xcbe1feba92e40ce6},
+ {1, 0, 0, 0}},
+ {{0xe998ceea4396e4c1, 0xfc82ef0b6acea274, 0x230f729f2250e927, 0xd0b2f94d2f420109},
+ {0x4305adddb38d4966, 0x10b838f8624c3b45, 0x7db2636658954e7a, 0x971459828b0719e5},
+ {1, 0, 0, 0}},
+ {{0x4bd6b72623369fc9, 0x57f2929e53d0b876, 0xc2d5cba4f2340687, 0x961610004a866aba},
+ {0x49997bcd2e407a5e, 0x69ab197d92ddcb24, 0x2cf1f2438fe5131c, 0x7acb9fadcee75e44},
+ {1, 0, 0, 0}},
+ {{0x254e839423d2d4c0, 0xf57f0c917aea685b, 0xa60d880f6f75aaea, 0x24eb9acca333bf5b},
+ {0xe3de4ccb1cda5dea, 0xfeef9341c51a6b4f, 0x743125f88bac4c4d, 0x69f891c5acd079cc},
+ {1, 0, 0, 0}},
+ {{0xeee44b35702476b5, 0x7ed031a0e45c2258, 0xb422d1e7bd6f8514, 0xe51f547c5972a107},
+ {0xa25bcd6fc9cf343d, 0x8ca922ee097c184e, 0xa62f98b3a9fe9a06, 0x1c309a2b25bb1387},
+ {1, 0, 0, 0}},
+ {{0x9295dbeb1967c459, 0xb00148833472c98e, 0xc504977708011828, 0x20b87b8aa2c4e503},
+ {0x3063175de057c277, 0x1bd539338fe582dd, 0x0d11adef5f69a044, 0xf5c6fa49919776be},
+ {1, 0, 0, 0}},
+ {{0x8c944e760fd59e11, 0x3876cba1102fad5f, 0xa454c3fad83faa56, 0x1ed7d1b9332010b9},
+ {0xa1011a270024b889, 0x05e4d0dcac0cd344, 0x52b520f0eb6a2a24, 0x3a2b03f03217257a},
+ {1, 0, 0, 0}},
+ {{0xf20fc2afdf1d043d, 0xf330240db58d5a62, 0xfc7d229ca0058c3b, 0x15fee545c78dd9f6},
+ {0x501e82885bc98cda, 0x41ef80e5d046ac04, 0x557d9f49461210fb, 0x4ab5b6b2b8753f81},
+ {1, 0, 0, 0}}}};
+
+/* select_point selects the |idx|th point from a precomputation table and
+ * copies it to out. */
+static void select_point(const u64 idx, unsigned int size, const smallfelem pre_comp[16][3], smallfelem out[3])
+ {
+ unsigned i, j;
+ u64 *outlimbs = &out[0][0];
+ memset(outlimbs, 0, 3 * sizeof(smallfelem));
+
+ for (i = 0; i < size; i++)
+ {
+ const u64 *inlimbs = (u64*) &pre_comp[i][0][0];
+ u64 mask = i ^ idx;
+ mask |= mask >> 4;
+ mask |= mask >> 2;
+ mask |= mask >> 1;
+ mask &= 1;
+ mask--;
+ for (j = 0; j < NLIMBS * 3; j++)
+ outlimbs[j] |= inlimbs[j] & mask;
+ }
+ }
+
+/* get_bit returns the |i|th bit in |in| */
+static char get_bit(const felem_bytearray in, int i)
+ {
+ if ((i < 0) || (i >= 256))
+ return 0;
+ return (in[i >> 3] >> (i & 7)) & 1;
+ }
+
+/* Interleaved point multiplication using precomputed point multiples:
+ * The small point multiples 0*P, 1*P, ..., 17*P are in pre_comp[],
+ * the scalars in scalars[]. If g_scalar is non-NULL, we also add this multiple
+ * of the generator, using certain (large) precomputed multiples in g_pre_comp.
+ * Output point (X, Y, Z) is stored in x_out, y_out, z_out */
+static void batch_mul(felem x_out, felem y_out, felem z_out,
+ const felem_bytearray scalars[], const unsigned num_points, const u8 *g_scalar,
+ const int mixed, const smallfelem pre_comp[][17][3], const smallfelem g_pre_comp[2][16][3])
+ {
+ int i, skip;
+ unsigned num, gen_mul = (g_scalar != NULL);
+ felem nq[3], ftmp;
+ smallfelem tmp[3];
+ u64 bits;
+ u8 sign, digit;
+
+ /* set nq to the point at infinity */
+ memset(nq, 0, 3 * sizeof(felem));
+
+ /* Loop over all scalars msb-to-lsb, interleaving additions
+ * of multiples of the generator (two in each of the last 32 rounds)
+ * and additions of other points multiples (every 5th round).
+ */
+ skip = 1; /* save two point operations in the first round */
+ for (i = (num_points ? 255 : 31); i >= 0; --i)
+ {
+ /* double */
+ if (!skip)
+ point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]);
+
+ /* add multiples of the generator */
+ if (gen_mul && (i <= 31))
+ {
+ /* first, look 32 bits upwards */
+ bits = get_bit(g_scalar, i + 224) << 3;
+ bits |= get_bit(g_scalar, i + 160) << 2;
+ bits |= get_bit(g_scalar, i + 96) << 1;
+ bits |= get_bit(g_scalar, i + 32);
+ /* select the point to add, in constant time */
+ select_point(bits, 16, g_pre_comp[1], tmp);
+
+ if (!skip)
+ {
+ point_add(nq[0], nq[1], nq[2],
+ nq[0], nq[1], nq[2],
+ 1 /* mixed */, tmp[0], tmp[1], tmp[2]);
+ }
+ else
+ {
+ smallfelem_expand(nq[0], tmp[0]);
+ smallfelem_expand(nq[1], tmp[1]);
+ smallfelem_expand(nq[2], tmp[2]);
+ skip = 0;
+ }
+
+ /* second, look at the current position */
+ bits = get_bit(g_scalar, i + 192) << 3;
+ bits |= get_bit(g_scalar, i + 128) << 2;
+ bits |= get_bit(g_scalar, i + 64) << 1;
+ bits |= get_bit(g_scalar, i);
+ /* select the point to add, in constant time */
+ select_point(bits, 16, g_pre_comp[0], tmp);
+ point_add(nq[0], nq[1], nq[2],
+ nq[0], nq[1], nq[2],
+ 1 /* mixed */, tmp[0], tmp[1], tmp[2]);
+ }
+
+ /* do other additions every 5 doublings */
+ if (num_points && (i % 5 == 0))
+ {
+ /* loop over all scalars */
+ for (num = 0; num < num_points; ++num)
+ {
+ bits = get_bit(scalars[num], i + 4) << 5;
+ bits |= get_bit(scalars[num], i + 3) << 4;
+ bits |= get_bit(scalars[num], i + 2) << 3;
+ bits |= get_bit(scalars[num], i + 1) << 2;
+ bits |= get_bit(scalars[num], i) << 1;
+ bits |= get_bit(scalars[num], i - 1);
+ ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits);
+
+ /* select the point to add or subtract, in constant time */
+ select_point(digit, 17, pre_comp[num], tmp);
+ smallfelem_neg(ftmp, tmp[1]); /* (X, -Y, Z) is the negative point */
+ copy_small_conditional(ftmp, tmp[1], (((limb) sign) - 1));
+ felem_contract(tmp[1], ftmp);
+
+ if (!skip)
+ {
+ point_add(nq[0], nq[1], nq[2],
+ nq[0], nq[1], nq[2],
+ mixed, tmp[0], tmp[1], tmp[2]);
+ }
+ else
+ {
+ smallfelem_expand(nq[0], tmp[0]);
+ smallfelem_expand(nq[1], tmp[1]);
+ smallfelem_expand(nq[2], tmp[2]);
+ skip = 0;
+ }
+ }
+ }
+ }
+ felem_assign(x_out, nq[0]);
+ felem_assign(y_out, nq[1]);
+ felem_assign(z_out, nq[2]);
+ }
+
+/* Precomputation for the group generator. */
+typedef struct {
+ smallfelem g_pre_comp[2][16][3];
+ int references;
+} NISTP256_PRE_COMP;
+
+const EC_METHOD *EC_GFp_nistp256_method(void)
+ {
+ static const EC_METHOD ret = {
+ EC_FLAGS_DEFAULT_OCT,
+ NID_X9_62_prime_field,
+ ec_GFp_nistp256_group_init,
+ ec_GFp_simple_group_finish,
+ ec_GFp_simple_group_clear_finish,
+ ec_GFp_nist_group_copy,
+ ec_GFp_nistp256_group_set_curve,
+ ec_GFp_simple_group_get_curve,
+ ec_GFp_simple_group_get_degree,
+ ec_GFp_simple_group_check_discriminant,
+ ec_GFp_simple_point_init,
+ ec_GFp_simple_point_finish,
+ ec_GFp_simple_point_clear_finish,
+ ec_GFp_simple_point_copy,
+ ec_GFp_simple_point_set_to_infinity,
+ ec_GFp_simple_set_Jprojective_coordinates_GFp,
+ ec_GFp_simple_get_Jprojective_coordinates_GFp,
+ ec_GFp_simple_point_set_affine_coordinates,
+ ec_GFp_nistp256_point_get_affine_coordinates,
+ 0 /* point_set_compressed_coordinates */,
+ 0 /* point2oct */,
+ 0 /* oct2point */,
+ ec_GFp_simple_add,
+ ec_GFp_simple_dbl,
+ ec_GFp_simple_invert,
+ ec_GFp_simple_is_at_infinity,
+ ec_GFp_simple_is_on_curve,
+ ec_GFp_simple_cmp,
+ ec_GFp_simple_make_affine,
+ ec_GFp_simple_points_make_affine,
+ ec_GFp_nistp256_points_mul,
+ ec_GFp_nistp256_precompute_mult,
+ ec_GFp_nistp256_have_precompute_mult,
+ ec_GFp_nist_field_mul,
+ ec_GFp_nist_field_sqr,
+ 0 /* field_div */,
+ 0 /* field_encode */,
+ 0 /* field_decode */,
+ 0 /* field_set_to_one */ };
+
+ return &ret;
+ }
+
+/******************************************************************************/
+/* FUNCTIONS TO MANAGE PRECOMPUTATION
+ */
+
+static NISTP256_PRE_COMP *nistp256_pre_comp_new()
+ {
+ NISTP256_PRE_COMP *ret = NULL;
+ ret = (NISTP256_PRE_COMP *) OPENSSL_malloc(sizeof *ret);
+ if (!ret)
+ {
+ ECerr(EC_F_NISTP256_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
+ return ret;
+ }
+ memset(ret->g_pre_comp, 0, sizeof(ret->g_pre_comp));
+ ret->references = 1;
+ return ret;
+ }
+
+static void *nistp256_pre_comp_dup(void *src_)
+ {
+ NISTP256_PRE_COMP *src = src_;
+
+ /* no need to actually copy, these objects never change! */
+ CRYPTO_add(&src->references, 1, CRYPTO_LOCK_EC_PRE_COMP);
+
+ return src_;
+ }
+
+static void nistp256_pre_comp_free(void *pre_)
+ {
+ int i;
+ NISTP256_PRE_COMP *pre = pre_;
+
+ if (!pre)
+ return;
+
+ i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
+ if (i > 0)
+ return;
+
+ OPENSSL_free(pre);
+ }
+
+static void nistp256_pre_comp_clear_free(void *pre_)
+ {
+ int i;
+ NISTP256_PRE_COMP *pre = pre_;
+
+ if (!pre)
+ return;
+
+ i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
+ if (i > 0)
+ return;
+
+ OPENSSL_cleanse(pre, sizeof *pre);
+ OPENSSL_free(pre);
+ }
+
+/******************************************************************************/
+/* OPENSSL EC_METHOD FUNCTIONS
+ */
+
+int ec_GFp_nistp256_group_init(EC_GROUP *group)
+ {
+ int ret;
+ ret = ec_GFp_simple_group_init(group);
+ group->a_is_minus3 = 1;
+ return ret;
+ }
+
+int ec_GFp_nistp256_group_set_curve(EC_GROUP *group, const BIGNUM *p,
+ const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
+ {
+ int ret = 0;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *curve_p, *curve_a, *curve_b;
+
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((curve_p = BN_CTX_get(ctx)) == NULL) ||
+ ((curve_a = BN_CTX_get(ctx)) == NULL) ||
+ ((curve_b = BN_CTX_get(ctx)) == NULL)) goto err;
+ BN_bin2bn(nistp256_curve_params[0], sizeof(felem_bytearray), curve_p);
+ BN_bin2bn(nistp256_curve_params[1], sizeof(felem_bytearray), curve_a);
+ BN_bin2bn(nistp256_curve_params[2], sizeof(felem_bytearray), curve_b);
+ if ((BN_cmp(curve_p, p)) || (BN_cmp(curve_a, a)) ||
+ (BN_cmp(curve_b, b)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP256_GROUP_SET_CURVE,
+ EC_R_WRONG_CURVE_PARAMETERS);
+ goto err;
+ }
+ group->field_mod_func = BN_nist_mod_256;
+ ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+ }
+
+/* Takes the Jacobian coordinates (X, Y, Z) of a point and returns
+ * (X', Y') = (X/Z^2, Y/Z^3) */
+int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
+ {
+ felem z1, z2, x_in, y_in;
+ smallfelem x_out, y_out;
+ longfelem tmp;
+
+ if (EC_POINT_is_at_infinity(group, point))
+ {
+ ECerr(EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES,
+ EC_R_POINT_AT_INFINITY);
+ return 0;
+ }
+ if ((!BN_to_felem(x_in, &point->X)) || (!BN_to_felem(y_in, &point->Y)) ||
+ (!BN_to_felem(z1, &point->Z))) return 0;
+ felem_inv(z2, z1);
+ felem_square(tmp, z2); felem_reduce(z1, tmp);
+ felem_mul(tmp, x_in, z1); felem_reduce(x_in, tmp);
+ felem_contract(x_out, x_in);
+ if (x != NULL)
+ {
+ if (!smallfelem_to_BN(x, x_out)) {
+ ECerr(EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES,
+ ERR_R_BN_LIB);
+ return 0;
+ }
+ }
+ felem_mul(tmp, z1, z2); felem_reduce(z1, tmp);
+ felem_mul(tmp, y_in, z1); felem_reduce(y_in, tmp);
+ felem_contract(y_out, y_in);
+ if (y != NULL)
+ {
+ if (!smallfelem_to_BN(y, y_out))
+ {
+ ECerr(EC_F_EC_GFP_NISTP256_POINT_GET_AFFINE_COORDINATES,
+ ERR_R_BN_LIB);
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+static void make_points_affine(size_t num, smallfelem points[/* num */][3], smallfelem tmp_smallfelems[/* num+1 */])
+ {
+ /* Runs in constant time, unless an input is the point at infinity
+ * (which normally shouldn't happen). */
+ ec_GFp_nistp_points_make_affine_internal(
+ num,
+ points,
+ sizeof(smallfelem),
+ tmp_smallfelems,
+ (void (*)(void *)) smallfelem_one,
+ (int (*)(const void *)) smallfelem_is_zero_int,
+ (void (*)(void *, const void *)) smallfelem_assign,
+ (void (*)(void *, const void *)) smallfelem_square_contract,
+ (void (*)(void *, const void *, const void *)) smallfelem_mul_contract,
+ (void (*)(void *, const void *)) smallfelem_inv_contract,
+ (void (*)(void *, const void *)) smallfelem_assign /* nothing to contract */);
+ }
+
+/* Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL values
+ * Result is stored in r (r can equal one of the inputs). */
+int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
+ const BIGNUM *scalar, size_t num, const EC_POINT *points[],
+ const BIGNUM *scalars[], BN_CTX *ctx)
+ {
+ int ret = 0;
+ int j;
+ int mixed = 0;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y, *z, *tmp_scalar;
+ felem_bytearray g_secret;
+ felem_bytearray *secrets = NULL;
+ smallfelem (*pre_comp)[17][3] = NULL;
+ smallfelem *tmp_smallfelems = NULL;
+ felem_bytearray tmp;
+ unsigned i, num_bytes;
+ int have_pre_comp = 0;
+ size_t num_points = num;
+ smallfelem x_in, y_in, z_in;
+ felem x_out, y_out, z_out;
+ NISTP256_PRE_COMP *pre = NULL;
+ const smallfelem (*g_pre_comp)[16][3] = NULL;
+ EC_POINT *generator = NULL;
+ const EC_POINT *p = NULL;
+ const BIGNUM *p_scalar = NULL;
+
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((x = BN_CTX_get(ctx)) == NULL) ||
+ ((y = BN_CTX_get(ctx)) == NULL) ||
+ ((z = BN_CTX_get(ctx)) == NULL) ||
+ ((tmp_scalar = BN_CTX_get(ctx)) == NULL))
+ goto err;
+
+ if (scalar != NULL)
+ {
+ pre = EC_EX_DATA_get_data(group->extra_data,
+ nistp256_pre_comp_dup, nistp256_pre_comp_free,
+ nistp256_pre_comp_clear_free);
+ if (pre)
+ /* we have precomputation, try to use it */
+ g_pre_comp = (const smallfelem (*)[16][3]) pre->g_pre_comp;
+ else
+ /* try to use the standard precomputation */
+ g_pre_comp = &gmul[0];
+ generator = EC_POINT_new(group);
+ if (generator == NULL)
+ goto err;
+ /* get the generator from precomputation */
+ if (!smallfelem_to_BN(x, g_pre_comp[0][1][0]) ||
+ !smallfelem_to_BN(y, g_pre_comp[0][1][1]) ||
+ !smallfelem_to_BN(z, g_pre_comp[0][1][2]))
+ {
+ ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ if (!EC_POINT_set_Jprojective_coordinates_GFp(group,
+ generator, x, y, z, ctx))
+ goto err;
+ if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
+ /* precomputation matches generator */
+ have_pre_comp = 1;
+ else
+ /* we don't have valid precomputation:
+ * treat the generator as a random point */
+ num_points++;
+ }
+ if (num_points > 0)
+ {
+ if (num_points >= 3)
+ {
+ /* unless we precompute multiples for just one or two points,
+ * converting those into affine form is time well spent */
+ mixed = 1;
+ }
+ secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray));
+ pre_comp = OPENSSL_malloc(num_points * 17 * 3 * sizeof(smallfelem));
+ if (mixed)
+ tmp_smallfelems = OPENSSL_malloc((num_points * 17 + 1) * sizeof(smallfelem));
+ if ((secrets == NULL) || (pre_comp == NULL) || (mixed && (tmp_smallfelems == NULL)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* we treat NULL scalars as 0, and NULL points as points at infinity,
+ * i.e., they contribute nothing to the linear combination */
+ memset(secrets, 0, num_points * sizeof(felem_bytearray));
+ memset(pre_comp, 0, num_points * 17 * 3 * sizeof(smallfelem));
+ for (i = 0; i < num_points; ++i)
+ {
+ if (i == num)
+ /* we didn't have a valid precomputation, so we pick
+ * the generator */
+ {
+ p = EC_GROUP_get0_generator(group);
+ p_scalar = scalar;
+ }
+ else
+ /* the i^th point */
+ {
+ p = points[i];
+ p_scalar = scalars[i];
+ }
+ if ((p_scalar != NULL) && (p != NULL))
+ {
+ /* reduce scalar to 0 <= scalar < 2^256 */
+ if ((BN_num_bits(p_scalar) > 256) || (BN_is_negative(p_scalar)))
+ {
+ /* this is an unusual input, and we don't guarantee
+ * constant-timeness */
+ if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx))
+ {
+ ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ num_bytes = BN_bn2bin(tmp_scalar, tmp);
+ }
+ else
+ num_bytes = BN_bn2bin(p_scalar, tmp);
+ flip_endian(secrets[i], tmp, num_bytes);
+ /* precompute multiples */
+ if ((!BN_to_felem(x_out, &p->X)) ||
+ (!BN_to_felem(y_out, &p->Y)) ||
+ (!BN_to_felem(z_out, &p->Z))) goto err;
+ felem_shrink(pre_comp[i][1][0], x_out);
+ felem_shrink(pre_comp[i][1][1], y_out);
+ felem_shrink(pre_comp[i][1][2], z_out);
+ for (j = 2; j <= 16; ++j)
+ {
+ if (j & 1)
+ {
+ point_add_small(
+ pre_comp[i][j][0], pre_comp[i][j][1], pre_comp[i][j][2],
+ pre_comp[i][1][0], pre_comp[i][1][1], pre_comp[i][1][2],
+ pre_comp[i][j-1][0], pre_comp[i][j-1][1], pre_comp[i][j-1][2]);
+ }
+ else
+ {
+ point_double_small(
+ pre_comp[i][j][0], pre_comp[i][j][1], pre_comp[i][j][2],
+ pre_comp[i][j/2][0], pre_comp[i][j/2][1], pre_comp[i][j/2][2]);
+ }
+ }
+ }
+ }
+ if (mixed)
+ make_points_affine(num_points * 17, pre_comp[0], tmp_smallfelems);
+ }
+
+ /* the scalar for the generator */
+ if ((scalar != NULL) && (have_pre_comp))
+ {
+ memset(g_secret, 0, sizeof(g_secret));
+ /* reduce scalar to 0 <= scalar < 2^256 */
+ if ((BN_num_bits(scalar) > 256) || (BN_is_negative(scalar)))
+ {
+ /* this is an unusual input, and we don't guarantee
+ * constant-timeness */
+ if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx))
+ {
+ ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ num_bytes = BN_bn2bin(tmp_scalar, tmp);
+ }
+ else
+ num_bytes = BN_bn2bin(scalar, tmp);
+ flip_endian(g_secret, tmp, num_bytes);
+ /* do the multiplication with generator precomputation*/
+ batch_mul(x_out, y_out, z_out,
+ (const felem_bytearray (*)) secrets, num_points,
+ g_secret,
+ mixed, (const smallfelem (*)[17][3]) pre_comp,
+ g_pre_comp);
+ }
+ else
+ /* do the multiplication without generator precomputation */
+ batch_mul(x_out, y_out, z_out,
+ (const felem_bytearray (*)) secrets, num_points,
+ NULL, mixed, (const smallfelem (*)[17][3]) pre_comp, NULL);
+ /* reduce the output to its unique minimal representation */
+ felem_contract(x_in, x_out);
+ felem_contract(y_in, y_out);
+ felem_contract(z_in, z_out);
+ if ((!smallfelem_to_BN(x, x_in)) || (!smallfelem_to_BN(y, y_in)) ||
+ (!smallfelem_to_BN(z, z_in)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP256_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ ret = EC_POINT_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx);
+
+err:
+ BN_CTX_end(ctx);
+ if (generator != NULL)
+ EC_POINT_free(generator);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (secrets != NULL)
+ OPENSSL_free(secrets);
+ if (pre_comp != NULL)
+ OPENSSL_free(pre_comp);
+ if (tmp_smallfelems != NULL)
+ OPENSSL_free(tmp_smallfelems);
+ return ret;
+ }
+
+int ec_GFp_nistp256_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
+ {
+ int ret = 0;
+ NISTP256_PRE_COMP *pre = NULL;
+ int i, j;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y;
+ EC_POINT *generator = NULL;
+ smallfelem tmp_smallfelems[32];
+ felem x_tmp, y_tmp, z_tmp;
+
+ /* throw away old precomputation */
+ EC_EX_DATA_free_data(&group->extra_data, nistp256_pre_comp_dup,
+ nistp256_pre_comp_free, nistp256_pre_comp_clear_free);
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((x = BN_CTX_get(ctx)) == NULL) ||
+ ((y = BN_CTX_get(ctx)) == NULL))
+ goto err;
+ /* get the generator */
+ if (group->generator == NULL) goto err;
+ generator = EC_POINT_new(group);
+ if (generator == NULL)
+ goto err;
+ BN_bin2bn(nistp256_curve_params[3], sizeof (felem_bytearray), x);
+ BN_bin2bn(nistp256_curve_params[4], sizeof (felem_bytearray), y);
+ if (!EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, ctx))
+ goto err;
+ if ((pre = nistp256_pre_comp_new()) == NULL)
+ goto err;
+ /* if the generator is the standard one, use built-in precomputation */
+ if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
+ {
+ memcpy(pre->g_pre_comp, gmul, sizeof(pre->g_pre_comp));
+ ret = 1;
+ goto err;
+ }
+ if ((!BN_to_felem(x_tmp, &group->generator->X)) ||
+ (!BN_to_felem(y_tmp, &group->generator->Y)) ||
+ (!BN_to_felem(z_tmp, &group->generator->Z)))
+ goto err;
+ felem_shrink(pre->g_pre_comp[0][1][0], x_tmp);
+ felem_shrink(pre->g_pre_comp[0][1][1], y_tmp);
+ felem_shrink(pre->g_pre_comp[0][1][2], z_tmp);
+ /* compute 2^64*G, 2^128*G, 2^192*G for the first table,
+ * 2^32*G, 2^96*G, 2^160*G, 2^224*G for the second one
+ */
+ for (i = 1; i <= 8; i <<= 1)
+ {
+ point_double_small(
+ pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2],
+ pre->g_pre_comp[0][i][0], pre->g_pre_comp[0][i][1], pre->g_pre_comp[0][i][2]);
+ for (j = 0; j < 31; ++j)
+ {
+ point_double_small(
+ pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2],
+ pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2]);
+ }
+ if (i == 8)
+ break;
+ point_double_small(
+ pre->g_pre_comp[0][2*i][0], pre->g_pre_comp[0][2*i][1], pre->g_pre_comp[0][2*i][2],
+ pre->g_pre_comp[1][i][0], pre->g_pre_comp[1][i][1], pre->g_pre_comp[1][i][2]);
+ for (j = 0; j < 31; ++j)
+ {
+ point_double_small(
+ pre->g_pre_comp[0][2*i][0], pre->g_pre_comp[0][2*i][1], pre->g_pre_comp[0][2*i][2],
+ pre->g_pre_comp[0][2*i][0], pre->g_pre_comp[0][2*i][1], pre->g_pre_comp[0][2*i][2]);
+ }
+ }
+ for (i = 0; i < 2; i++)
+ {
+ /* g_pre_comp[i][0] is the point at infinity */
+ memset(pre->g_pre_comp[i][0], 0, sizeof(pre->g_pre_comp[i][0]));
+ /* the remaining multiples */
+ /* 2^64*G + 2^128*G resp. 2^96*G + 2^160*G */
+ point_add_small(
+ pre->g_pre_comp[i][6][0], pre->g_pre_comp[i][6][1], pre->g_pre_comp[i][6][2],
+ pre->g_pre_comp[i][4][0], pre->g_pre_comp[i][4][1], pre->g_pre_comp[i][4][2],
+ pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1], pre->g_pre_comp[i][2][2]);
+ /* 2^64*G + 2^192*G resp. 2^96*G + 2^224*G */
+ point_add_small(
+ pre->g_pre_comp[i][10][0], pre->g_pre_comp[i][10][1], pre->g_pre_comp[i][10][2],
+ pre->g_pre_comp[i][8][0], pre->g_pre_comp[i][8][1], pre->g_pre_comp[i][8][2],
+ pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1], pre->g_pre_comp[i][2][2]);
+ /* 2^128*G + 2^192*G resp. 2^160*G + 2^224*G */
+ point_add_small(
+ pre->g_pre_comp[i][12][0], pre->g_pre_comp[i][12][1], pre->g_pre_comp[i][12][2],
+ pre->g_pre_comp[i][8][0], pre->g_pre_comp[i][8][1], pre->g_pre_comp[i][8][2],
+ pre->g_pre_comp[i][4][0], pre->g_pre_comp[i][4][1], pre->g_pre_comp[i][4][2]);
+ /* 2^64*G + 2^128*G + 2^192*G resp. 2^96*G + 2^160*G + 2^224*G */
+ point_add_small(
+ pre->g_pre_comp[i][14][0], pre->g_pre_comp[i][14][1], pre->g_pre_comp[i][14][2],
+ pre->g_pre_comp[i][12][0], pre->g_pre_comp[i][12][1], pre->g_pre_comp[i][12][2],
+ pre->g_pre_comp[i][2][0], pre->g_pre_comp[i][2][1], pre->g_pre_comp[i][2][2]);
+ for (j = 1; j < 8; ++j)
+ {
+ /* odd multiples: add G resp. 2^32*G */
+ point_add_small(
+ pre->g_pre_comp[i][2*j+1][0], pre->g_pre_comp[i][2*j+1][1], pre->g_pre_comp[i][2*j+1][2],
+ pre->g_pre_comp[i][2*j][0], pre->g_pre_comp[i][2*j][1], pre->g_pre_comp[i][2*j][2],
+ pre->g_pre_comp[i][1][0], pre->g_pre_comp[i][1][1], pre->g_pre_comp[i][1][2]);
+ }
+ }
+ make_points_affine(31, &(pre->g_pre_comp[0][1]), tmp_smallfelems);
+
+ if (!EC_EX_DATA_set_data(&group->extra_data, pre, nistp256_pre_comp_dup,
+ nistp256_pre_comp_free, nistp256_pre_comp_clear_free))
+ goto err;
+ ret = 1;
+ pre = NULL;
+ err:
+ BN_CTX_end(ctx);
+ if (generator != NULL)
+ EC_POINT_free(generator);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (pre)
+ nistp256_pre_comp_free(pre);
+ return ret;
+ }
+
+int ec_GFp_nistp256_have_precompute_mult(const EC_GROUP *group)
+ {
+ if (EC_EX_DATA_get_data(group->extra_data, nistp256_pre_comp_dup,
+ nistp256_pre_comp_free, nistp256_pre_comp_clear_free)
+ != NULL)
+ return 1;
+ else
+ return 0;
+ }
+#else
+static void *dummy=&dummy;
+#endif
diff --git a/crypto/ec/ecp_nistp521.c b/crypto/ec/ecp_nistp521.c
new file mode 100644
index 0000000000000..178b655f7f177
--- /dev/null
+++ b/crypto/ec/ecp_nistp521.c
@@ -0,0 +1,2025 @@
+/* crypto/ec/ecp_nistp521.c */
+/*
+ * Written by Adam Langley (Google) for the OpenSSL project
+ */
+/* Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ *
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A 64-bit implementation of the NIST P-521 elliptic curve point multiplication
+ *
+ * OpenSSL integration was taken from Emilia Kasper's work in ecp_nistp224.c.
+ * Otherwise based on Emilia's P224 work, which was inspired by my curve25519
+ * work which got its smarts from Daniel J. Bernstein's work on the same.
+ */
+
+#include <openssl/opensslconf.h>
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+
+#ifndef OPENSSL_SYS_VMS
+#include <stdint.h>
+#else
+#include <inttypes.h>
+#endif
+
+#include <string.h>
+#include <openssl/err.h>
+#include "ec_lcl.h"
+
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+ /* even with gcc, the typedef won't work for 32-bit platforms */
+ typedef __uint128_t uint128_t; /* nonstandard; implemented by gcc on 64-bit platforms */
+#else
+ #error "Need GCC 3.1 or later to define type uint128_t"
+#endif
+
+typedef uint8_t u8;
+typedef uint64_t u64;
+typedef int64_t s64;
+
+/* The underlying field.
+ *
+ * P521 operates over GF(2^521-1). We can serialise an element of this field
+ * into 66 bytes where the most significant byte contains only a single bit. We
+ * call this an felem_bytearray. */
+
+typedef u8 felem_bytearray[66];
+
+/* These are the parameters of P521, taken from FIPS 186-3, section D.1.2.5.
+ * These values are big-endian. */
+static const felem_bytearray nistp521_curve_params[5] =
+ {
+ {0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* p */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff},
+ {0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* a = -3 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xfc},
+ {0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, /* b */
+ 0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85,
+ 0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3,
+ 0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1,
+ 0x09, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e,
+ 0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1,
+ 0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c,
+ 0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50,
+ 0x3f, 0x00},
+ {0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, /* x */
+ 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95,
+ 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
+ 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d,
+ 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7,
+ 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
+ 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a,
+ 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5,
+ 0xbd, 0x66},
+ {0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, /* y */
+ 0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d,
+ 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
+ 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e,
+ 0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4,
+ 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
+ 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72,
+ 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1,
+ 0x66, 0x50}
+ };
+
+/* The representation of field elements.
+ * ------------------------------------
+ *
+ * We represent field elements with nine values. These values are either 64 or
+ * 128 bits and the field element represented is:
+ * v[0]*2^0 + v[1]*2^58 + v[2]*2^116 + ... + v[8]*2^464 (mod p)
+ * Each of the nine values is called a 'limb'. Since the limbs are spaced only
+ * 58 bits apart, but are greater than 58 bits in length, the most significant
+ * bits of each limb overlap with the least significant bits of the next.
+ *
+ * A field element with 64-bit limbs is an 'felem'. One with 128-bit limbs is a
+ * 'largefelem' */
+
+#define NLIMBS 9
+
+typedef uint64_t limb;
+typedef limb felem[NLIMBS];
+typedef uint128_t largefelem[NLIMBS];
+
+static const limb bottom57bits = 0x1ffffffffffffff;
+static const limb bottom58bits = 0x3ffffffffffffff;
+
+/* bin66_to_felem takes a little-endian byte array and converts it into felem
+ * form. This assumes that the CPU is little-endian. */
+static void bin66_to_felem(felem out, const u8 in[66])
+ {
+ out[0] = (*((limb*) &in[0])) & bottom58bits;
+ out[1] = (*((limb*) &in[7]) >> 2) & bottom58bits;
+ out[2] = (*((limb*) &in[14]) >> 4) & bottom58bits;
+ out[3] = (*((limb*) &in[21]) >> 6) & bottom58bits;
+ out[4] = (*((limb*) &in[29])) & bottom58bits;
+ out[5] = (*((limb*) &in[36]) >> 2) & bottom58bits;
+ out[6] = (*((limb*) &in[43]) >> 4) & bottom58bits;
+ out[7] = (*((limb*) &in[50]) >> 6) & bottom58bits;
+ out[8] = (*((limb*) &in[58])) & bottom57bits;
+ }
+
+/* felem_to_bin66 takes an felem and serialises into a little endian, 66 byte
+ * array. This assumes that the CPU is little-endian. */
+static void felem_to_bin66(u8 out[66], const felem in)
+ {
+ memset(out, 0, 66);
+ (*((limb*) &out[0])) = in[0];
+ (*((limb*) &out[7])) |= in[1] << 2;
+ (*((limb*) &out[14])) |= in[2] << 4;
+ (*((limb*) &out[21])) |= in[3] << 6;
+ (*((limb*) &out[29])) = in[4];
+ (*((limb*) &out[36])) |= in[5] << 2;
+ (*((limb*) &out[43])) |= in[6] << 4;
+ (*((limb*) &out[50])) |= in[7] << 6;
+ (*((limb*) &out[58])) = in[8];
+ }
+
+/* To preserve endianness when using BN_bn2bin and BN_bin2bn */
+static void flip_endian(u8 *out, const u8 *in, unsigned len)
+ {
+ unsigned i;
+ for (i = 0; i < len; ++i)
+ out[i] = in[len-1-i];
+ }
+
+/* BN_to_felem converts an OpenSSL BIGNUM into an felem */
+static int BN_to_felem(felem out, const BIGNUM *bn)
+ {
+ felem_bytearray b_in;
+ felem_bytearray b_out;
+ unsigned num_bytes;
+
+ /* BN_bn2bin eats leading zeroes */
+ memset(b_out, 0, sizeof b_out);
+ num_bytes = BN_num_bytes(bn);
+ if (num_bytes > sizeof b_out)
+ {
+ ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
+ return 0;
+ }
+ if (BN_is_negative(bn))
+ {
+ ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE);
+ return 0;
+ }
+ num_bytes = BN_bn2bin(bn, b_in);
+ flip_endian(b_out, b_in, num_bytes);
+ bin66_to_felem(out, b_out);
+ return 1;
+ }
+
+/* felem_to_BN converts an felem into an OpenSSL BIGNUM */
+static BIGNUM *felem_to_BN(BIGNUM *out, const felem in)
+ {
+ felem_bytearray b_in, b_out;
+ felem_to_bin66(b_in, in);
+ flip_endian(b_out, b_in, sizeof b_out);
+ return BN_bin2bn(b_out, sizeof b_out, out);
+ }
+
+
+/* Field operations
+ * ---------------- */
+
+static void felem_one(felem out)
+ {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ }
+
+static void felem_assign(felem out, const felem in)
+ {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[4] = in[4];
+ out[5] = in[5];
+ out[6] = in[6];
+ out[7] = in[7];
+ out[8] = in[8];
+ }
+
+/* felem_sum64 sets out = out + in. */
+static void felem_sum64(felem out, const felem in)
+ {
+ out[0] += in[0];
+ out[1] += in[1];
+ out[2] += in[2];
+ out[3] += in[3];
+ out[4] += in[4];
+ out[5] += in[5];
+ out[6] += in[6];
+ out[7] += in[7];
+ out[8] += in[8];
+ }
+
+/* felem_scalar sets out = in * scalar */
+static void felem_scalar(felem out, const felem in, limb scalar)
+ {
+ out[0] = in[0] * scalar;
+ out[1] = in[1] * scalar;
+ out[2] = in[2] * scalar;
+ out[3] = in[3] * scalar;
+ out[4] = in[4] * scalar;
+ out[5] = in[5] * scalar;
+ out[6] = in[6] * scalar;
+ out[7] = in[7] * scalar;
+ out[8] = in[8] * scalar;
+ }
+
+/* felem_scalar64 sets out = out * scalar */
+static void felem_scalar64(felem out, limb scalar)
+ {
+ out[0] *= scalar;
+ out[1] *= scalar;
+ out[2] *= scalar;
+ out[3] *= scalar;
+ out[4] *= scalar;
+ out[5] *= scalar;
+ out[6] *= scalar;
+ out[7] *= scalar;
+ out[8] *= scalar;
+ }
+
+/* felem_scalar128 sets out = out * scalar */
+static void felem_scalar128(largefelem out, limb scalar)
+ {
+ out[0] *= scalar;
+ out[1] *= scalar;
+ out[2] *= scalar;
+ out[3] *= scalar;
+ out[4] *= scalar;
+ out[5] *= scalar;
+ out[6] *= scalar;
+ out[7] *= scalar;
+ out[8] *= scalar;
+ }
+
+/* felem_neg sets |out| to |-in|
+ * On entry:
+ * in[i] < 2^59 + 2^14
+ * On exit:
+ * out[i] < 2^62
+ */
+static void felem_neg(felem out, const felem in)
+ {
+ /* In order to prevent underflow, we subtract from 0 mod p. */
+ static const limb two62m3 = (((limb)1) << 62) - (((limb)1) << 5);
+ static const limb two62m2 = (((limb)1) << 62) - (((limb)1) << 4);
+
+ out[0] = two62m3 - in[0];
+ out[1] = two62m2 - in[1];
+ out[2] = two62m2 - in[2];
+ out[3] = two62m2 - in[3];
+ out[4] = two62m2 - in[4];
+ out[5] = two62m2 - in[5];
+ out[6] = two62m2 - in[6];
+ out[7] = two62m2 - in[7];
+ out[8] = two62m2 - in[8];
+ }
+
+/* felem_diff64 subtracts |in| from |out|
+ * On entry:
+ * in[i] < 2^59 + 2^14
+ * On exit:
+ * out[i] < out[i] + 2^62
+ */
+static void felem_diff64(felem out, const felem in)
+ {
+ /* In order to prevent underflow, we add 0 mod p before subtracting. */
+ static const limb two62m3 = (((limb)1) << 62) - (((limb)1) << 5);
+ static const limb two62m2 = (((limb)1) << 62) - (((limb)1) << 4);
+
+ out[0] += two62m3 - in[0];
+ out[1] += two62m2 - in[1];
+ out[2] += two62m2 - in[2];
+ out[3] += two62m2 - in[3];
+ out[4] += two62m2 - in[4];
+ out[5] += two62m2 - in[5];
+ out[6] += two62m2 - in[6];
+ out[7] += two62m2 - in[7];
+ out[8] += two62m2 - in[8];
+ }
+
+/* felem_diff_128_64 subtracts |in| from |out|
+ * On entry:
+ * in[i] < 2^62 + 2^17
+ * On exit:
+ * out[i] < out[i] + 2^63
+ */
+static void felem_diff_128_64(largefelem out, const felem in)
+ {
+ /* In order to prevent underflow, we add 0 mod p before subtracting. */
+ static const limb two63m6 = (((limb)1) << 62) - (((limb)1) << 5);
+ static const limb two63m5 = (((limb)1) << 62) - (((limb)1) << 4);
+
+ out[0] += two63m6 - in[0];
+ out[1] += two63m5 - in[1];
+ out[2] += two63m5 - in[2];
+ out[3] += two63m5 - in[3];
+ out[4] += two63m5 - in[4];
+ out[5] += two63m5 - in[5];
+ out[6] += two63m5 - in[6];
+ out[7] += two63m5 - in[7];
+ out[8] += two63m5 - in[8];
+ }
+
+/* felem_diff_128_64 subtracts |in| from |out|
+ * On entry:
+ * in[i] < 2^126
+ * On exit:
+ * out[i] < out[i] + 2^127 - 2^69
+ */
+static void felem_diff128(largefelem out, const largefelem in)
+ {
+ /* In order to prevent underflow, we add 0 mod p before subtracting. */
+ static const uint128_t two127m70 = (((uint128_t)1) << 127) - (((uint128_t)1) << 70);
+ static const uint128_t two127m69 = (((uint128_t)1) << 127) - (((uint128_t)1) << 69);
+
+ out[0] += (two127m70 - in[0]);
+ out[1] += (two127m69 - in[1]);
+ out[2] += (two127m69 - in[2]);
+ out[3] += (two127m69 - in[3]);
+ out[4] += (two127m69 - in[4]);
+ out[5] += (two127m69 - in[5]);
+ out[6] += (two127m69 - in[6]);
+ out[7] += (two127m69 - in[7]);
+ out[8] += (two127m69 - in[8]);
+ }
+
+/* felem_square sets |out| = |in|^2
+ * On entry:
+ * in[i] < 2^62
+ * On exit:
+ * out[i] < 17 * max(in[i]) * max(in[i])
+ */
+static void felem_square(largefelem out, const felem in)
+ {
+ felem inx2, inx4;
+ felem_scalar(inx2, in, 2);
+ felem_scalar(inx4, in, 4);
+
+ /* We have many cases were we want to do
+ * in[x] * in[y] +
+ * in[y] * in[x]
+ * This is obviously just
+ * 2 * in[x] * in[y]
+ * However, rather than do the doubling on the 128 bit result, we
+ * double one of the inputs to the multiplication by reading from
+ * |inx2| */
+
+ out[0] = ((uint128_t) in[0]) * in[0];
+ out[1] = ((uint128_t) in[0]) * inx2[1];
+ out[2] = ((uint128_t) in[0]) * inx2[2] +
+ ((uint128_t) in[1]) * in[1];
+ out[3] = ((uint128_t) in[0]) * inx2[3] +
+ ((uint128_t) in[1]) * inx2[2];
+ out[4] = ((uint128_t) in[0]) * inx2[4] +
+ ((uint128_t) in[1]) * inx2[3] +
+ ((uint128_t) in[2]) * in[2];
+ out[5] = ((uint128_t) in[0]) * inx2[5] +
+ ((uint128_t) in[1]) * inx2[4] +
+ ((uint128_t) in[2]) * inx2[3];
+ out[6] = ((uint128_t) in[0]) * inx2[6] +
+ ((uint128_t) in[1]) * inx2[5] +
+ ((uint128_t) in[2]) * inx2[4] +
+ ((uint128_t) in[3]) * in[3];
+ out[7] = ((uint128_t) in[0]) * inx2[7] +
+ ((uint128_t) in[1]) * inx2[6] +
+ ((uint128_t) in[2]) * inx2[5] +
+ ((uint128_t) in[3]) * inx2[4];
+ out[8] = ((uint128_t) in[0]) * inx2[8] +
+ ((uint128_t) in[1]) * inx2[7] +
+ ((uint128_t) in[2]) * inx2[6] +
+ ((uint128_t) in[3]) * inx2[5] +
+ ((uint128_t) in[4]) * in[4];
+
+ /* The remaining limbs fall above 2^521, with the first falling at
+ * 2^522. They correspond to locations one bit up from the limbs
+ * produced above so we would have to multiply by two to align them.
+ * Again, rather than operate on the 128-bit result, we double one of
+ * the inputs to the multiplication. If we want to double for both this
+ * reason, and the reason above, then we end up multiplying by four. */
+
+ /* 9 */
+ out[0] += ((uint128_t) in[1]) * inx4[8] +
+ ((uint128_t) in[2]) * inx4[7] +
+ ((uint128_t) in[3]) * inx4[6] +
+ ((uint128_t) in[4]) * inx4[5];
+
+ /* 10 */
+ out[1] += ((uint128_t) in[2]) * inx4[8] +
+ ((uint128_t) in[3]) * inx4[7] +
+ ((uint128_t) in[4]) * inx4[6] +
+ ((uint128_t) in[5]) * inx2[5];
+
+ /* 11 */
+ out[2] += ((uint128_t) in[3]) * inx4[8] +
+ ((uint128_t) in[4]) * inx4[7] +
+ ((uint128_t) in[5]) * inx4[6];
+
+ /* 12 */
+ out[3] += ((uint128_t) in[4]) * inx4[8] +
+ ((uint128_t) in[5]) * inx4[7] +
+ ((uint128_t) in[6]) * inx2[6];
+
+ /* 13 */
+ out[4] += ((uint128_t) in[5]) * inx4[8] +
+ ((uint128_t) in[6]) * inx4[7];
+
+ /* 14 */
+ out[5] += ((uint128_t) in[6]) * inx4[8] +
+ ((uint128_t) in[7]) * inx2[7];
+
+ /* 15 */
+ out[6] += ((uint128_t) in[7]) * inx4[8];
+
+ /* 16 */
+ out[7] += ((uint128_t) in[8]) * inx2[8];
+ }
+
+/* felem_mul sets |out| = |in1| * |in2|
+ * On entry:
+ * in1[i] < 2^64
+ * in2[i] < 2^63
+ * On exit:
+ * out[i] < 17 * max(in1[i]) * max(in2[i])
+ */
+static void felem_mul(largefelem out, const felem in1, const felem in2)
+ {
+ felem in2x2;
+ felem_scalar(in2x2, in2, 2);
+
+ out[0] = ((uint128_t) in1[0]) * in2[0];
+
+ out[1] = ((uint128_t) in1[0]) * in2[1] +
+ ((uint128_t) in1[1]) * in2[0];
+
+ out[2] = ((uint128_t) in1[0]) * in2[2] +
+ ((uint128_t) in1[1]) * in2[1] +
+ ((uint128_t) in1[2]) * in2[0];
+
+ out[3] = ((uint128_t) in1[0]) * in2[3] +
+ ((uint128_t) in1[1]) * in2[2] +
+ ((uint128_t) in1[2]) * in2[1] +
+ ((uint128_t) in1[3]) * in2[0];
+
+ out[4] = ((uint128_t) in1[0]) * in2[4] +
+ ((uint128_t) in1[1]) * in2[3] +
+ ((uint128_t) in1[2]) * in2[2] +
+ ((uint128_t) in1[3]) * in2[1] +
+ ((uint128_t) in1[4]) * in2[0];
+
+ out[5] = ((uint128_t) in1[0]) * in2[5] +
+ ((uint128_t) in1[1]) * in2[4] +
+ ((uint128_t) in1[2]) * in2[3] +
+ ((uint128_t) in1[3]) * in2[2] +
+ ((uint128_t) in1[4]) * in2[1] +
+ ((uint128_t) in1[5]) * in2[0];
+
+ out[6] = ((uint128_t) in1[0]) * in2[6] +
+ ((uint128_t) in1[1]) * in2[5] +
+ ((uint128_t) in1[2]) * in2[4] +
+ ((uint128_t) in1[3]) * in2[3] +
+ ((uint128_t) in1[4]) * in2[2] +
+ ((uint128_t) in1[5]) * in2[1] +
+ ((uint128_t) in1[6]) * in2[0];
+
+ out[7] = ((uint128_t) in1[0]) * in2[7] +
+ ((uint128_t) in1[1]) * in2[6] +
+ ((uint128_t) in1[2]) * in2[5] +
+ ((uint128_t) in1[3]) * in2[4] +
+ ((uint128_t) in1[4]) * in2[3] +
+ ((uint128_t) in1[5]) * in2[2] +
+ ((uint128_t) in1[6]) * in2[1] +
+ ((uint128_t) in1[7]) * in2[0];
+
+ out[8] = ((uint128_t) in1[0]) * in2[8] +
+ ((uint128_t) in1[1]) * in2[7] +
+ ((uint128_t) in1[2]) * in2[6] +
+ ((uint128_t) in1[3]) * in2[5] +
+ ((uint128_t) in1[4]) * in2[4] +
+ ((uint128_t) in1[5]) * in2[3] +
+ ((uint128_t) in1[6]) * in2[2] +
+ ((uint128_t) in1[7]) * in2[1] +
+ ((uint128_t) in1[8]) * in2[0];
+
+ /* See comment in felem_square about the use of in2x2 here */
+
+ out[0] += ((uint128_t) in1[1]) * in2x2[8] +
+ ((uint128_t) in1[2]) * in2x2[7] +
+ ((uint128_t) in1[3]) * in2x2[6] +
+ ((uint128_t) in1[4]) * in2x2[5] +
+ ((uint128_t) in1[5]) * in2x2[4] +
+ ((uint128_t) in1[6]) * in2x2[3] +
+ ((uint128_t) in1[7]) * in2x2[2] +
+ ((uint128_t) in1[8]) * in2x2[1];
+
+ out[1] += ((uint128_t) in1[2]) * in2x2[8] +
+ ((uint128_t) in1[3]) * in2x2[7] +
+ ((uint128_t) in1[4]) * in2x2[6] +
+ ((uint128_t) in1[5]) * in2x2[5] +
+ ((uint128_t) in1[6]) * in2x2[4] +
+ ((uint128_t) in1[7]) * in2x2[3] +
+ ((uint128_t) in1[8]) * in2x2[2];
+
+ out[2] += ((uint128_t) in1[3]) * in2x2[8] +
+ ((uint128_t) in1[4]) * in2x2[7] +
+ ((uint128_t) in1[5]) * in2x2[6] +
+ ((uint128_t) in1[6]) * in2x2[5] +
+ ((uint128_t) in1[7]) * in2x2[4] +
+ ((uint128_t) in1[8]) * in2x2[3];
+
+ out[3] += ((uint128_t) in1[4]) * in2x2[8] +
+ ((uint128_t) in1[5]) * in2x2[7] +
+ ((uint128_t) in1[6]) * in2x2[6] +
+ ((uint128_t) in1[7]) * in2x2[5] +
+ ((uint128_t) in1[8]) * in2x2[4];
+
+ out[4] += ((uint128_t) in1[5]) * in2x2[8] +
+ ((uint128_t) in1[6]) * in2x2[7] +
+ ((uint128_t) in1[7]) * in2x2[6] +
+ ((uint128_t) in1[8]) * in2x2[5];
+
+ out[5] += ((uint128_t) in1[6]) * in2x2[8] +
+ ((uint128_t) in1[7]) * in2x2[7] +
+ ((uint128_t) in1[8]) * in2x2[6];
+
+ out[6] += ((uint128_t) in1[7]) * in2x2[8] +
+ ((uint128_t) in1[8]) * in2x2[7];
+
+ out[7] += ((uint128_t) in1[8]) * in2x2[8];
+ }
+
+static const limb bottom52bits = 0xfffffffffffff;
+
+/* felem_reduce converts a largefelem to an felem.
+ * On entry:
+ * in[i] < 2^128
+ * On exit:
+ * out[i] < 2^59 + 2^14
+ */
+static void felem_reduce(felem out, const largefelem in)
+ {
+ u64 overflow1, overflow2;
+
+ out[0] = ((limb) in[0]) & bottom58bits;
+ out[1] = ((limb) in[1]) & bottom58bits;
+ out[2] = ((limb) in[2]) & bottom58bits;
+ out[3] = ((limb) in[3]) & bottom58bits;
+ out[4] = ((limb) in[4]) & bottom58bits;
+ out[5] = ((limb) in[5]) & bottom58bits;
+ out[6] = ((limb) in[6]) & bottom58bits;
+ out[7] = ((limb) in[7]) & bottom58bits;
+ out[8] = ((limb) in[8]) & bottom58bits;
+
+ /* out[i] < 2^58 */
+
+ out[1] += ((limb) in[0]) >> 58;
+ out[1] += (((limb) (in[0] >> 64)) & bottom52bits) << 6;
+ /* out[1] < 2^58 + 2^6 + 2^58
+ * = 2^59 + 2^6 */
+ out[2] += ((limb) (in[0] >> 64)) >> 52;
+
+ out[2] += ((limb) in[1]) >> 58;
+ out[2] += (((limb) (in[1] >> 64)) & bottom52bits) << 6;
+ out[3] += ((limb) (in[1] >> 64)) >> 52;
+
+ out[3] += ((limb) in[2]) >> 58;
+ out[3] += (((limb) (in[2] >> 64)) & bottom52bits) << 6;
+ out[4] += ((limb) (in[2] >> 64)) >> 52;
+
+ out[4] += ((limb) in[3]) >> 58;
+ out[4] += (((limb) (in[3] >> 64)) & bottom52bits) << 6;
+ out[5] += ((limb) (in[3] >> 64)) >> 52;
+
+ out[5] += ((limb) in[4]) >> 58;
+ out[5] += (((limb) (in[4] >> 64)) & bottom52bits) << 6;
+ out[6] += ((limb) (in[4] >> 64)) >> 52;
+
+ out[6] += ((limb) in[5]) >> 58;
+ out[6] += (((limb) (in[5] >> 64)) & bottom52bits) << 6;
+ out[7] += ((limb) (in[5] >> 64)) >> 52;
+
+ out[7] += ((limb) in[6]) >> 58;
+ out[7] += (((limb) (in[6] >> 64)) & bottom52bits) << 6;
+ out[8] += ((limb) (in[6] >> 64)) >> 52;
+
+ out[8] += ((limb) in[7]) >> 58;
+ out[8] += (((limb) (in[7] >> 64)) & bottom52bits) << 6;
+ /* out[x > 1] < 2^58 + 2^6 + 2^58 + 2^12
+ * < 2^59 + 2^13 */
+ overflow1 = ((limb) (in[7] >> 64)) >> 52;
+
+ overflow1 += ((limb) in[8]) >> 58;
+ overflow1 += (((limb) (in[8] >> 64)) & bottom52bits) << 6;
+ overflow2 = ((limb) (in[8] >> 64)) >> 52;
+
+ overflow1 <<= 1; /* overflow1 < 2^13 + 2^7 + 2^59 */
+ overflow2 <<= 1; /* overflow2 < 2^13 */
+
+ out[0] += overflow1; /* out[0] < 2^60 */
+ out[1] += overflow2; /* out[1] < 2^59 + 2^6 + 2^13 */
+
+ out[1] += out[0] >> 58; out[0] &= bottom58bits;
+ /* out[0] < 2^58
+ * out[1] < 2^59 + 2^6 + 2^13 + 2^2
+ * < 2^59 + 2^14 */
+ }
+
+static void felem_square_reduce(felem out, const felem in)
+ {
+ largefelem tmp;
+ felem_square(tmp, in);
+ felem_reduce(out, tmp);
+ }
+
+static void felem_mul_reduce(felem out, const felem in1, const felem in2)
+ {
+ largefelem tmp;
+ felem_mul(tmp, in1, in2);
+ felem_reduce(out, tmp);
+ }
+
+/* felem_inv calculates |out| = |in|^{-1}
+ *
+ * Based on Fermat's Little Theorem:
+ * a^p = a (mod p)
+ * a^{p-1} = 1 (mod p)
+ * a^{p-2} = a^{-1} (mod p)
+ */
+static void felem_inv(felem out, const felem in)
+ {
+ felem ftmp, ftmp2, ftmp3, ftmp4;
+ largefelem tmp;
+ unsigned i;
+
+ felem_square(tmp, in); felem_reduce(ftmp, tmp); /* 2^1 */
+ felem_mul(tmp, in, ftmp); felem_reduce(ftmp, tmp); /* 2^2 - 2^0 */
+ felem_assign(ftmp2, ftmp);
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^3 - 2^1 */
+ felem_mul(tmp, in, ftmp); felem_reduce(ftmp, tmp); /* 2^3 - 2^0 */
+ felem_square(tmp, ftmp); felem_reduce(ftmp, tmp); /* 2^4 - 2^1 */
+
+ felem_square(tmp, ftmp2); felem_reduce(ftmp3, tmp); /* 2^3 - 2^1 */
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^4 - 2^2 */
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^4 - 2^0 */
+
+ felem_assign(ftmp2, ftmp3);
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^5 - 2^1 */
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^6 - 2^2 */
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^7 - 2^3 */
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^8 - 2^4 */
+ felem_assign(ftmp4, ftmp3);
+ felem_mul(tmp, ftmp3, ftmp); felem_reduce(ftmp4, tmp); /* 2^8 - 2^1 */
+ felem_square(tmp, ftmp4); felem_reduce(ftmp4, tmp); /* 2^9 - 2^2 */
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^8 - 2^0 */
+ felem_assign(ftmp2, ftmp3);
+
+ for (i = 0; i < 8; i++)
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^16 - 2^8 */
+ }
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^16 - 2^0 */
+ felem_assign(ftmp2, ftmp3);
+
+ for (i = 0; i < 16; i++)
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^32 - 2^16 */
+ }
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^32 - 2^0 */
+ felem_assign(ftmp2, ftmp3);
+
+ for (i = 0; i < 32; i++)
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^64 - 2^32 */
+ }
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^64 - 2^0 */
+ felem_assign(ftmp2, ftmp3);
+
+ for (i = 0; i < 64; i++)
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^128 - 2^64 */
+ }
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^128 - 2^0 */
+ felem_assign(ftmp2, ftmp3);
+
+ for (i = 0; i < 128; i++)
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^256 - 2^128 */
+ }
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^256 - 2^0 */
+ felem_assign(ftmp2, ftmp3);
+
+ for (i = 0; i < 256; i++)
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^512 - 2^256 */
+ }
+ felem_mul(tmp, ftmp3, ftmp2); felem_reduce(ftmp3, tmp); /* 2^512 - 2^0 */
+
+ for (i = 0; i < 9; i++)
+ {
+ felem_square(tmp, ftmp3); felem_reduce(ftmp3, tmp); /* 2^521 - 2^9 */
+ }
+ felem_mul(tmp, ftmp3, ftmp4); felem_reduce(ftmp3, tmp); /* 2^512 - 2^2 */
+ felem_mul(tmp, ftmp3, in); felem_reduce(out, tmp); /* 2^512 - 3 */
+}
+
+/* This is 2^521-1, expressed as an felem */
+static const felem kPrime =
+ {
+ 0x03ffffffffffffff, 0x03ffffffffffffff, 0x03ffffffffffffff,
+ 0x03ffffffffffffff, 0x03ffffffffffffff, 0x03ffffffffffffff,
+ 0x03ffffffffffffff, 0x03ffffffffffffff, 0x01ffffffffffffff
+ };
+
+/* felem_is_zero returns a limb with all bits set if |in| == 0 (mod p) and 0
+ * otherwise.
+ * On entry:
+ * in[i] < 2^59 + 2^14
+ */
+static limb felem_is_zero(const felem in)
+ {
+ felem ftmp;
+ limb is_zero, is_p;
+ felem_assign(ftmp, in);
+
+ ftmp[0] += ftmp[8] >> 57; ftmp[8] &= bottom57bits;
+ /* ftmp[8] < 2^57 */
+ ftmp[1] += ftmp[0] >> 58; ftmp[0] &= bottom58bits;
+ ftmp[2] += ftmp[1] >> 58; ftmp[1] &= bottom58bits;
+ ftmp[3] += ftmp[2] >> 58; ftmp[2] &= bottom58bits;
+ ftmp[4] += ftmp[3] >> 58; ftmp[3] &= bottom58bits;
+ ftmp[5] += ftmp[4] >> 58; ftmp[4] &= bottom58bits;
+ ftmp[6] += ftmp[5] >> 58; ftmp[5] &= bottom58bits;
+ ftmp[7] += ftmp[6] >> 58; ftmp[6] &= bottom58bits;
+ ftmp[8] += ftmp[7] >> 58; ftmp[7] &= bottom58bits;
+ /* ftmp[8] < 2^57 + 4 */
+
+ /* The ninth limb of 2*(2^521-1) is 0x03ffffffffffffff, which is
+ * greater than our bound for ftmp[8]. Therefore we only have to check
+ * if the zero is zero or 2^521-1. */
+
+ is_zero = 0;
+ is_zero |= ftmp[0];
+ is_zero |= ftmp[1];
+ is_zero |= ftmp[2];
+ is_zero |= ftmp[3];
+ is_zero |= ftmp[4];
+ is_zero |= ftmp[5];
+ is_zero |= ftmp[6];
+ is_zero |= ftmp[7];
+ is_zero |= ftmp[8];
+
+ is_zero--;
+ /* We know that ftmp[i] < 2^63, therefore the only way that the top bit
+ * can be set is if is_zero was 0 before the decrement. */
+ is_zero = ((s64) is_zero) >> 63;
+
+ is_p = ftmp[0] ^ kPrime[0];
+ is_p |= ftmp[1] ^ kPrime[1];
+ is_p |= ftmp[2] ^ kPrime[2];
+ is_p |= ftmp[3] ^ kPrime[3];
+ is_p |= ftmp[4] ^ kPrime[4];
+ is_p |= ftmp[5] ^ kPrime[5];
+ is_p |= ftmp[6] ^ kPrime[6];
+ is_p |= ftmp[7] ^ kPrime[7];
+ is_p |= ftmp[8] ^ kPrime[8];
+
+ is_p--;
+ is_p = ((s64) is_p) >> 63;
+
+ is_zero |= is_p;
+ return is_zero;
+ }
+
+static int felem_is_zero_int(const felem in)
+ {
+ return (int) (felem_is_zero(in) & ((limb)1));
+ }
+
+/* felem_contract converts |in| to its unique, minimal representation.
+ * On entry:
+ * in[i] < 2^59 + 2^14
+ */
+static void felem_contract(felem out, const felem in)
+ {
+ limb is_p, is_greater, sign;
+ static const limb two58 = ((limb)1) << 58;
+
+ felem_assign(out, in);
+
+ out[0] += out[8] >> 57; out[8] &= bottom57bits;
+ /* out[8] < 2^57 */
+ out[1] += out[0] >> 58; out[0] &= bottom58bits;
+ out[2] += out[1] >> 58; out[1] &= bottom58bits;
+ out[3] += out[2] >> 58; out[2] &= bottom58bits;
+ out[4] += out[3] >> 58; out[3] &= bottom58bits;
+ out[5] += out[4] >> 58; out[4] &= bottom58bits;
+ out[6] += out[5] >> 58; out[5] &= bottom58bits;
+ out[7] += out[6] >> 58; out[6] &= bottom58bits;
+ out[8] += out[7] >> 58; out[7] &= bottom58bits;
+ /* out[8] < 2^57 + 4 */
+
+ /* If the value is greater than 2^521-1 then we have to subtract
+ * 2^521-1 out. See the comments in felem_is_zero regarding why we
+ * don't test for other multiples of the prime. */
+
+ /* First, if |out| is equal to 2^521-1, we subtract it out to get zero. */
+
+ is_p = out[0] ^ kPrime[0];
+ is_p |= out[1] ^ kPrime[1];
+ is_p |= out[2] ^ kPrime[2];
+ is_p |= out[3] ^ kPrime[3];
+ is_p |= out[4] ^ kPrime[4];
+ is_p |= out[5] ^ kPrime[5];
+ is_p |= out[6] ^ kPrime[6];
+ is_p |= out[7] ^ kPrime[7];
+ is_p |= out[8] ^ kPrime[8];
+
+ is_p--;
+ is_p &= is_p << 32;
+ is_p &= is_p << 16;
+ is_p &= is_p << 8;
+ is_p &= is_p << 4;
+ is_p &= is_p << 2;
+ is_p &= is_p << 1;
+ is_p = ((s64) is_p) >> 63;
+ is_p = ~is_p;
+
+ /* is_p is 0 iff |out| == 2^521-1 and all ones otherwise */
+
+ out[0] &= is_p;
+ out[1] &= is_p;
+ out[2] &= is_p;
+ out[3] &= is_p;
+ out[4] &= is_p;
+ out[5] &= is_p;
+ out[6] &= is_p;
+ out[7] &= is_p;
+ out[8] &= is_p;
+
+ /* In order to test that |out| >= 2^521-1 we need only test if out[8]
+ * >> 57 is greater than zero as (2^521-1) + x >= 2^522 */
+ is_greater = out[8] >> 57;
+ is_greater |= is_greater << 32;
+ is_greater |= is_greater << 16;
+ is_greater |= is_greater << 8;
+ is_greater |= is_greater << 4;
+ is_greater |= is_greater << 2;
+ is_greater |= is_greater << 1;
+ is_greater = ((s64) is_greater) >> 63;
+
+ out[0] -= kPrime[0] & is_greater;
+ out[1] -= kPrime[1] & is_greater;
+ out[2] -= kPrime[2] & is_greater;
+ out[3] -= kPrime[3] & is_greater;
+ out[4] -= kPrime[4] & is_greater;
+ out[5] -= kPrime[5] & is_greater;
+ out[6] -= kPrime[6] & is_greater;
+ out[7] -= kPrime[7] & is_greater;
+ out[8] -= kPrime[8] & is_greater;
+
+ /* Eliminate negative coefficients */
+ sign = -(out[0] >> 63); out[0] += (two58 & sign); out[1] -= (1 & sign);
+ sign = -(out[1] >> 63); out[1] += (two58 & sign); out[2] -= (1 & sign);
+ sign = -(out[2] >> 63); out[2] += (two58 & sign); out[3] -= (1 & sign);
+ sign = -(out[3] >> 63); out[3] += (two58 & sign); out[4] -= (1 & sign);
+ sign = -(out[4] >> 63); out[4] += (two58 & sign); out[5] -= (1 & sign);
+ sign = -(out[0] >> 63); out[5] += (two58 & sign); out[6] -= (1 & sign);
+ sign = -(out[6] >> 63); out[6] += (two58 & sign); out[7] -= (1 & sign);
+ sign = -(out[7] >> 63); out[7] += (two58 & sign); out[8] -= (1 & sign);
+ sign = -(out[5] >> 63); out[5] += (two58 & sign); out[6] -= (1 & sign);
+ sign = -(out[6] >> 63); out[6] += (two58 & sign); out[7] -= (1 & sign);
+ sign = -(out[7] >> 63); out[7] += (two58 & sign); out[8] -= (1 & sign);
+ }
+
+/* Group operations
+ * ----------------
+ *
+ * Building on top of the field operations we have the operations on the
+ * elliptic curve group itself. Points on the curve are represented in Jacobian
+ * coordinates */
+
+/* point_double calcuates 2*(x_in, y_in, z_in)
+ *
+ * The method is taken from:
+ * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
+ *
+ * Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed.
+ * while x_out == y_in is not (maybe this works, but it's not tested). */
+static void
+point_double(felem x_out, felem y_out, felem z_out,
+ const felem x_in, const felem y_in, const felem z_in)
+ {
+ largefelem tmp, tmp2;
+ felem delta, gamma, beta, alpha, ftmp, ftmp2;
+
+ felem_assign(ftmp, x_in);
+ felem_assign(ftmp2, x_in);
+
+ /* delta = z^2 */
+ felem_square(tmp, z_in);
+ felem_reduce(delta, tmp); /* delta[i] < 2^59 + 2^14 */
+
+ /* gamma = y^2 */
+ felem_square(tmp, y_in);
+ felem_reduce(gamma, tmp); /* gamma[i] < 2^59 + 2^14 */
+
+ /* beta = x*gamma */
+ felem_mul(tmp, x_in, gamma);
+ felem_reduce(beta, tmp); /* beta[i] < 2^59 + 2^14 */
+
+ /* alpha = 3*(x-delta)*(x+delta) */
+ felem_diff64(ftmp, delta);
+ /* ftmp[i] < 2^61 */
+ felem_sum64(ftmp2, delta);
+ /* ftmp2[i] < 2^60 + 2^15 */
+ felem_scalar64(ftmp2, 3);
+ /* ftmp2[i] < 3*2^60 + 3*2^15 */
+ felem_mul(tmp, ftmp, ftmp2);
+ /* tmp[i] < 17(3*2^121 + 3*2^76)
+ * = 61*2^121 + 61*2^76
+ * < 64*2^121 + 64*2^76
+ * = 2^127 + 2^82
+ * < 2^128 */
+ felem_reduce(alpha, tmp);
+
+ /* x' = alpha^2 - 8*beta */
+ felem_square(tmp, alpha);
+ /* tmp[i] < 17*2^120
+ * < 2^125 */
+ felem_assign(ftmp, beta);
+ felem_scalar64(ftmp, 8);
+ /* ftmp[i] < 2^62 + 2^17 */
+ felem_diff_128_64(tmp, ftmp);
+ /* tmp[i] < 2^125 + 2^63 + 2^62 + 2^17 */
+ felem_reduce(x_out, tmp);
+
+ /* z' = (y + z)^2 - gamma - delta */
+ felem_sum64(delta, gamma);
+ /* delta[i] < 2^60 + 2^15 */
+ felem_assign(ftmp, y_in);
+ felem_sum64(ftmp, z_in);
+ /* ftmp[i] < 2^60 + 2^15 */
+ felem_square(tmp, ftmp);
+ /* tmp[i] < 17(2^122)
+ * < 2^127 */
+ felem_diff_128_64(tmp, delta);
+ /* tmp[i] < 2^127 + 2^63 */
+ felem_reduce(z_out, tmp);
+
+ /* y' = alpha*(4*beta - x') - 8*gamma^2 */
+ felem_scalar64(beta, 4);
+ /* beta[i] < 2^61 + 2^16 */
+ felem_diff64(beta, x_out);
+ /* beta[i] < 2^61 + 2^60 + 2^16 */
+ felem_mul(tmp, alpha, beta);
+ /* tmp[i] < 17*((2^59 + 2^14)(2^61 + 2^60 + 2^16))
+ * = 17*(2^120 + 2^75 + 2^119 + 2^74 + 2^75 + 2^30)
+ * = 17*(2^120 + 2^119 + 2^76 + 2^74 + 2^30)
+ * < 2^128 */
+ felem_square(tmp2, gamma);
+ /* tmp2[i] < 17*(2^59 + 2^14)^2
+ * = 17*(2^118 + 2^74 + 2^28) */
+ felem_scalar128(tmp2, 8);
+ /* tmp2[i] < 8*17*(2^118 + 2^74 + 2^28)
+ * = 2^125 + 2^121 + 2^81 + 2^77 + 2^35 + 2^31
+ * < 2^126 */
+ felem_diff128(tmp, tmp2);
+ /* tmp[i] < 2^127 - 2^69 + 17(2^120 + 2^119 + 2^76 + 2^74 + 2^30)
+ * = 2^127 + 2^124 + 2^122 + 2^120 + 2^118 + 2^80 + 2^78 + 2^76 +
+ * 2^74 + 2^69 + 2^34 + 2^30
+ * < 2^128 */
+ felem_reduce(y_out, tmp);
+ }
+
+/* copy_conditional copies in to out iff mask is all ones. */
+static void
+copy_conditional(felem out, const felem in, limb mask)
+ {
+ unsigned i;
+ for (i = 0; i < NLIMBS; ++i)
+ {
+ const limb tmp = mask & (in[i] ^ out[i]);
+ out[i] ^= tmp;
+ }
+ }
+
+/* point_add calcuates (x1, y1, z1) + (x2, y2, z2)
+ *
+ * The method is taken from
+ * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl,
+ * adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity).
+ *
+ * This function includes a branch for checking whether the two input points
+ * are equal (while not equal to the point at infinity). This case never
+ * happens during single point multiplication, so there is no timing leak for
+ * ECDH or ECDSA signing. */
+static void point_add(felem x3, felem y3, felem z3,
+ const felem x1, const felem y1, const felem z1,
+ const int mixed, const felem x2, const felem y2, const felem z2)
+ {
+ felem ftmp, ftmp2, ftmp3, ftmp4, ftmp5, ftmp6, x_out, y_out, z_out;
+ largefelem tmp, tmp2;
+ limb x_equal, y_equal, z1_is_zero, z2_is_zero;
+
+ z1_is_zero = felem_is_zero(z1);
+ z2_is_zero = felem_is_zero(z2);
+
+ /* ftmp = z1z1 = z1**2 */
+ felem_square(tmp, z1);
+ felem_reduce(ftmp, tmp);
+
+ if (!mixed)
+ {
+ /* ftmp2 = z2z2 = z2**2 */
+ felem_square(tmp, z2);
+ felem_reduce(ftmp2, tmp);
+
+ /* u1 = ftmp3 = x1*z2z2 */
+ felem_mul(tmp, x1, ftmp2);
+ felem_reduce(ftmp3, tmp);
+
+ /* ftmp5 = z1 + z2 */
+ felem_assign(ftmp5, z1);
+ felem_sum64(ftmp5, z2);
+ /* ftmp5[i] < 2^61 */
+
+ /* ftmp5 = (z1 + z2)**2 - z1z1 - z2z2 = 2*z1z2 */
+ felem_square(tmp, ftmp5);
+ /* tmp[i] < 17*2^122 */
+ felem_diff_128_64(tmp, ftmp);
+ /* tmp[i] < 17*2^122 + 2^63 */
+ felem_diff_128_64(tmp, ftmp2);
+ /* tmp[i] < 17*2^122 + 2^64 */
+ felem_reduce(ftmp5, tmp);
+
+ /* ftmp2 = z2 * z2z2 */
+ felem_mul(tmp, ftmp2, z2);
+ felem_reduce(ftmp2, tmp);
+
+ /* s1 = ftmp6 = y1 * z2**3 */
+ felem_mul(tmp, y1, ftmp2);
+ felem_reduce(ftmp6, tmp);
+ }
+ else
+ {
+ /* We'll assume z2 = 1 (special case z2 = 0 is handled later) */
+
+ /* u1 = ftmp3 = x1*z2z2 */
+ felem_assign(ftmp3, x1);
+
+ /* ftmp5 = 2*z1z2 */
+ felem_scalar(ftmp5, z1, 2);
+
+ /* s1 = ftmp6 = y1 * z2**3 */
+ felem_assign(ftmp6, y1);
+ }
+
+ /* u2 = x2*z1z1 */
+ felem_mul(tmp, x2, ftmp);
+ /* tmp[i] < 17*2^120 */
+
+ /* h = ftmp4 = u2 - u1 */
+ felem_diff_128_64(tmp, ftmp3);
+ /* tmp[i] < 17*2^120 + 2^63 */
+ felem_reduce(ftmp4, tmp);
+
+ x_equal = felem_is_zero(ftmp4);
+
+ /* z_out = ftmp5 * h */
+ felem_mul(tmp, ftmp5, ftmp4);
+ felem_reduce(z_out, tmp);
+
+ /* ftmp = z1 * z1z1 */
+ felem_mul(tmp, ftmp, z1);
+ felem_reduce(ftmp, tmp);
+
+ /* s2 = tmp = y2 * z1**3 */
+ felem_mul(tmp, y2, ftmp);
+ /* tmp[i] < 17*2^120 */
+
+ /* r = ftmp5 = (s2 - s1)*2 */
+ felem_diff_128_64(tmp, ftmp6);
+ /* tmp[i] < 17*2^120 + 2^63 */
+ felem_reduce(ftmp5, tmp);
+ y_equal = felem_is_zero(ftmp5);
+ felem_scalar64(ftmp5, 2);
+ /* ftmp5[i] < 2^61 */
+
+ if (x_equal && y_equal && !z1_is_zero && !z2_is_zero)
+ {
+ point_double(x3, y3, z3, x1, y1, z1);
+ return;
+ }
+
+ /* I = ftmp = (2h)**2 */
+ felem_assign(ftmp, ftmp4);
+ felem_scalar64(ftmp, 2);
+ /* ftmp[i] < 2^61 */
+ felem_square(tmp, ftmp);
+ /* tmp[i] < 17*2^122 */
+ felem_reduce(ftmp, tmp);
+
+ /* J = ftmp2 = h * I */
+ felem_mul(tmp, ftmp4, ftmp);
+ felem_reduce(ftmp2, tmp);
+
+ /* V = ftmp4 = U1 * I */
+ felem_mul(tmp, ftmp3, ftmp);
+ felem_reduce(ftmp4, tmp);
+
+ /* x_out = r**2 - J - 2V */
+ felem_square(tmp, ftmp5);
+ /* tmp[i] < 17*2^122 */
+ felem_diff_128_64(tmp, ftmp2);
+ /* tmp[i] < 17*2^122 + 2^63 */
+ felem_assign(ftmp3, ftmp4);
+ felem_scalar64(ftmp4, 2);
+ /* ftmp4[i] < 2^61 */
+ felem_diff_128_64(tmp, ftmp4);
+ /* tmp[i] < 17*2^122 + 2^64 */
+ felem_reduce(x_out, tmp);
+
+ /* y_out = r(V-x_out) - 2 * s1 * J */
+ felem_diff64(ftmp3, x_out);
+ /* ftmp3[i] < 2^60 + 2^60
+ * = 2^61 */
+ felem_mul(tmp, ftmp5, ftmp3);
+ /* tmp[i] < 17*2^122 */
+ felem_mul(tmp2, ftmp6, ftmp2);
+ /* tmp2[i] < 17*2^120 */
+ felem_scalar128(tmp2, 2);
+ /* tmp2[i] < 17*2^121 */
+ felem_diff128(tmp, tmp2);
+ /* tmp[i] < 2^127 - 2^69 + 17*2^122
+ * = 2^126 - 2^122 - 2^6 - 2^2 - 1
+ * < 2^127 */
+ felem_reduce(y_out, tmp);
+
+ copy_conditional(x_out, x2, z1_is_zero);
+ copy_conditional(x_out, x1, z2_is_zero);
+ copy_conditional(y_out, y2, z1_is_zero);
+ copy_conditional(y_out, y1, z2_is_zero);
+ copy_conditional(z_out, z2, z1_is_zero);
+ copy_conditional(z_out, z1, z2_is_zero);
+ felem_assign(x3, x_out);
+ felem_assign(y3, y_out);
+ felem_assign(z3, z_out);
+ }
+
+/* Base point pre computation
+ * --------------------------
+ *
+ * Two different sorts of precomputed tables are used in the following code.
+ * Each contain various points on the curve, where each point is three field
+ * elements (x, y, z).
+ *
+ * For the base point table, z is usually 1 (0 for the point at infinity).
+ * This table has 16 elements:
+ * index | bits | point
+ * ------+---------+------------------------------
+ * 0 | 0 0 0 0 | 0G
+ * 1 | 0 0 0 1 | 1G
+ * 2 | 0 0 1 0 | 2^130G
+ * 3 | 0 0 1 1 | (2^130 + 1)G
+ * 4 | 0 1 0 0 | 2^260G
+ * 5 | 0 1 0 1 | (2^260 + 1)G
+ * 6 | 0 1 1 0 | (2^260 + 2^130)G
+ * 7 | 0 1 1 1 | (2^260 + 2^130 + 1)G
+ * 8 | 1 0 0 0 | 2^390G
+ * 9 | 1 0 0 1 | (2^390 + 1)G
+ * 10 | 1 0 1 0 | (2^390 + 2^130)G
+ * 11 | 1 0 1 1 | (2^390 + 2^130 + 1)G
+ * 12 | 1 1 0 0 | (2^390 + 2^260)G
+ * 13 | 1 1 0 1 | (2^390 + 2^260 + 1)G
+ * 14 | 1 1 1 0 | (2^390 + 2^260 + 2^130)G
+ * 15 | 1 1 1 1 | (2^390 + 2^260 + 2^130 + 1)G
+ *
+ * The reason for this is so that we can clock bits into four different
+ * locations when doing simple scalar multiplies against the base point.
+ *
+ * Tables for other points have table[i] = iG for i in 0 .. 16. */
+
+/* gmul is the table of precomputed base points */
+static const felem gmul[16][3] =
+ {{{0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x017e7e31c2e5bd66, 0x022cf0615a90a6fe, 0x00127a2ffa8de334,
+ 0x01dfbf9d64a3f877, 0x006b4d3dbaa14b5e, 0x014fed487e0a2bd8,
+ 0x015b4429c6481390, 0x03a73678fb2d988e, 0x00c6858e06b70404},
+ {0x00be94769fd16650, 0x031c21a89cb09022, 0x039013fad0761353,
+ 0x02657bd099031542, 0x03273e662c97ee72, 0x01e6d11a05ebef45,
+ 0x03d1bd998f544495, 0x03001172297ed0b1, 0x011839296a789a3b},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x0373faacbc875bae, 0x00f325023721c671, 0x00f666fd3dbde5ad,
+ 0x01a6932363f88ea7, 0x01fc6d9e13f9c47b, 0x03bcbffc2bbf734e,
+ 0x013ee3c3647f3a92, 0x029409fefe75d07d, 0x00ef9199963d85e5},
+ {0x011173743ad5b178, 0x02499c7c21bf7d46, 0x035beaeabb8b1a58,
+ 0x00f989c4752ea0a3, 0x0101e1de48a9c1a3, 0x01a20076be28ba6c,
+ 0x02f8052e5eb2de95, 0x01bfe8f82dea117c, 0x0160074d3c36ddb7},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x012f3fc373393b3b, 0x03d3d6172f1419fa, 0x02adc943c0b86873,
+ 0x00d475584177952b, 0x012a4d1673750ee2, 0x00512517a0f13b0c,
+ 0x02b184671a7b1734, 0x0315b84236f1a50a, 0x00a4afc472edbdb9},
+ {0x00152a7077f385c4, 0x03044007d8d1c2ee, 0x0065829d61d52b52,
+ 0x00494ff6b6631d0d, 0x00a11d94d5f06bcf, 0x02d2f89474d9282e,
+ 0x0241c5727c06eeb9, 0x0386928710fbdb9d, 0x01f883f727b0dfbe},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x019b0c3c9185544d, 0x006243a37c9d97db, 0x02ee3cbe030a2ad2,
+ 0x00cfdd946bb51e0d, 0x0271c00932606b91, 0x03f817d1ec68c561,
+ 0x03f37009806a369c, 0x03c1f30baf184fd5, 0x01091022d6d2f065},
+ {0x0292c583514c45ed, 0x0316fca51f9a286c, 0x00300af507c1489a,
+ 0x0295f69008298cf1, 0x02c0ed8274943d7b, 0x016509b9b47a431e,
+ 0x02bc9de9634868ce, 0x005b34929bffcb09, 0x000c1a0121681524},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x0286abc0292fb9f2, 0x02665eee9805b3f7, 0x01ed7455f17f26d6,
+ 0x0346355b83175d13, 0x006284944cd0a097, 0x0191895bcdec5e51,
+ 0x02e288370afda7d9, 0x03b22312bfefa67a, 0x01d104d3fc0613fe},
+ {0x0092421a12f7e47f, 0x0077a83fa373c501, 0x03bd25c5f696bd0d,
+ 0x035c41e4d5459761, 0x01ca0d1742b24f53, 0x00aaab27863a509c,
+ 0x018b6de47df73917, 0x025c0b771705cd01, 0x01fd51d566d760a7},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x01dd92ff6b0d1dbd, 0x039c5e2e8f8afa69, 0x0261ed13242c3b27,
+ 0x0382c6e67026e6a0, 0x01d60b10be2089f9, 0x03c15f3dce86723f,
+ 0x03c764a32d2a062d, 0x017307eac0fad056, 0x018207c0b96c5256},
+ {0x0196a16d60e13154, 0x03e6ce74c0267030, 0x00ddbf2b4e52a5aa,
+ 0x012738241bbf31c8, 0x00ebe8dc04685a28, 0x024c2ad6d380d4a2,
+ 0x035ee062a6e62d0e, 0x0029ed74af7d3a0f, 0x00eef32aec142ebd},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x00c31ec398993b39, 0x03a9f45bcda68253, 0x00ac733c24c70890,
+ 0x00872b111401ff01, 0x01d178c23195eafb, 0x03bca2c816b87f74,
+ 0x0261a9af46fbad7a, 0x0324b2a8dd3d28f9, 0x00918121d8f24e23},
+ {0x032bc8c1ca983cd7, 0x00d869dfb08fc8c6, 0x01693cb61fce1516,
+ 0x012a5ea68f4e88a8, 0x010869cab88d7ae3, 0x009081ad277ceee1,
+ 0x033a77166d064cdc, 0x03955235a1fb3a95, 0x01251a4a9b25b65e},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x00148a3a1b27f40b, 0x0123186df1b31fdc, 0x00026e7beaad34ce,
+ 0x01db446ac1d3dbba, 0x0299c1a33437eaec, 0x024540610183cbb7,
+ 0x0173bb0e9ce92e46, 0x02b937e43921214b, 0x01ab0436a9bf01b5},
+ {0x0383381640d46948, 0x008dacbf0e7f330f, 0x03602122bcc3f318,
+ 0x01ee596b200620d6, 0x03bd0585fda430b3, 0x014aed77fd123a83,
+ 0x005ace749e52f742, 0x0390fe041da2b842, 0x0189a8ceb3299242},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x012a19d6b3282473, 0x00c0915918b423ce, 0x023a954eb94405ae,
+ 0x00529f692be26158, 0x0289fa1b6fa4b2aa, 0x0198ae4ceea346ef,
+ 0x0047d8cdfbdedd49, 0x00cc8c8953f0f6b8, 0x001424abbff49203},
+ {0x0256732a1115a03a, 0x0351bc38665c6733, 0x03f7b950fb4a6447,
+ 0x000afffa94c22155, 0x025763d0a4dab540, 0x000511e92d4fc283,
+ 0x030a7e9eda0ee96c, 0x004c3cd93a28bf0a, 0x017edb3a8719217f},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x011de5675a88e673, 0x031d7d0f5e567fbe, 0x0016b2062c970ae5,
+ 0x03f4a2be49d90aa7, 0x03cef0bd13822866, 0x03f0923dcf774a6c,
+ 0x0284bebc4f322f72, 0x016ab2645302bb2c, 0x01793f95dace0e2a},
+ {0x010646e13527a28f, 0x01ca1babd59dc5e7, 0x01afedfd9a5595df,
+ 0x01f15785212ea6b1, 0x0324e5d64f6ae3f4, 0x02d680f526d00645,
+ 0x0127920fadf627a7, 0x03b383f75df4f684, 0x0089e0057e783b0a},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x00f334b9eb3c26c6, 0x0298fdaa98568dce, 0x01c2d24843a82292,
+ 0x020bcb24fa1b0711, 0x02cbdb3d2b1875e6, 0x0014907598f89422,
+ 0x03abe3aa43b26664, 0x02cbf47f720bc168, 0x0133b5e73014b79b},
+ {0x034aab5dab05779d, 0x00cdc5d71fee9abb, 0x0399f16bd4bd9d30,
+ 0x03582fa592d82647, 0x02be1cdfb775b0e9, 0x0034f7cea32e94cb,
+ 0x0335a7f08f56f286, 0x03b707e9565d1c8b, 0x0015c946ea5b614f},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x024676f6cff72255, 0x00d14625cac96378, 0x00532b6008bc3767,
+ 0x01fc16721b985322, 0x023355ea1b091668, 0x029de7afdc0317c3,
+ 0x02fc8a7ca2da037c, 0x02de1217d74a6f30, 0x013f7173175b73bf},
+ {0x0344913f441490b5, 0x0200f9e272b61eca, 0x0258a246b1dd55d2,
+ 0x03753db9ea496f36, 0x025e02937a09c5ef, 0x030cbd3d14012692,
+ 0x01793a67e70dc72a, 0x03ec1d37048a662e, 0x006550f700c32a8d},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x00d3f48a347eba27, 0x008e636649b61bd8, 0x00d3b93716778fb3,
+ 0x004d1915757bd209, 0x019d5311a3da44e0, 0x016d1afcbbe6aade,
+ 0x0241bf5f73265616, 0x0384672e5d50d39b, 0x005009fee522b684},
+ {0x029b4fab064435fe, 0x018868ee095bbb07, 0x01ea3d6936cc92b8,
+ 0x000608b00f78a2f3, 0x02db911073d1c20f, 0x018205938470100a,
+ 0x01f1e4964cbe6ff2, 0x021a19a29eed4663, 0x01414485f42afa81},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x01612b3a17f63e34, 0x03813992885428e6, 0x022b3c215b5a9608,
+ 0x029b4057e19f2fcb, 0x0384059a587af7e6, 0x02d6400ace6fe610,
+ 0x029354d896e8e331, 0x00c047ee6dfba65e, 0x0037720542e9d49d},
+ {0x02ce9eed7c5e9278, 0x0374ed703e79643b, 0x01316c54c4072006,
+ 0x005aaa09054b2ee8, 0x002824000c840d57, 0x03d4eba24771ed86,
+ 0x0189c50aabc3bdae, 0x0338c01541e15510, 0x00466d56e38eed42},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0x007efd8330ad8bd6, 0x02465ed48047710b, 0x0034c6606b215e0c,
+ 0x016ae30c53cbf839, 0x01fa17bd37161216, 0x018ead4e61ce8ab9,
+ 0x005482ed5f5dee46, 0x037543755bba1d7f, 0x005e5ac7e70a9d0f},
+ {0x0117e1bb2fdcb2a2, 0x03deea36249f40c4, 0x028d09b4a6246cb7,
+ 0x03524b8855bcf756, 0x023d7d109d5ceb58, 0x0178e43e3223ef9c,
+ 0x0154536a0c6e966a, 0x037964d1286ee9fe, 0x0199bcd90e125055},
+ {1, 0, 0, 0, 0, 0, 0, 0, 0}}};
+
+/* select_point selects the |idx|th point from a precomputation table and
+ * copies it to out. */
+static void select_point(const limb idx, unsigned int size, const felem pre_comp[/* size */][3],
+ felem out[3])
+ {
+ unsigned i, j;
+ limb *outlimbs = &out[0][0];
+ memset(outlimbs, 0, 3 * sizeof(felem));
+
+ for (i = 0; i < size; i++)
+ {
+ const limb *inlimbs = &pre_comp[i][0][0];
+ limb mask = i ^ idx;
+ mask |= mask >> 4;
+ mask |= mask >> 2;
+ mask |= mask >> 1;
+ mask &= 1;
+ mask--;
+ for (j = 0; j < NLIMBS * 3; j++)
+ outlimbs[j] |= inlimbs[j] & mask;
+ }
+ }
+
+/* get_bit returns the |i|th bit in |in| */
+static char get_bit(const felem_bytearray in, int i)
+ {
+ if (i < 0)
+ return 0;
+ return (in[i >> 3] >> (i & 7)) & 1;
+ }
+
+/* Interleaved point multiplication using precomputed point multiples:
+ * The small point multiples 0*P, 1*P, ..., 16*P are in pre_comp[],
+ * the scalars in scalars[]. If g_scalar is non-NULL, we also add this multiple
+ * of the generator, using certain (large) precomputed multiples in g_pre_comp.
+ * Output point (X, Y, Z) is stored in x_out, y_out, z_out */
+static void batch_mul(felem x_out, felem y_out, felem z_out,
+ const felem_bytearray scalars[], const unsigned num_points, const u8 *g_scalar,
+ const int mixed, const felem pre_comp[][17][3], const felem g_pre_comp[16][3])
+ {
+ int i, skip;
+ unsigned num, gen_mul = (g_scalar != NULL);
+ felem nq[3], tmp[4];
+ limb bits;
+ u8 sign, digit;
+
+ /* set nq to the point at infinity */
+ memset(nq, 0, 3 * sizeof(felem));
+
+ /* Loop over all scalars msb-to-lsb, interleaving additions
+ * of multiples of the generator (last quarter of rounds)
+ * and additions of other points multiples (every 5th round).
+ */
+ skip = 1; /* save two point operations in the first round */
+ for (i = (num_points ? 520 : 130); i >= 0; --i)
+ {
+ /* double */
+ if (!skip)
+ point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]);
+
+ /* add multiples of the generator */
+ if (gen_mul && (i <= 130))
+ {
+ bits = get_bit(g_scalar, i + 390) << 3;
+ if (i < 130)
+ {
+ bits |= get_bit(g_scalar, i + 260) << 2;
+ bits |= get_bit(g_scalar, i + 130) << 1;
+ bits |= get_bit(g_scalar, i);
+ }
+ /* select the point to add, in constant time */
+ select_point(bits, 16, g_pre_comp, tmp);
+ if (!skip)
+ {
+ point_add(nq[0], nq[1], nq[2],
+ nq[0], nq[1], nq[2],
+ 1 /* mixed */, tmp[0], tmp[1], tmp[2]);
+ }
+ else
+ {
+ memcpy(nq, tmp, 3 * sizeof(felem));
+ skip = 0;
+ }
+ }
+
+ /* do other additions every 5 doublings */
+ if (num_points && (i % 5 == 0))
+ {
+ /* loop over all scalars */
+ for (num = 0; num < num_points; ++num)
+ {
+ bits = get_bit(scalars[num], i + 4) << 5;
+ bits |= get_bit(scalars[num], i + 3) << 4;
+ bits |= get_bit(scalars[num], i + 2) << 3;
+ bits |= get_bit(scalars[num], i + 1) << 2;
+ bits |= get_bit(scalars[num], i) << 1;
+ bits |= get_bit(scalars[num], i - 1);
+ ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits);
+
+ /* select the point to add or subtract, in constant time */
+ select_point(digit, 17, pre_comp[num], tmp);
+ felem_neg(tmp[3], tmp[1]); /* (X, -Y, Z) is the negative point */
+ copy_conditional(tmp[1], tmp[3], (-(limb) sign));
+
+ if (!skip)
+ {
+ point_add(nq[0], nq[1], nq[2],
+ nq[0], nq[1], nq[2],
+ mixed, tmp[0], tmp[1], tmp[2]);
+ }
+ else
+ {
+ memcpy(nq, tmp, 3 * sizeof(felem));
+ skip = 0;
+ }
+ }
+ }
+ }
+ felem_assign(x_out, nq[0]);
+ felem_assign(y_out, nq[1]);
+ felem_assign(z_out, nq[2]);
+ }
+
+
+/* Precomputation for the group generator. */
+typedef struct {
+ felem g_pre_comp[16][3];
+ int references;
+} NISTP521_PRE_COMP;
+
+const EC_METHOD *EC_GFp_nistp521_method(void)
+ {
+ static const EC_METHOD ret = {
+ EC_FLAGS_DEFAULT_OCT,
+ NID_X9_62_prime_field,
+ ec_GFp_nistp521_group_init,
+ ec_GFp_simple_group_finish,
+ ec_GFp_simple_group_clear_finish,
+ ec_GFp_nist_group_copy,
+ ec_GFp_nistp521_group_set_curve,
+ ec_GFp_simple_group_get_curve,
+ ec_GFp_simple_group_get_degree,
+ ec_GFp_simple_group_check_discriminant,
+ ec_GFp_simple_point_init,
+ ec_GFp_simple_point_finish,
+ ec_GFp_simple_point_clear_finish,
+ ec_GFp_simple_point_copy,
+ ec_GFp_simple_point_set_to_infinity,
+ ec_GFp_simple_set_Jprojective_coordinates_GFp,
+ ec_GFp_simple_get_Jprojective_coordinates_GFp,
+ ec_GFp_simple_point_set_affine_coordinates,
+ ec_GFp_nistp521_point_get_affine_coordinates,
+ 0 /* point_set_compressed_coordinates */,
+ 0 /* point2oct */,
+ 0 /* oct2point */,
+ ec_GFp_simple_add,
+ ec_GFp_simple_dbl,
+ ec_GFp_simple_invert,
+ ec_GFp_simple_is_at_infinity,
+ ec_GFp_simple_is_on_curve,
+ ec_GFp_simple_cmp,
+ ec_GFp_simple_make_affine,
+ ec_GFp_simple_points_make_affine,
+ ec_GFp_nistp521_points_mul,
+ ec_GFp_nistp521_precompute_mult,
+ ec_GFp_nistp521_have_precompute_mult,
+ ec_GFp_nist_field_mul,
+ ec_GFp_nist_field_sqr,
+ 0 /* field_div */,
+ 0 /* field_encode */,
+ 0 /* field_decode */,
+ 0 /* field_set_to_one */ };
+
+ return &ret;
+ }
+
+
+/******************************************************************************/
+/* FUNCTIONS TO MANAGE PRECOMPUTATION
+ */
+
+static NISTP521_PRE_COMP *nistp521_pre_comp_new()
+ {
+ NISTP521_PRE_COMP *ret = NULL;
+ ret = (NISTP521_PRE_COMP *)OPENSSL_malloc(sizeof(NISTP521_PRE_COMP));
+ if (!ret)
+ {
+ ECerr(EC_F_NISTP521_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE);
+ return ret;
+ }
+ memset(ret->g_pre_comp, 0, sizeof(ret->g_pre_comp));
+ ret->references = 1;
+ return ret;
+ }
+
+static void *nistp521_pre_comp_dup(void *src_)
+ {
+ NISTP521_PRE_COMP *src = src_;
+
+ /* no need to actually copy, these objects never change! */
+ CRYPTO_add(&src->references, 1, CRYPTO_LOCK_EC_PRE_COMP);
+
+ return src_;
+ }
+
+static void nistp521_pre_comp_free(void *pre_)
+ {
+ int i;
+ NISTP521_PRE_COMP *pre = pre_;
+
+ if (!pre)
+ return;
+
+ i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
+ if (i > 0)
+ return;
+
+ OPENSSL_free(pre);
+ }
+
+static void nistp521_pre_comp_clear_free(void *pre_)
+ {
+ int i;
+ NISTP521_PRE_COMP *pre = pre_;
+
+ if (!pre)
+ return;
+
+ i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
+ if (i > 0)
+ return;
+
+ OPENSSL_cleanse(pre, sizeof(*pre));
+ OPENSSL_free(pre);
+ }
+
+/******************************************************************************/
+/* OPENSSL EC_METHOD FUNCTIONS
+ */
+
+int ec_GFp_nistp521_group_init(EC_GROUP *group)
+ {
+ int ret;
+ ret = ec_GFp_simple_group_init(group);
+ group->a_is_minus3 = 1;
+ return ret;
+ }
+
+int ec_GFp_nistp521_group_set_curve(EC_GROUP *group, const BIGNUM *p,
+ const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
+ {
+ int ret = 0;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *curve_p, *curve_a, *curve_b;
+
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((curve_p = BN_CTX_get(ctx)) == NULL) ||
+ ((curve_a = BN_CTX_get(ctx)) == NULL) ||
+ ((curve_b = BN_CTX_get(ctx)) == NULL)) goto err;
+ BN_bin2bn(nistp521_curve_params[0], sizeof(felem_bytearray), curve_p);
+ BN_bin2bn(nistp521_curve_params[1], sizeof(felem_bytearray), curve_a);
+ BN_bin2bn(nistp521_curve_params[2], sizeof(felem_bytearray), curve_b);
+ if ((BN_cmp(curve_p, p)) || (BN_cmp(curve_a, a)) ||
+ (BN_cmp(curve_b, b)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_GROUP_SET_CURVE,
+ EC_R_WRONG_CURVE_PARAMETERS);
+ goto err;
+ }
+ group->field_mod_func = BN_nist_mod_521;
+ ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+ }
+
+/* Takes the Jacobian coordinates (X, Y, Z) of a point and returns
+ * (X', Y') = (X/Z^2, Y/Z^3) */
+int ec_GFp_nistp521_point_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
+ {
+ felem z1, z2, x_in, y_in, x_out, y_out;
+ largefelem tmp;
+
+ if (EC_POINT_is_at_infinity(group, point))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES,
+ EC_R_POINT_AT_INFINITY);
+ return 0;
+ }
+ if ((!BN_to_felem(x_in, &point->X)) || (!BN_to_felem(y_in, &point->Y)) ||
+ (!BN_to_felem(z1, &point->Z))) return 0;
+ felem_inv(z2, z1);
+ felem_square(tmp, z2); felem_reduce(z1, tmp);
+ felem_mul(tmp, x_in, z1); felem_reduce(x_in, tmp);
+ felem_contract(x_out, x_in);
+ if (x != NULL)
+ {
+ if (!felem_to_BN(x, x_out))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES, ERR_R_BN_LIB);
+ return 0;
+ }
+ }
+ felem_mul(tmp, z1, z2); felem_reduce(z1, tmp);
+ felem_mul(tmp, y_in, z1); felem_reduce(y_in, tmp);
+ felem_contract(y_out, y_in);
+ if (y != NULL)
+ {
+ if (!felem_to_BN(y, y_out))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_POINT_GET_AFFINE_COORDINATES, ERR_R_BN_LIB);
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+static void make_points_affine(size_t num, felem points[/* num */][3], felem tmp_felems[/* num+1 */])
+ {
+ /* Runs in constant time, unless an input is the point at infinity
+ * (which normally shouldn't happen). */
+ ec_GFp_nistp_points_make_affine_internal(
+ num,
+ points,
+ sizeof(felem),
+ tmp_felems,
+ (void (*)(void *)) felem_one,
+ (int (*)(const void *)) felem_is_zero_int,
+ (void (*)(void *, const void *)) felem_assign,
+ (void (*)(void *, const void *)) felem_square_reduce,
+ (void (*)(void *, const void *, const void *)) felem_mul_reduce,
+ (void (*)(void *, const void *)) felem_inv,
+ (void (*)(void *, const void *)) felem_contract);
+ }
+
+/* Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL values
+ * Result is stored in r (r can equal one of the inputs). */
+int ec_GFp_nistp521_points_mul(const EC_GROUP *group, EC_POINT *r,
+ const BIGNUM *scalar, size_t num, const EC_POINT *points[],
+ const BIGNUM *scalars[], BN_CTX *ctx)
+ {
+ int ret = 0;
+ int j;
+ int mixed = 0;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y, *z, *tmp_scalar;
+ felem_bytearray g_secret;
+ felem_bytearray *secrets = NULL;
+ felem (*pre_comp)[17][3] = NULL;
+ felem *tmp_felems = NULL;
+ felem_bytearray tmp;
+ unsigned i, num_bytes;
+ int have_pre_comp = 0;
+ size_t num_points = num;
+ felem x_in, y_in, z_in, x_out, y_out, z_out;
+ NISTP521_PRE_COMP *pre = NULL;
+ felem (*g_pre_comp)[3] = NULL;
+ EC_POINT *generator = NULL;
+ const EC_POINT *p = NULL;
+ const BIGNUM *p_scalar = NULL;
+
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((x = BN_CTX_get(ctx)) == NULL) ||
+ ((y = BN_CTX_get(ctx)) == NULL) ||
+ ((z = BN_CTX_get(ctx)) == NULL) ||
+ ((tmp_scalar = BN_CTX_get(ctx)) == NULL))
+ goto err;
+
+ if (scalar != NULL)
+ {
+ pre = EC_EX_DATA_get_data(group->extra_data,
+ nistp521_pre_comp_dup, nistp521_pre_comp_free,
+ nistp521_pre_comp_clear_free);
+ if (pre)
+ /* we have precomputation, try to use it */
+ g_pre_comp = &pre->g_pre_comp[0];
+ else
+ /* try to use the standard precomputation */
+ g_pre_comp = (felem (*)[3]) gmul;
+ generator = EC_POINT_new(group);
+ if (generator == NULL)
+ goto err;
+ /* get the generator from precomputation */
+ if (!felem_to_BN(x, g_pre_comp[1][0]) ||
+ !felem_to_BN(y, g_pre_comp[1][1]) ||
+ !felem_to_BN(z, g_pre_comp[1][2]))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ if (!EC_POINT_set_Jprojective_coordinates_GFp(group,
+ generator, x, y, z, ctx))
+ goto err;
+ if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
+ /* precomputation matches generator */
+ have_pre_comp = 1;
+ else
+ /* we don't have valid precomputation:
+ * treat the generator as a random point */
+ num_points++;
+ }
+
+ if (num_points > 0)
+ {
+ if (num_points >= 2)
+ {
+ /* unless we precompute multiples for just one point,
+ * converting those into affine form is time well spent */
+ mixed = 1;
+ }
+ secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray));
+ pre_comp = OPENSSL_malloc(num_points * 17 * 3 * sizeof(felem));
+ if (mixed)
+ tmp_felems = OPENSSL_malloc((num_points * 17 + 1) * sizeof(felem));
+ if ((secrets == NULL) || (pre_comp == NULL) || (mixed && (tmp_felems == NULL)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* we treat NULL scalars as 0, and NULL points as points at infinity,
+ * i.e., they contribute nothing to the linear combination */
+ memset(secrets, 0, num_points * sizeof(felem_bytearray));
+ memset(pre_comp, 0, num_points * 17 * 3 * sizeof(felem));
+ for (i = 0; i < num_points; ++i)
+ {
+ if (i == num)
+ /* we didn't have a valid precomputation, so we pick
+ * the generator */
+ {
+ p = EC_GROUP_get0_generator(group);
+ p_scalar = scalar;
+ }
+ else
+ /* the i^th point */
+ {
+ p = points[i];
+ p_scalar = scalars[i];
+ }
+ if ((p_scalar != NULL) && (p != NULL))
+ {
+ /* reduce scalar to 0 <= scalar < 2^521 */
+ if ((BN_num_bits(p_scalar) > 521) || (BN_is_negative(p_scalar)))
+ {
+ /* this is an unusual input, and we don't guarantee
+ * constant-timeness */
+ if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ num_bytes = BN_bn2bin(tmp_scalar, tmp);
+ }
+ else
+ num_bytes = BN_bn2bin(p_scalar, tmp);
+ flip_endian(secrets[i], tmp, num_bytes);
+ /* precompute multiples */
+ if ((!BN_to_felem(x_out, &p->X)) ||
+ (!BN_to_felem(y_out, &p->Y)) ||
+ (!BN_to_felem(z_out, &p->Z))) goto err;
+ memcpy(pre_comp[i][1][0], x_out, sizeof(felem));
+ memcpy(pre_comp[i][1][1], y_out, sizeof(felem));
+ memcpy(pre_comp[i][1][2], z_out, sizeof(felem));
+ for (j = 2; j <= 16; ++j)
+ {
+ if (j & 1)
+ {
+ point_add(
+ pre_comp[i][j][0], pre_comp[i][j][1], pre_comp[i][j][2],
+ pre_comp[i][1][0], pre_comp[i][1][1], pre_comp[i][1][2],
+ 0, pre_comp[i][j-1][0], pre_comp[i][j-1][1], pre_comp[i][j-1][2]);
+ }
+ else
+ {
+ point_double(
+ pre_comp[i][j][0], pre_comp[i][j][1], pre_comp[i][j][2],
+ pre_comp[i][j/2][0], pre_comp[i][j/2][1], pre_comp[i][j/2][2]);
+ }
+ }
+ }
+ }
+ if (mixed)
+ make_points_affine(num_points * 17, pre_comp[0], tmp_felems);
+ }
+
+ /* the scalar for the generator */
+ if ((scalar != NULL) && (have_pre_comp))
+ {
+ memset(g_secret, 0, sizeof(g_secret));
+ /* reduce scalar to 0 <= scalar < 2^521 */
+ if ((BN_num_bits(scalar) > 521) || (BN_is_negative(scalar)))
+ {
+ /* this is an unusual input, and we don't guarantee
+ * constant-timeness */
+ if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ num_bytes = BN_bn2bin(tmp_scalar, tmp);
+ }
+ else
+ num_bytes = BN_bn2bin(scalar, tmp);
+ flip_endian(g_secret, tmp, num_bytes);
+ /* do the multiplication with generator precomputation*/
+ batch_mul(x_out, y_out, z_out,
+ (const felem_bytearray (*)) secrets, num_points,
+ g_secret,
+ mixed, (const felem (*)[17][3]) pre_comp,
+ (const felem (*)[3]) g_pre_comp);
+ }
+ else
+ /* do the multiplication without generator precomputation */
+ batch_mul(x_out, y_out, z_out,
+ (const felem_bytearray (*)) secrets, num_points,
+ NULL, mixed, (const felem (*)[17][3]) pre_comp, NULL);
+ /* reduce the output to its unique minimal representation */
+ felem_contract(x_in, x_out);
+ felem_contract(y_in, y_out);
+ felem_contract(z_in, z_out);
+ if ((!felem_to_BN(x, x_in)) || (!felem_to_BN(y, y_in)) ||
+ (!felem_to_BN(z, z_in)))
+ {
+ ECerr(EC_F_EC_GFP_NISTP521_POINTS_MUL, ERR_R_BN_LIB);
+ goto err;
+ }
+ ret = EC_POINT_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx);
+
+err:
+ BN_CTX_end(ctx);
+ if (generator != NULL)
+ EC_POINT_free(generator);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (secrets != NULL)
+ OPENSSL_free(secrets);
+ if (pre_comp != NULL)
+ OPENSSL_free(pre_comp);
+ if (tmp_felems != NULL)
+ OPENSSL_free(tmp_felems);
+ return ret;
+ }
+
+int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx)
+ {
+ int ret = 0;
+ NISTP521_PRE_COMP *pre = NULL;
+ int i, j;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y;
+ EC_POINT *generator = NULL;
+ felem tmp_felems[16];
+
+ /* throw away old precomputation */
+ EC_EX_DATA_free_data(&group->extra_data, nistp521_pre_comp_dup,
+ nistp521_pre_comp_free, nistp521_pre_comp_clear_free);
+ if (ctx == NULL)
+ if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0;
+ BN_CTX_start(ctx);
+ if (((x = BN_CTX_get(ctx)) == NULL) ||
+ ((y = BN_CTX_get(ctx)) == NULL))
+ goto err;
+ /* get the generator */
+ if (group->generator == NULL) goto err;
+ generator = EC_POINT_new(group);
+ if (generator == NULL)
+ goto err;
+ BN_bin2bn(nistp521_curve_params[3], sizeof (felem_bytearray), x);
+ BN_bin2bn(nistp521_curve_params[4], sizeof (felem_bytearray), y);
+ if (!EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, ctx))
+ goto err;
+ if ((pre = nistp521_pre_comp_new()) == NULL)
+ goto err;
+ /* if the generator is the standard one, use built-in precomputation */
+ if (0 == EC_POINT_cmp(group, generator, group->generator, ctx))
+ {
+ memcpy(pre->g_pre_comp, gmul, sizeof(pre->g_pre_comp));
+ ret = 1;
+ goto err;
+ }
+ if ((!BN_to_felem(pre->g_pre_comp[1][0], &group->generator->X)) ||
+ (!BN_to_felem(pre->g_pre_comp[1][1], &group->generator->Y)) ||
+ (!BN_to_felem(pre->g_pre_comp[1][2], &group->generator->Z)))
+ goto err;
+ /* compute 2^130*G, 2^260*G, 2^390*G */
+ for (i = 1; i <= 4; i <<= 1)
+ {
+ point_double(pre->g_pre_comp[2*i][0], pre->g_pre_comp[2*i][1],
+ pre->g_pre_comp[2*i][2], pre->g_pre_comp[i][0],
+ pre->g_pre_comp[i][1], pre->g_pre_comp[i][2]);
+ for (j = 0; j < 129; ++j)
+ {
+ point_double(pre->g_pre_comp[2*i][0],
+ pre->g_pre_comp[2*i][1],
+ pre->g_pre_comp[2*i][2],
+ pre->g_pre_comp[2*i][0],
+ pre->g_pre_comp[2*i][1],
+ pre->g_pre_comp[2*i][2]);
+ }
+ }
+ /* g_pre_comp[0] is the point at infinity */
+ memset(pre->g_pre_comp[0], 0, sizeof(pre->g_pre_comp[0]));
+ /* the remaining multiples */
+ /* 2^130*G + 2^260*G */
+ point_add(pre->g_pre_comp[6][0], pre->g_pre_comp[6][1],
+ pre->g_pre_comp[6][2], pre->g_pre_comp[4][0],
+ pre->g_pre_comp[4][1], pre->g_pre_comp[4][2],
+ 0, pre->g_pre_comp[2][0], pre->g_pre_comp[2][1],
+ pre->g_pre_comp[2][2]);
+ /* 2^130*G + 2^390*G */
+ point_add(pre->g_pre_comp[10][0], pre->g_pre_comp[10][1],
+ pre->g_pre_comp[10][2], pre->g_pre_comp[8][0],
+ pre->g_pre_comp[8][1], pre->g_pre_comp[8][2],
+ 0, pre->g_pre_comp[2][0], pre->g_pre_comp[2][1],
+ pre->g_pre_comp[2][2]);
+ /* 2^260*G + 2^390*G */
+ point_add(pre->g_pre_comp[12][0], pre->g_pre_comp[12][1],
+ pre->g_pre_comp[12][2], pre->g_pre_comp[8][0],
+ pre->g_pre_comp[8][1], pre->g_pre_comp[8][2],
+ 0, pre->g_pre_comp[4][0], pre->g_pre_comp[4][1],
+ pre->g_pre_comp[4][2]);
+ /* 2^130*G + 2^260*G + 2^390*G */
+ point_add(pre->g_pre_comp[14][0], pre->g_pre_comp[14][1],
+ pre->g_pre_comp[14][2], pre->g_pre_comp[12][0],
+ pre->g_pre_comp[12][1], pre->g_pre_comp[12][2],
+ 0, pre->g_pre_comp[2][0], pre->g_pre_comp[2][1],
+ pre->g_pre_comp[2][2]);
+ for (i = 1; i < 8; ++i)
+ {
+ /* odd multiples: add G */
+ point_add(pre->g_pre_comp[2*i+1][0], pre->g_pre_comp[2*i+1][1],
+ pre->g_pre_comp[2*i+1][2], pre->g_pre_comp[2*i][0],
+ pre->g_pre_comp[2*i][1], pre->g_pre_comp[2*i][2],
+ 0, pre->g_pre_comp[1][0], pre->g_pre_comp[1][1],
+ pre->g_pre_comp[1][2]);
+ }
+ make_points_affine(15, &(pre->g_pre_comp[1]), tmp_felems);
+
+ if (!EC_EX_DATA_set_data(&group->extra_data, pre, nistp521_pre_comp_dup,
+ nistp521_pre_comp_free, nistp521_pre_comp_clear_free))
+ goto err;
+ ret = 1;
+ pre = NULL;
+ err:
+ BN_CTX_end(ctx);
+ if (generator != NULL)
+ EC_POINT_free(generator);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (pre)
+ nistp521_pre_comp_free(pre);
+ return ret;
+ }
+
+int ec_GFp_nistp521_have_precompute_mult(const EC_GROUP *group)
+ {
+ if (EC_EX_DATA_get_data(group->extra_data, nistp521_pre_comp_dup,
+ nistp521_pre_comp_free, nistp521_pre_comp_clear_free)
+ != NULL)
+ return 1;
+ else
+ return 0;
+ }
+
+#else
+static void *dummy=&dummy;
+#endif
diff --git a/crypto/ec/ecp_nistputil.c b/crypto/ec/ecp_nistputil.c
new file mode 100644
index 0000000000000..c8140c807fb07
--- /dev/null
+++ b/crypto/ec/ecp_nistputil.c
@@ -0,0 +1,197 @@
+/* crypto/ec/ecp_nistputil.c */
+/*
+ * Written by Bodo Moeller for the OpenSSL project.
+ */
+/* Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ *
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <openssl/opensslconf.h>
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+
+/*
+ * Common utility functions for ecp_nistp224.c, ecp_nistp256.c, ecp_nistp521.c.
+ */
+
+#include <stddef.h>
+#include "ec_lcl.h"
+
+/* Convert an array of points into affine coordinates.
+ * (If the point at infinity is found (Z = 0), it remains unchanged.)
+ * This function is essentially an equivalent to EC_POINTs_make_affine(), but
+ * works with the internal representation of points as used by ecp_nistp###.c
+ * rather than with (BIGNUM-based) EC_POINT data structures.
+ *
+ * point_array is the input/output buffer ('num' points in projective form,
+ * i.e. three coordinates each), based on an internal representation of
+ * field elements of size 'felem_size'.
+ *
+ * tmp_felems needs to point to a temporary array of 'num'+1 field elements
+ * for storage of intermediate values.
+ */
+void ec_GFp_nistp_points_make_affine_internal(size_t num, void *point_array,
+ size_t felem_size, void *tmp_felems,
+ void (*felem_one)(void *out),
+ int (*felem_is_zero)(const void *in),
+ void (*felem_assign)(void *out, const void *in),
+ void (*felem_square)(void *out, const void *in),
+ void (*felem_mul)(void *out, const void *in1, const void *in2),
+ void (*felem_inv)(void *out, const void *in),
+ void (*felem_contract)(void *out, const void *in))
+ {
+ int i = 0;
+
+#define tmp_felem(I) (&((char *)tmp_felems)[(I) * felem_size])
+#define X(I) (&((char *)point_array)[3*(I) * felem_size])
+#define Y(I) (&((char *)point_array)[(3*(I) + 1) * felem_size])
+#define Z(I) (&((char *)point_array)[(3*(I) + 2) * felem_size])
+
+ if (!felem_is_zero(Z(0)))
+ felem_assign(tmp_felem(0), Z(0));
+ else
+ felem_one(tmp_felem(0));
+ for (i = 1; i < (int)num; i++)
+ {
+ if (!felem_is_zero(Z(i)))
+ felem_mul(tmp_felem(i), tmp_felem(i-1), Z(i));
+ else
+ felem_assign(tmp_felem(i), tmp_felem(i-1));
+ }
+ /* Now each tmp_felem(i) is the product of Z(0) .. Z(i), skipping any zero-valued factors:
+ * if Z(i) = 0, we essentially pretend that Z(i) = 1 */
+
+ felem_inv(tmp_felem(num-1), tmp_felem(num-1));
+ for (i = num - 1; i >= 0; i--)
+ {
+ if (i > 0)
+ /* tmp_felem(i-1) is the product of Z(0) .. Z(i-1),
+ * tmp_felem(i) is the inverse of the product of Z(0) .. Z(i)
+ */
+ felem_mul(tmp_felem(num), tmp_felem(i-1), tmp_felem(i)); /* 1/Z(i) */
+ else
+ felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */
+
+ if (!felem_is_zero(Z(i)))
+ {
+ if (i > 0)
+ /* For next iteration, replace tmp_felem(i-1) by its inverse */
+ felem_mul(tmp_felem(i-1), tmp_felem(i), Z(i));
+
+ /* Convert point (X, Y, Z) into affine form (X/(Z^2), Y/(Z^3), 1) */
+ felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */
+ felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */
+ felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */
+ felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */
+ felem_contract(X(i), X(i));
+ felem_contract(Y(i), Y(i));
+ felem_one(Z(i));
+ }
+ else
+ {
+ if (i > 0)
+ /* For next iteration, replace tmp_felem(i-1) by its inverse */
+ felem_assign(tmp_felem(i-1), tmp_felem(i));
+ }
+ }
+ }
+
+/*
+ * This function looks at 5+1 scalar bits (5 current, 1 adjacent less
+ * significant bit), and recodes them into a signed digit for use in fast point
+ * multiplication: the use of signed rather than unsigned digits means that
+ * fewer points need to be precomputed, given that point inversion is easy
+ * (a precomputed point dP makes -dP available as well).
+ *
+ * BACKGROUND:
+ *
+ * Signed digits for multiplication were introduced by Booth ("A signed binary
+ * multiplication technique", Quart. Journ. Mech. and Applied Math., vol. IV,
+ * pt. 2 (1951), pp. 236-240), in that case for multiplication of integers.
+ * Booth's original encoding did not generally improve the density of nonzero
+ * digits over the binary representation, and was merely meant to simplify the
+ * handling of signed factors given in two's complement; but it has since been
+ * shown to be the basis of various signed-digit representations that do have
+ * further advantages, including the wNAF, using the following general approach:
+ *
+ * (1) Given a binary representation
+ *
+ * b_k ... b_2 b_1 b_0,
+ *
+ * of a nonnegative integer (b_k in {0, 1}), rewrite it in digits 0, 1, -1
+ * by using bit-wise subtraction as follows:
+ *
+ * b_k b_(k-1) ... b_2 b_1 b_0
+ * - b_k ... b_3 b_2 b_1 b_0
+ * -------------------------------------
+ * s_k b_(k-1) ... s_3 s_2 s_1 s_0
+ *
+ * A left-shift followed by subtraction of the original value yields a new
+ * representation of the same value, using signed bits s_i = b_(i+1) - b_i.
+ * This representation from Booth's paper has since appeared in the
+ * literature under a variety of different names including "reversed binary
+ * form", "alternating greedy expansion", "mutual opposite form", and
+ * "sign-alternating {+-1}-representation".
+ *
+ * An interesting property is that among the nonzero bits, values 1 and -1
+ * strictly alternate.
+ *
+ * (2) Various window schemes can be applied to the Booth representation of
+ * integers: for example, right-to-left sliding windows yield the wNAF
+ * (a signed-digit encoding independently discovered by various researchers
+ * in the 1990s), and left-to-right sliding windows yield a left-to-right
+ * equivalent of the wNAF (independently discovered by various researchers
+ * around 2004).
+ *
+ * To prevent leaking information through side channels in point multiplication,
+ * we need to recode the given integer into a regular pattern: sliding windows
+ * as in wNAFs won't do, we need their fixed-window equivalent -- which is a few
+ * decades older: we'll be using the so-called "modified Booth encoding" due to
+ * MacSorley ("High-speed arithmetic in binary computers", Proc. IRE, vol. 49
+ * (1961), pp. 67-91), in a radix-2^5 setting. That is, we always combine five
+ * signed bits into a signed digit:
+ *
+ * s_(4j + 4) s_(4j + 3) s_(4j + 2) s_(4j + 1) s_(4j)
+ *
+ * The sign-alternating property implies that the resulting digit values are
+ * integers from -16 to 16.
+ *
+ * Of course, we don't actually need to compute the signed digits s_i as an
+ * intermediate step (that's just a nice way to see how this scheme relates
+ * to the wNAF): a direct computation obtains the recoded digit from the
+ * six bits b_(4j + 4) ... b_(4j - 1).
+ *
+ * This function takes those five bits as an integer (0 .. 63), writing the
+ * recoded digit to *sign (0 for positive, 1 for negative) and *digit (absolute
+ * value, in the range 0 .. 8). Note that this integer essentially provides the
+ * input bits "shifted to the left" by one position: for example, the input to
+ * compute the least significant recoded digit, given that there's no bit b_-1,
+ * has to be b_4 b_3 b_2 b_1 b_0 0.
+ *
+ */
+void ec_GFp_nistp_recode_scalar_bits(unsigned char *sign, unsigned char *digit, unsigned char in)
+ {
+ unsigned char s, d;
+
+ s = ~((in >> 5) - 1); /* sets all bits to MSB(in), 'in' seen as 6-bit value */
+ d = (1 << 6) - in - 1;
+ d = (d & s) | (in & ~s);
+ d = (d >> 1) + (d & 1);
+
+ *sign = s & 1;
+ *digit = d;
+ }
+#else
+static void *dummy=&dummy;
+#endif
diff --git a/crypto/ec/ecp_oct.c b/crypto/ec/ecp_oct.c
new file mode 100644
index 0000000000000..374a0ee731ae0
--- /dev/null
+++ b/crypto/ec/ecp_oct.c
@@ -0,0 +1,433 @@
+/* crypto/ec/ecp_oct.c */
+/* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
+ * for the OpenSSL project.
+ * Includes code written by Bodo Moeller for the OpenSSL project.
+*/
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * Portions of this software developed by SUN MICROSYSTEMS, INC.,
+ * and contributed to the OpenSSL project.
+ */
+
+#include <openssl/err.h>
+#include <openssl/symhacks.h>
+
+#include "ec_lcl.h"
+
+int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point,
+ const BIGNUM *x_, int y_bit, BN_CTX *ctx)
+ {
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *tmp1, *tmp2, *x, *y;
+ int ret = 0;
+
+ /* clear error queue*/
+ ERR_clear_error();
+
+ if (ctx == NULL)
+ {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ y_bit = (y_bit != 0);
+
+ BN_CTX_start(ctx);
+ tmp1 = BN_CTX_get(ctx);
+ tmp2 = BN_CTX_get(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL) goto err;
+
+ /* Recover y. We have a Weierstrass equation
+ * y^2 = x^3 + a*x + b,
+ * so y is one of the square roots of x^3 + a*x + b.
+ */
+
+ /* tmp1 := x^3 */
+ if (!BN_nnmod(x, x_, &group->field,ctx)) goto err;
+ if (group->meth->field_decode == 0)
+ {
+ /* field_{sqr,mul} work on standard representation */
+ if (!group->meth->field_sqr(group, tmp2, x_, ctx)) goto err;
+ if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) goto err;
+ }
+ else
+ {
+ if (!BN_mod_sqr(tmp2, x_, &group->field, ctx)) goto err;
+ if (!BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) goto err;
+ }
+
+ /* tmp1 := tmp1 + a*x */
+ if (group->a_is_minus3)
+ {
+ if (!BN_mod_lshift1_quick(tmp2, x, &group->field)) goto err;
+ if (!BN_mod_add_quick(tmp2, tmp2, x, &group->field)) goto err;
+ if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
+ }
+ else
+ {
+ if (group->meth->field_decode)
+ {
+ if (!group->meth->field_decode(group, tmp2, &group->a, ctx)) goto err;
+ if (!BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) goto err;
+ }
+ else
+ {
+ /* field_mul works on standard representation */
+ if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) goto err;
+ }
+
+ if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
+ }
+
+ /* tmp1 := tmp1 + b */
+ if (group->meth->field_decode)
+ {
+ if (!group->meth->field_decode(group, tmp2, &group->b, ctx)) goto err;
+ if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
+ }
+ else
+ {
+ if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) goto err;
+ }
+
+ if (!BN_mod_sqrt(y, tmp1, &group->field, ctx))
+ {
+ unsigned long err = ERR_peek_last_error();
+
+ if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE)
+ {
+ ERR_clear_error();
+ ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
+ }
+ else
+ ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (y_bit != BN_is_odd(y))
+ {
+ if (BN_is_zero(y))
+ {
+ int kron;
+
+ kron = BN_kronecker(x, &group->field, ctx);
+ if (kron == -2) goto err;
+
+ if (kron == 1)
+ ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSION_BIT);
+ else
+ /* BN_mod_sqrt() should have cought this error (not a square) */
+ ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
+ goto err;
+ }
+ if (!BN_usub(y, &group->field, y)) goto err;
+ }
+ if (y_bit != BN_is_odd(y))
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
+
+ ret = 1;
+
+ err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+ }
+
+
+size_t ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
+ unsigned char *buf, size_t len, BN_CTX *ctx)
+ {
+ size_t ret;
+ BN_CTX *new_ctx = NULL;
+ int used_ctx = 0;
+ BIGNUM *x, *y;
+ size_t field_len, i, skip;
+
+ if ((form != POINT_CONVERSION_COMPRESSED)
+ && (form != POINT_CONVERSION_UNCOMPRESSED)
+ && (form != POINT_CONVERSION_HYBRID))
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
+ goto err;
+ }
+
+ if (EC_POINT_is_at_infinity(group, point))
+ {
+ /* encodes to a single 0 octet */
+ if (buf != NULL)
+ {
+ if (len < 1)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ buf[0] = 0;
+ }
+ return 1;
+ }
+
+
+ /* ret := required output buffer length */
+ field_len = BN_num_bytes(&group->field);
+ ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
+
+ /* if 'buf' is NULL, just return required length */
+ if (buf != NULL)
+ {
+ if (len < ret)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
+ goto err;
+ }
+
+ if (ctx == NULL)
+ {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ used_ctx = 1;
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL) goto err;
+
+ if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
+
+ if ((form == POINT_CONVERSION_COMPRESSED || form == POINT_CONVERSION_HYBRID) && BN_is_odd(y))
+ buf[0] = form + 1;
+ else
+ buf[0] = form;
+
+ i = 1;
+
+ skip = field_len - BN_num_bytes(x);
+ if (skip > field_len)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ while (skip > 0)
+ {
+ buf[i++] = 0;
+ skip--;
+ }
+ skip = BN_bn2bin(x, buf + i);
+ i += skip;
+ if (i != 1 + field_len)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID)
+ {
+ skip = field_len - BN_num_bytes(y);
+ if (skip > field_len)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ while (skip > 0)
+ {
+ buf[i++] = 0;
+ skip--;
+ }
+ skip = BN_bn2bin(y, buf + i);
+ i += skip;
+ }
+
+ if (i != ret)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (used_ctx)
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+
+ err:
+ if (used_ctx)
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return 0;
+ }
+
+
+int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
+ const unsigned char *buf, size_t len, BN_CTX *ctx)
+ {
+ point_conversion_form_t form;
+ int y_bit;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y;
+ size_t field_len, enc_len;
+ int ret = 0;
+
+ if (len == 0)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ form = buf[0];
+ y_bit = form & 1;
+ form = form & ~1U;
+ if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
+ && (form != POINT_CONVERSION_UNCOMPRESSED)
+ && (form != POINT_CONVERSION_HYBRID))
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+ if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+
+ if (form == 0)
+ {
+ if (len != 1)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+
+ return EC_POINT_set_to_infinity(group, point);
+ }
+
+ field_len = BN_num_bytes(&group->field);
+ enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
+
+ if (len != enc_len)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+
+ if (ctx == NULL)
+ {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL) goto err;
+
+ if (!BN_bin2bn(buf + 1, field_len, x)) goto err;
+ if (BN_ucmp(x, &group->field) >= 0)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+
+ if (form == POINT_CONVERSION_COMPRESSED)
+ {
+ if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) goto err;
+ }
+ else
+ {
+ if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err;
+ if (BN_ucmp(y, &group->field) >= 0)
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+ if (form == POINT_CONVERSION_HYBRID)
+ {
+ if (y_bit != BN_is_odd(y))
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
+ }
+
+ if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */
+ {
+ ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE);
+ goto err;
+ }
+
+ ret = 1;
+
+ err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+ }
+
diff --git a/crypto/ec/ecp_smpl.c b/crypto/ec/ecp_smpl.c
index 66a92e2a9005c..7cbb321f9aae4 100644
--- a/crypto/ec/ecp_smpl.c
+++ b/crypto/ec/ecp_smpl.c
@@ -65,11 +65,19 @@
#include <openssl/err.h>
#include <openssl/symhacks.h>
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
+
#include "ec_lcl.h"
const EC_METHOD *EC_GFp_simple_method(void)
{
+#ifdef OPENSSL_FIPS
+ return fips_ec_gfp_simple_method();
+#else
static const EC_METHOD ret = {
+ EC_FLAGS_DEFAULT_OCT,
NID_X9_62_prime_field,
ec_GFp_simple_group_init,
ec_GFp_simple_group_finish,
@@ -88,9 +96,7 @@ const EC_METHOD *EC_GFp_simple_method(void)
ec_GFp_simple_get_Jprojective_coordinates_GFp,
ec_GFp_simple_point_set_affine_coordinates,
ec_GFp_simple_point_get_affine_coordinates,
- ec_GFp_simple_set_compressed_coordinates,
- ec_GFp_simple_point2oct,
- ec_GFp_simple_oct2point,
+ 0,0,0,
ec_GFp_simple_add,
ec_GFp_simple_dbl,
ec_GFp_simple_invert,
@@ -110,6 +116,7 @@ const EC_METHOD *EC_GFp_simple_method(void)
0 /* field_set_to_one */ };
return &ret;
+#endif
}
@@ -633,372 +640,6 @@ int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_P
return ret;
}
-
-int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point,
- const BIGNUM *x_, int y_bit, BN_CTX *ctx)
- {
- BN_CTX *new_ctx = NULL;
- BIGNUM *tmp1, *tmp2, *x, *y;
- int ret = 0;
-
- /* clear error queue*/
- ERR_clear_error();
-
- if (ctx == NULL)
- {
- ctx = new_ctx = BN_CTX_new();
- if (ctx == NULL)
- return 0;
- }
-
- y_bit = (y_bit != 0);
-
- BN_CTX_start(ctx);
- tmp1 = BN_CTX_get(ctx);
- tmp2 = BN_CTX_get(ctx);
- x = BN_CTX_get(ctx);
- y = BN_CTX_get(ctx);
- if (y == NULL) goto err;
-
- /* Recover y. We have a Weierstrass equation
- * y^2 = x^3 + a*x + b,
- * so y is one of the square roots of x^3 + a*x + b.
- */
-
- /* tmp1 := x^3 */
- if (!BN_nnmod(x, x_, &group->field,ctx)) goto err;
- if (group->meth->field_decode == 0)
- {
- /* field_{sqr,mul} work on standard representation */
- if (!group->meth->field_sqr(group, tmp2, x_, ctx)) goto err;
- if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) goto err;
- }
- else
- {
- if (!BN_mod_sqr(tmp2, x_, &group->field, ctx)) goto err;
- if (!BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) goto err;
- }
-
- /* tmp1 := tmp1 + a*x */
- if (group->a_is_minus3)
- {
- if (!BN_mod_lshift1_quick(tmp2, x, &group->field)) goto err;
- if (!BN_mod_add_quick(tmp2, tmp2, x, &group->field)) goto err;
- if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
- }
- else
- {
- if (group->meth->field_decode)
- {
- if (!group->meth->field_decode(group, tmp2, &group->a, ctx)) goto err;
- if (!BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) goto err;
- }
- else
- {
- /* field_mul works on standard representation */
- if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) goto err;
- }
-
- if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
- }
-
- /* tmp1 := tmp1 + b */
- if (group->meth->field_decode)
- {
- if (!group->meth->field_decode(group, tmp2, &group->b, ctx)) goto err;
- if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
- }
- else
- {
- if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) goto err;
- }
-
- if (!BN_mod_sqrt(y, tmp1, &group->field, ctx))
- {
- unsigned long err = ERR_peek_last_error();
-
- if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE)
- {
- ERR_clear_error();
- ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
- }
- else
- ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB);
- goto err;
- }
-
- if (y_bit != BN_is_odd(y))
- {
- if (BN_is_zero(y))
- {
- int kron;
-
- kron = BN_kronecker(x, &group->field, ctx);
- if (kron == -2) goto err;
-
- if (kron == 1)
- ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSION_BIT);
- else
- /* BN_mod_sqrt() should have cought this error (not a square) */
- ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
- goto err;
- }
- if (!BN_usub(y, &group->field, y)) goto err;
- }
- if (y_bit != BN_is_odd(y))
- {
- ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
-
- ret = 1;
-
- err:
- BN_CTX_end(ctx);
- if (new_ctx != NULL)
- BN_CTX_free(new_ctx);
- return ret;
- }
-
-
-size_t ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *ctx)
- {
- size_t ret;
- BN_CTX *new_ctx = NULL;
- int used_ctx = 0;
- BIGNUM *x, *y;
- size_t field_len, i, skip;
-
- if ((form != POINT_CONVERSION_COMPRESSED)
- && (form != POINT_CONVERSION_UNCOMPRESSED)
- && (form != POINT_CONVERSION_HYBRID))
- {
- ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
- goto err;
- }
-
- if (EC_POINT_is_at_infinity(group, point))
- {
- /* encodes to a single 0 octet */
- if (buf != NULL)
- {
- if (len < 1)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
- return 0;
- }
- buf[0] = 0;
- }
- return 1;
- }
-
-
- /* ret := required output buffer length */
- field_len = BN_num_bytes(&group->field);
- ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
-
- /* if 'buf' is NULL, just return required length */
- if (buf != NULL)
- {
- if (len < ret)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
- goto err;
- }
-
- if (ctx == NULL)
- {
- ctx = new_ctx = BN_CTX_new();
- if (ctx == NULL)
- return 0;
- }
-
- BN_CTX_start(ctx);
- used_ctx = 1;
- x = BN_CTX_get(ctx);
- y = BN_CTX_get(ctx);
- if (y == NULL) goto err;
-
- if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
-
- if ((form == POINT_CONVERSION_COMPRESSED || form == POINT_CONVERSION_HYBRID) && BN_is_odd(y))
- buf[0] = form + 1;
- else
- buf[0] = form;
-
- i = 1;
-
- skip = field_len - BN_num_bytes(x);
- if (skip > field_len)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- while (skip > 0)
- {
- buf[i++] = 0;
- skip--;
- }
- skip = BN_bn2bin(x, buf + i);
- i += skip;
- if (i != 1 + field_len)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
- if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID)
- {
- skip = field_len - BN_num_bytes(y);
- if (skip > field_len)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- while (skip > 0)
- {
- buf[i++] = 0;
- skip--;
- }
- skip = BN_bn2bin(y, buf + i);
- i += skip;
- }
-
- if (i != ret)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
- goto err;
- }
- }
-
- if (used_ctx)
- BN_CTX_end(ctx);
- if (new_ctx != NULL)
- BN_CTX_free(new_ctx);
- return ret;
-
- err:
- if (used_ctx)
- BN_CTX_end(ctx);
- if (new_ctx != NULL)
- BN_CTX_free(new_ctx);
- return 0;
- }
-
-
-int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
- const unsigned char *buf, size_t len, BN_CTX *ctx)
- {
- point_conversion_form_t form;
- int y_bit;
- BN_CTX *new_ctx = NULL;
- BIGNUM *x, *y;
- size_t field_len, enc_len;
- int ret = 0;
-
- if (len == 0)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
- return 0;
- }
- form = buf[0];
- y_bit = form & 1;
- form = form & ~1U;
- if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
- && (form != POINT_CONVERSION_UNCOMPRESSED)
- && (form != POINT_CONVERSION_HYBRID))
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- return 0;
- }
- if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- return 0;
- }
-
- if (form == 0)
- {
- if (len != 1)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- return 0;
- }
-
- return EC_POINT_set_to_infinity(group, point);
- }
-
- field_len = BN_num_bytes(&group->field);
- enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
-
- if (len != enc_len)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- return 0;
- }
-
- if (ctx == NULL)
- {
- ctx = new_ctx = BN_CTX_new();
- if (ctx == NULL)
- return 0;
- }
-
- BN_CTX_start(ctx);
- x = BN_CTX_get(ctx);
- y = BN_CTX_get(ctx);
- if (y == NULL) goto err;
-
- if (!BN_bin2bn(buf + 1, field_len, x)) goto err;
- if (BN_ucmp(x, &group->field) >= 0)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- goto err;
- }
-
- if (form == POINT_CONVERSION_COMPRESSED)
- {
- if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) goto err;
- }
- else
- {
- if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err;
- if (BN_ucmp(y, &group->field) >= 0)
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- goto err;
- }
- if (form == POINT_CONVERSION_HYBRID)
- {
- if (y_bit != BN_is_odd(y))
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
- goto err;
- }
- }
-
- if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
- }
-
- if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */
- {
- ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE);
- goto err;
- }
-
- ret = 1;
-
- err:
- BN_CTX_end(ctx);
- if (new_ctx != NULL)
- BN_CTX_free(new_ctx);
- return ret;
- }
-
-
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
{
int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
diff --git a/crypto/ec/ectest.c b/crypto/ec/ectest.c
index 6148d553f9d59..f107782de006d 100644
--- a/crypto/ec/ectest.c
+++ b/crypto/ec/ectest.c
@@ -94,6 +94,7 @@ int main(int argc, char * argv[]) { puts("Elliptic curves are disabled."); retur
#include <openssl/objects.h>
#include <openssl/rand.h>
#include <openssl/bn.h>
+#include <openssl/opensslconf.h>
#if defined(_MSC_VER) && defined(_MIPS_) && (_MSC_VER/100==12)
/* suppress "too big too optimize" warning */
@@ -107,10 +108,6 @@ int main(int argc, char * argv[]) { puts("Elliptic curves are disabled."); retur
EXIT(1); \
} while (0)
-void prime_field_tests(void);
-void char2_field_tests(void);
-void internal_curve_test(void);
-
#define TIMING_BASE_PT 0
#define TIMING_RAND_PT 1
#define TIMING_SIMUL 2
@@ -195,7 +192,50 @@ static void timings(EC_GROUP *group, int type, BN_CTX *ctx)
}
#endif
-void prime_field_tests()
+/* test multiplication with group order, long and negative scalars */
+static void group_order_tests(EC_GROUP *group)
+ {
+ BIGNUM *n1, *n2, *order;
+ EC_POINT *P = EC_POINT_new(group);
+ EC_POINT *Q = EC_POINT_new(group);
+ BN_CTX *ctx = BN_CTX_new();
+
+ n1 = BN_new(); n2 = BN_new(); order = BN_new();
+ fprintf(stdout, "verify group order ...");
+ fflush(stdout);
+ if (!EC_GROUP_get_order(group, order, ctx)) ABORT;
+ if (!EC_POINT_mul(group, Q, order, NULL, NULL, ctx)) ABORT;
+ if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
+ fprintf(stdout, ".");
+ fflush(stdout);
+ if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
+ if (!EC_POINT_mul(group, Q, order, NULL, NULL, ctx)) ABORT;
+ if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
+ fprintf(stdout, " ok\n");
+ fprintf(stdout, "long/negative scalar tests ... ");
+ if (!BN_one(n1)) ABORT;
+ /* n1 = 1 - order */
+ if (!BN_sub(n1, n1, order)) ABORT;
+ if(!EC_POINT_mul(group, Q, NULL, P, n1, ctx)) ABORT;
+ if (0 != EC_POINT_cmp(group, Q, P, ctx)) ABORT;
+ /* n2 = 1 + order */
+ if (!BN_add(n2, order, BN_value_one())) ABORT;
+ if(!EC_POINT_mul(group, Q, NULL, P, n2, ctx)) ABORT;
+ if (0 != EC_POINT_cmp(group, Q, P, ctx)) ABORT;
+ /* n2 = (1 - order) * (1 + order) */
+ if (!BN_mul(n2, n1, n2, ctx)) ABORT;
+ if(!EC_POINT_mul(group, Q, NULL, P, n2, ctx)) ABORT;
+ if (0 != EC_POINT_cmp(group, Q, P, ctx)) ABORT;
+ fprintf(stdout, "ok\n");
+ EC_POINT_free(P);
+ EC_POINT_free(Q);
+ BN_free(n1);
+ BN_free(n2);
+ BN_free(order);
+ BN_CTX_free(ctx);
+ }
+
+static void prime_field_tests(void)
{
BN_CTX *ctx = NULL;
BIGNUM *p, *a, *b;
@@ -321,21 +361,21 @@ void prime_field_tests()
if (len == 0) ABORT;
if (!EC_POINT_oct2point(group, P, buf, len, ctx)) ABORT;
if (0 != EC_POINT_cmp(group, P, Q, ctx)) ABORT;
- fprintf(stdout, "Generator as octect string, compressed form:\n ");
+ fprintf(stdout, "Generator as octet string, compressed form:\n ");
for (i = 0; i < len; i++) fprintf(stdout, "%02X", buf[i]);
len = EC_POINT_point2oct(group, Q, POINT_CONVERSION_UNCOMPRESSED, buf, sizeof buf, ctx);
if (len == 0) ABORT;
if (!EC_POINT_oct2point(group, P, buf, len, ctx)) ABORT;
if (0 != EC_POINT_cmp(group, P, Q, ctx)) ABORT;
- fprintf(stdout, "\nGenerator as octect string, uncompressed form:\n ");
+ fprintf(stdout, "\nGenerator as octet string, uncompressed form:\n ");
for (i = 0; i < len; i++) fprintf(stdout, "%02X", buf[i]);
len = EC_POINT_point2oct(group, Q, POINT_CONVERSION_HYBRID, buf, sizeof buf, ctx);
if (len == 0) ABORT;
if (!EC_POINT_oct2point(group, P, buf, len, ctx)) ABORT;
if (0 != EC_POINT_cmp(group, P, Q, ctx)) ABORT;
- fprintf(stdout, "\nGenerator as octect string, hybrid form:\n ");
+ fprintf(stdout, "\nGenerator as octet string, hybrid form:\n ");
for (i = 0; i < len; i++) fprintf(stdout, "%02X", buf[i]);
if (!EC_POINT_get_Jprojective_coordinates_GFp(group, R, x, y, z, ctx)) ABORT;
@@ -381,17 +421,7 @@ void prime_field_tests()
if (EC_GROUP_get_degree(group) != 160) ABORT;
fprintf(stdout, " ok\n");
- fprintf(stdout, "verify group order ...");
- fflush(stdout);
- if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, ".");
- fflush(stdout);
- if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, " ok\n");
+ group_order_tests(group);
if (!(P_160 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT;
if (!EC_GROUP_copy(P_160, group)) ABORT;
@@ -425,19 +455,7 @@ void prime_field_tests()
if (EC_GROUP_get_degree(group) != 192) ABORT;
fprintf(stdout, " ok\n");
- fprintf(stdout, "verify group order ...");
- fflush(stdout);
- if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, ".");
- fflush(stdout);
-#if 0
- if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
-#endif
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, " ok\n");
+ group_order_tests(group);
if (!(P_192 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT;
if (!EC_GROUP_copy(P_192, group)) ABORT;
@@ -471,19 +489,7 @@ void prime_field_tests()
if (EC_GROUP_get_degree(group) != 224) ABORT;
fprintf(stdout, " ok\n");
- fprintf(stdout, "verify group order ...");
- fflush(stdout);
- if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, ".");
- fflush(stdout);
-#if 0
- if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
-#endif
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, " ok\n");
+ group_order_tests(group);
if (!(P_224 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT;
if (!EC_GROUP_copy(P_224, group)) ABORT;
@@ -518,19 +524,7 @@ void prime_field_tests()
if (EC_GROUP_get_degree(group) != 256) ABORT;
fprintf(stdout, " ok\n");
- fprintf(stdout, "verify group order ...");
- fflush(stdout);
- if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, ".");
- fflush(stdout);
-#if 0
- if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
-#endif
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, " ok\n");
+ group_order_tests(group);
if (!(P_256 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT;
if (!EC_GROUP_copy(P_256, group)) ABORT;
@@ -569,20 +563,8 @@ void prime_field_tests()
fprintf(stdout, "verify degree ...");
if (EC_GROUP_get_degree(group) != 384) ABORT;
fprintf(stdout, " ok\n");
-
- fprintf(stdout, "verify group order ...");
- fflush(stdout);
- if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, ".");
- fflush(stdout);
-#if 0
- if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
-#endif
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, " ok\n");
+
+ group_order_tests(group);
if (!(P_384 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT;
if (!EC_GROUP_copy(P_384, group)) ABORT;
@@ -627,20 +609,8 @@ void prime_field_tests()
fprintf(stdout, "verify degree ...");
if (EC_GROUP_get_degree(group) != 521) ABORT;
fprintf(stdout, " ok\n");
-
- fprintf(stdout, "verify group order ...");
- fflush(stdout);
- if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, ".");
- fflush(stdout);
-#if 0
- if (!EC_GROUP_precompute_mult(group, ctx)) ABORT;
-#endif
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT;
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT;
- fprintf(stdout, " ok\n");
+
+ group_order_tests(group);
if (!(P_521 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT;
if (!EC_GROUP_copy(P_521, group)) ABORT;
@@ -669,6 +639,7 @@ void prime_field_tests()
points[2] = Q;
points[3] = Q;
+ if (!EC_GROUP_get_order(group, z, ctx)) ABORT;
if (!BN_add(y, z, BN_value_one())) ABORT;
if (BN_is_odd(y)) ABORT;
if (!BN_rshift1(y, y)) ABORT;
@@ -802,22 +773,14 @@ void prime_field_tests()
fprintf(stdout, "verify degree ..."); \
if (EC_GROUP_get_degree(group) != _degree) ABORT; \
fprintf(stdout, " ok\n"); \
- fprintf(stdout, "verify group order ..."); \
- fflush(stdout); \
- if (!EC_GROUP_get_order(group, z, ctx)) ABORT; \
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT; \
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT; \
- fprintf(stdout, "."); \
- fflush(stdout); \
- /* if (!EC_GROUP_precompute_mult(group, ctx)) ABORT; */ \
- if (!EC_POINT_mul(group, Q, z, NULL, NULL, ctx)) ABORT; \
- if (!EC_POINT_is_at_infinity(group, Q)) ABORT; \
- fprintf(stdout, " ok\n"); \
+ group_order_tests(group); \
if (!(_variable = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT; \
- if (!EC_GROUP_copy(_variable, group)) ABORT;
+ if (!EC_GROUP_copy(_variable, group)) ABORT; \
-void char2_field_tests()
- {
+#ifndef OPENSSL_NO_EC2M
+
+static void char2_field_tests(void)
+ {
BN_CTX *ctx = NULL;
BIGNUM *p, *a, *b;
EC_GROUP *group;
@@ -1249,8 +1212,9 @@ void char2_field_tests()
if (C2_B571) EC_GROUP_free(C2_B571);
}
+#endif
-void internal_curve_test(void)
+static void internal_curve_test(void)
{
EC_builtin_curve *curves = NULL;
size_t crv_len = 0, n = 0;
@@ -1297,13 +1261,189 @@ void internal_curve_test(void)
EC_GROUP_free(group);
}
if (ok)
- fprintf(stdout, " ok\n");
+ fprintf(stdout, " ok\n\n");
else
- fprintf(stdout, " failed\n");
+ {
+ fprintf(stdout, " failed\n\n");
+ ABORT;
+ }
OPENSSL_free(curves);
return;
}
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+/* nistp_test_params contains magic numbers for testing our optimized
+ * implementations of several NIST curves with characteristic > 3. */
+struct nistp_test_params
+ {
+ const EC_METHOD* (*meth) ();
+ int degree;
+ /* Qx, Qy and D are taken from
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/ECDSA_Prime.pdf
+ * Otherwise, values are standard curve parameters from FIPS 180-3 */
+ const char *p, *a, *b, *Qx, *Qy, *Gx, *Gy, *order, *d;
+ };
+
+static const struct nistp_test_params nistp_tests_params[] =
+ {
+ {
+ /* P-224 */
+ EC_GFp_nistp224_method,
+ 224,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", /* p */
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", /* a */
+ "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", /* b */
+ "E84FB0B8E7000CB657D7973CF6B42ED78B301674276DF744AF130B3E", /* Qx */
+ "4376675C6FC5612C21A0FF2D2A89D2987DF7A2BC52183B5982298555", /* Qy */
+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", /* Gx */
+ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", /* Gy */
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", /* order */
+ "3F0C488E987C80BE0FEE521F8D90BE6034EC69AE11CA72AA777481E8", /* d */
+ },
+ {
+ /* P-256 */
+ EC_GFp_nistp256_method,
+ 256,
+ "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", /* p */
+ "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", /* a */
+ "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", /* b */
+ "b7e08afdfe94bad3f1dc8c734798ba1c62b3a0ad1e9ea2a38201cd0889bc7a19", /* Qx */
+ "3603f747959dbf7a4bb226e41928729063adc7ae43529e61b563bbc606cc5e09", /* Qy */
+ "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", /* Gx */
+ "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", /* Gy */
+ "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", /* order */
+ "c477f9f65c22cce20657faa5b2d1d8122336f851a508a1ed04e479c34985bf96", /* d */
+ },
+ {
+ /* P-521 */
+ EC_GFp_nistp521_method,
+ 521,
+ "1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", /* p */
+ "1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", /* a */
+ "051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", /* b */
+ "0098e91eef9a68452822309c52fab453f5f117c1da8ed796b255e9ab8f6410cca16e59df403a6bdc6ca467a37056b1e54b3005d8ac030decfeb68df18b171885d5c4", /* Qx */
+ "0164350c321aecfc1cca1ba4364c9b15656150b4b78d6a48d7d28e7f31985ef17be8554376b72900712c4b83ad668327231526e313f5f092999a4632fd50d946bc2e", /* Qy */
+ "c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", /* Gx */
+ "11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", /* Gy */
+ "1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", /* order */
+ "0100085f47b8e1b8b11b7eb33028c0b2888e304bfc98501955b45bba1478dc184eeedf09b86a5f7c21994406072787205e69a63709fe35aa93ba333514b24f961722", /* d */
+ },
+ };
+
+void nistp_single_test(const struct nistp_test_params *test)
+ {
+ BN_CTX *ctx;
+ BIGNUM *p, *a, *b, *x, *y, *n, *m, *order;
+ EC_GROUP *NISTP;
+ EC_POINT *G, *P, *Q, *Q_CHECK;
+
+ fprintf(stdout, "\nNIST curve P-%d (optimised implementation):\n", test->degree);
+ ctx = BN_CTX_new();
+ p = BN_new();
+ a = BN_new();
+ b = BN_new();
+ x = BN_new(); y = BN_new();
+ m = BN_new(); n = BN_new(); order = BN_new();
+
+ NISTP = EC_GROUP_new(test->meth());
+ if(!NISTP) ABORT;
+ if (!BN_hex2bn(&p, test->p)) ABORT;
+ if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT;
+ if (!BN_hex2bn(&a, test->a)) ABORT;
+ if (!BN_hex2bn(&b, test->b)) ABORT;
+ if (!EC_GROUP_set_curve_GFp(NISTP, p, a, b, ctx)) ABORT;
+ G = EC_POINT_new(NISTP);
+ P = EC_POINT_new(NISTP);
+ Q = EC_POINT_new(NISTP);
+ Q_CHECK = EC_POINT_new(NISTP);
+ if(!BN_hex2bn(&x, test->Qx)) ABORT;
+ if(!BN_hex2bn(&y, test->Qy)) ABORT;
+ if(!EC_POINT_set_affine_coordinates_GFp(NISTP, Q_CHECK, x, y, ctx)) ABORT;
+ if (!BN_hex2bn(&x, test->Gx)) ABORT;
+ if (!BN_hex2bn(&y, test->Gy)) ABORT;
+ if (!EC_POINT_set_affine_coordinates_GFp(NISTP, G, x, y, ctx)) ABORT;
+ if (!BN_hex2bn(&order, test->order)) ABORT;
+ if (!EC_GROUP_set_generator(NISTP, G, order, BN_value_one())) ABORT;
+
+ fprintf(stdout, "verify degree ... ");
+ if (EC_GROUP_get_degree(NISTP) != test->degree) ABORT;
+ fprintf(stdout, "ok\n");
+
+ fprintf(stdout, "NIST test vectors ... ");
+ if (!BN_hex2bn(&n, test->d)) ABORT;
+ /* fixed point multiplication */
+ EC_POINT_mul(NISTP, Q, n, NULL, NULL, ctx);
+ if (0 != EC_POINT_cmp(NISTP, Q, Q_CHECK, ctx)) ABORT;
+ /* random point multiplication */
+ EC_POINT_mul(NISTP, Q, NULL, G, n, ctx);
+ if (0 != EC_POINT_cmp(NISTP, Q, Q_CHECK, ctx)) ABORT;
+
+ /* set generator to P = 2*G, where G is the standard generator */
+ if (!EC_POINT_dbl(NISTP, P, G, ctx)) ABORT;
+ if (!EC_GROUP_set_generator(NISTP, P, order, BN_value_one())) ABORT;
+ /* set the scalar to m=n/2, where n is the NIST test scalar */
+ if (!BN_rshift(m, n, 1)) ABORT;
+
+ /* test the non-standard generator */
+ /* fixed point multiplication */
+ EC_POINT_mul(NISTP, Q, m, NULL, NULL, ctx);
+ if (0 != EC_POINT_cmp(NISTP, Q, Q_CHECK, ctx)) ABORT;
+ /* random point multiplication */
+ EC_POINT_mul(NISTP, Q, NULL, P, m, ctx);
+ if (0 != EC_POINT_cmp(NISTP, Q, Q_CHECK, ctx)) ABORT;
+
+ /* now repeat all tests with precomputation */
+ if (!EC_GROUP_precompute_mult(NISTP, ctx)) ABORT;
+
+ /* fixed point multiplication */
+ EC_POINT_mul(NISTP, Q, m, NULL, NULL, ctx);
+ if (0 != EC_POINT_cmp(NISTP, Q, Q_CHECK, ctx)) ABORT;
+ /* random point multiplication */
+ EC_POINT_mul(NISTP, Q, NULL, P, m, ctx);
+ if (0 != EC_POINT_cmp(NISTP, Q, Q_CHECK, ctx)) ABORT;
+
+ /* reset generator */
+ if (!EC_GROUP_set_generator(NISTP, G, order, BN_value_one())) ABORT;
+ /* fixed point multiplication */
+ EC_POINT_mul(NISTP, Q, n, NULL, NULL, ctx);
+ if (0 != EC_POINT_cmp(NISTP, Q, Q_CHECK, ctx)) ABORT;
+ /* random point multiplication */
+ EC_POINT_mul(NISTP, Q, NULL, G, n, ctx);
+ if (0 != EC_POINT_cmp(NISTP, Q, Q_CHECK, ctx)) ABORT;
+
+ fprintf(stdout, "ok\n");
+ group_order_tests(NISTP);
+#if 0
+ timings(NISTP, TIMING_BASE_PT, ctx);
+ timings(NISTP, TIMING_RAND_PT, ctx);
+#endif
+ EC_GROUP_free(NISTP);
+ EC_POINT_free(G);
+ EC_POINT_free(P);
+ EC_POINT_free(Q);
+ EC_POINT_free(Q_CHECK);
+ BN_free(n);
+ BN_free(m);
+ BN_free(p);
+ BN_free(a);
+ BN_free(b);
+ BN_free(x);
+ BN_free(y);
+ BN_free(order);
+ BN_CTX_free(ctx);
+ }
+
+void nistp_tests()
+ {
+ unsigned i;
+
+ for (i = 0; i < sizeof(nistp_tests_params) / sizeof(struct nistp_test_params); i++)
+ {
+ nistp_single_test(&nistp_tests_params[i]);
+ }
+ }
+#endif
+
static const char rnd_seed[] = "string to make the random number generator think it has entropy";
int main(int argc, char *argv[])
@@ -1327,7 +1467,12 @@ int main(int argc, char *argv[])
prime_field_tests();
puts("");
+#ifndef OPENSSL_NO_EC2M
char2_field_tests();
+#endif
+#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
+ nistp_tests();
+#endif
/* test the internal curves */
internal_curve_test();
@@ -1336,7 +1481,7 @@ int main(int argc, char *argv[])
#endif
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
- ERR_remove_state(0);
+ ERR_remove_thread_state(NULL);
CRYPTO_mem_leaks_fp(stderr);
return 0;