diff options
Diffstat (limited to 'openssl/crypto/ec')
-rw-r--r-- | openssl/crypto/ec/Makefile | 193 | ||||
-rw-r--r-- | openssl/crypto/ec/ec.h | 526 | ||||
-rw-r--r-- | openssl/crypto/ec/ec2_mult.c | 380 | ||||
-rw-r--r-- | openssl/crypto/ec/ec2_smpl.c | 971 | ||||
-rw-r--r-- | openssl/crypto/ec/ec2_smpt.c | 141 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_asn1.c | 1429 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_check.c | 123 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_curve.c | 1270 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_cvt.c | 144 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_err.c | 239 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_key.c | 457 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_lcl.h | 390 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_lib.c | 1164 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_mult.c | 938 | ||||
-rw-r--r-- | openssl/crypto/ec/ec_print.c | 195 | ||||
-rw-r--r-- | openssl/crypto/ec/ecp_mont.c | 315 | ||||
-rw-r--r-- | openssl/crypto/ec/ecp_nist.c | 236 | ||||
-rw-r--r-- | openssl/crypto/ec/ecp_smpl.c | 1716 | ||||
-rw-r--r-- | openssl/crypto/ec/ectest.c | 1344 |
19 files changed, 12171 insertions, 0 deletions
diff --git a/openssl/crypto/ec/Makefile b/openssl/crypto/ec/Makefile new file mode 100644 index 000000000..b5bbc9faa --- /dev/null +++ b/openssl/crypto/ec/Makefile @@ -0,0 +1,193 @@ +# +# crypto/ec/Makefile +# + +DIR= ec +TOP= ../.. +CC= cc +INCLUDES= -I.. -I$(TOP) -I../../include +CFLAG=-g +MAKEFILE= Makefile +AR= ar r + +CFLAGS= $(INCLUDES) $(CFLAG) + +GENERAL=Makefile +TEST=ectest.c +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 + +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 + +SRC= $(LIBSRC) + +EXHEADER= ec.h +HEADER= ec_lcl.h $(EXHEADER) + +ALL= $(GENERAL) $(SRC) $(HEADER) + +top: + (cd ../..; $(MAKE) DIRS=crypto SDIRS=$(DIR) sub_all) + +all: lib + +lib: $(LIBOBJ) + $(ARX) $(LIB) $(LIBOBJ) + $(RANLIB) $(LIB) || echo Never mind. + @touch lib + +files: + $(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO + +links: + @$(PERL) $(TOP)/util/mklink.pl ../../include/openssl $(EXHEADER) + @$(PERL) $(TOP)/util/mklink.pl ../../test $(TEST) + @$(PERL) $(TOP)/util/mklink.pl ../../apps $(APPS) + +install: + @[ -n "$(INSTALLTOP)" ] # should be set by top Makefile... + @headerlist="$(EXHEADER)"; for i in $$headerlist ; \ + do \ + (cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \ + chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \ + done; + +tags: + ctags $(SRC) + +tests: + +lint: + lint -DLINT $(INCLUDES) $(SRC)>fluff + +depend: + @[ -n "$(MAKEDEPEND)" ] # should be set by upper Makefile... + $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(LIBSRC) + +dclean: + $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new + mv -f Makefile.new $(MAKEFILE) + +clean: + rm -f *.o */*.o *.obj lib tags core .pure .nfs* *.old *.bak fluff + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +ec2_mult.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ec2_mult.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h +ec2_mult.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +ec2_mult.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +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_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 +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 +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 +ec_asn1.o: ../../include/openssl/ec.h ../../include/openssl/err.h +ec_asn1.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +ec_asn1.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h +ec_asn1.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ec_asn1.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ec_asn1.o: ../../include/openssl/symhacks.h ec_asn1.c ec_lcl.h +ec_check.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ec_check.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h +ec_check.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +ec_check.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +ec_check.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h +ec_check.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ec_check.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ec_check.o: ../../include/openssl/symhacks.h ec_check.c ec_lcl.h +ec_curve.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ec_curve.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h +ec_curve.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +ec_curve.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +ec_curve.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h +ec_curve.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ec_curve.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ec_curve.o: ../../include/openssl/symhacks.h ec_curve.c ec_lcl.h +ec_cvt.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ec_cvt.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h +ec_cvt.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +ec_cvt.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +ec_cvt.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h +ec_cvt.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ec_cvt.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ec_cvt.o: ../../include/openssl/symhacks.h ec_cvt.c ec_lcl.h +ec_err.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ec_err.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h +ec_err.o: ../../include/openssl/ec.h ../../include/openssl/err.h +ec_err.o: ../../include/openssl/lhash.h ../../include/openssl/opensslconf.h +ec_err.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ec_err.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ec_err.o: ../../include/openssl/symhacks.h ec_err.c +ec_key.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ec_key.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h +ec_key.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +ec_key.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +ec_key.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h +ec_key.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ec_key.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ec_key.o: ../../include/openssl/symhacks.h ec_key.c ec_lcl.h +ec_lib.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ec_lib.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h +ec_lib.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +ec_lib.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +ec_lib.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h +ec_lib.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ec_lib.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ec_lib.o: ../../include/openssl/symhacks.h ec_lcl.h ec_lib.c +ec_mult.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ec_mult.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h +ec_mult.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +ec_mult.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +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_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 +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 +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 +ecp_mont.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +ecp_mont.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h +ecp_mont.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ecp_mont.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ecp_mont.o: ../../include/openssl/symhacks.h ec_lcl.h ecp_mont.c +ecp_nist.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +ecp_nist.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h +ecp_nist.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +ecp_nist.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +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_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 +ecp_smpl.o: ../../include/openssl/err.h ../../include/openssl/lhash.h +ecp_smpl.o: ../../include/openssl/obj_mac.h ../../include/openssl/opensslconf.h +ecp_smpl.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +ecp_smpl.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +ecp_smpl.o: ../../include/openssl/symhacks.h ec_lcl.h ecp_smpl.c diff --git a/openssl/crypto/ec/ec.h b/openssl/crypto/ec/ec.h new file mode 100644 index 000000000..8bc2a235b --- /dev/null +++ b/openssl/crypto/ec/ec.h @@ -0,0 +1,526 @@ +/* crypto/ec/ec.h */ +/* + * 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. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#ifndef HEADER_EC_H +#define HEADER_EC_H + +#include <openssl/opensslconf.h> + +#ifdef OPENSSL_NO_EC +#error EC is disabled. +#endif + +#include <openssl/asn1.h> +#include <openssl/symhacks.h> +#ifndef OPENSSL_NO_DEPRECATED +#include <openssl/bn.h> +#endif + +#ifdef __cplusplus +extern "C" { +#elif defined(__SUNPRO_C) +# if __SUNPRO_C >= 0x520 +# pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE) +# endif +#endif + + +#ifndef OPENSSL_ECC_MAX_FIELD_BITS +# define OPENSSL_ECC_MAX_FIELD_BITS 661 +#endif + +typedef enum { + /* values as defined in X9.62 (ECDSA) and elsewhere */ + POINT_CONVERSION_COMPRESSED = 2, + POINT_CONVERSION_UNCOMPRESSED = 4, + POINT_CONVERSION_HYBRID = 6 +} point_conversion_form_t; + + +typedef struct ec_method_st EC_METHOD; + +typedef struct ec_group_st + /* + EC_METHOD *meth; + -- field definition + -- curve coefficients + -- optional generator with associated information (order, cofactor) + -- optional extra data (precomputed table for fast computation of multiples of generator) + -- ASN1 stuff + */ + EC_GROUP; + +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. + */ +const EC_METHOD *EC_GFp_simple_method(void); +const EC_METHOD *EC_GFp_mont_method(void); +const EC_METHOD *EC_GFp_nist_method(void); + +/* EC_METHOD for curves over GF(2^m). + */ +const EC_METHOD *EC_GF2m_simple_method(void); + + +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 *); + +const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *); +int EC_METHOD_get_field_type(const EC_METHOD *); + +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 *); + +void EC_GROUP_set_curve_name(EC_GROUP *, int nid); +int EC_GROUP_get_curve_name(const EC_GROUP *); + +void EC_GROUP_set_asn1_flag(EC_GROUP *, int flag); +int EC_GROUP_get_asn1_flag(const EC_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 *); + +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 *); + +/* EC_GROUP_check() returns 1 if 'group' defines a valid group, 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 *); + +/* 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) */ +EC_GROUP *EC_GROUP_new_by_curve_name(int nid); +/* 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 + * are filled with the data of the first nitems internal groups */ +size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems); + + +/* EC_POINT functions */ + +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 *); + +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 *); + +/* other interfaces to point2oct/oct2point: */ +BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *, + point_conversion_form_t form, BIGNUM *, BN_CTX *); +EC_POINT *EC_POINT_bn2point(const EC_GROUP *, const BIGNUM *, + EC_POINT *, BN_CTX *); +char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *, + point_conversion_form_t form, BN_CTX *); +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 *); + +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 *); + + +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 *); + + + +/* 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 *); +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); + +#define OPENSSL_EC_NAMED_CURVE 0x001 + +typedef struct ecpk_parameters_st ECPKPARAMETERS; + +EC_GROUP *d2i_ECPKParameters(EC_GROUP **, const unsigned char **in, long len); +int i2d_ECPKParameters(const EC_GROUP *, unsigned char **out); + +#define d2i_ECPKParameters_bio(bp,x) ASN1_d2i_bio_of(EC_GROUP,NULL,d2i_ECPKParameters,bp,x) +#define i2d_ECPKParameters_bio(bp,x) ASN1_i2d_bio_of_const(EC_GROUP,i2d_ECPKParameters,bp,x) +#define d2i_ECPKParameters_fp(fp,x) (EC_GROUP *)ASN1_d2i_fp(NULL, \ + (char *(*)())d2i_ECPKParameters,(fp),(unsigned char **)(x)) +#define i2d_ECPKParameters_fp(fp,x) ASN1_i2d_fp(i2d_ECPKParameters,(fp), \ + (unsigned char *)(x)) + +#ifndef OPENSSL_NO_BIO +int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off); +#endif +#ifndef OPENSSL_NO_FP_API +int ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off); +#endif + +/* the EC_KEY stuff */ +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 + +EC_KEY *EC_KEY_new(void); +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 *); +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); +/* functions to set/get method specific data */ +void *EC_KEY_get_key_method_data(EC_KEY *, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)); +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); + +#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); +#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); +#endif + +#define ECParameters_dup(x) ASN1_dup_of(EC_KEY,i2d_ECParameters,d2i_ECParameters,x) + +#ifndef __cplusplus +#if defined(__SUNPRO_C) +# if __SUNPRO_C >= 0x520 +# pragma error_messages (default,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE) +# endif +# endif +#endif + +/* 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. + */ +void ERR_load_EC_strings(void); + +/* Error codes for the EC functions. */ + +/* Function codes. */ +#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_ECPARAMETERS_PRINT 147 +#define EC_F_ECPARAMETERS_PRINT_FP 148 +#define EC_F_ECPKPARAMETERS_PRINT 149 +#define EC_F_ECPKPARAMETERS_PRINT_FP 150 +#define EC_F_ECP_NIST_MOD_192 203 +#define EC_F_ECP_NIST_MOD_224 204 +#define EC_F_ECP_NIST_MOD_256 205 +#define EC_F_ECP_NIST_MOD_521 206 +#define EC_F_EC_ASN1_GROUP2CURVE 153 +#define EC_F_EC_ASN1_GROUP2FIELDID 154 +#define EC_F_EC_ASN1_GROUP2PARAMETERS 155 +#define EC_F_EC_ASN1_GROUP2PKPARAMETERS 156 +#define EC_F_EC_ASN1_PARAMETERS2GROUP 157 +#define EC_F_EC_ASN1_PKPARAMETERS2GROUP 158 +#define EC_F_EC_EX_DATA_SET_DATA 211 +#define EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY 208 +#define EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT 159 +#define EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE 195 +#define EC_F_EC_GF2M_SIMPLE_OCT2POINT 160 +#define EC_F_EC_GF2M_SIMPLE_POINT2OCT 161 +#define EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES 162 +#define EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES 163 +#define EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES 164 +#define EC_F_EC_GFP_MONT_FIELD_DECODE 133 +#define EC_F_EC_GFP_MONT_FIELD_ENCODE 134 +#define EC_F_EC_GFP_MONT_FIELD_MUL 131 +#define EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE 209 +#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_NIST_FIELD_MUL 200 +#define EC_F_EC_GFP_NIST_FIELD_SQR 201 +#define EC_F_EC_GFP_NIST_GROUP_SET_CURVE 202 +#define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT 165 +#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE 166 +#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP 100 +#define EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR 101 +#define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE 102 +#define EC_F_EC_GFP_SIMPLE_OCT2POINT 103 +#define EC_F_EC_GFP_SIMPLE_POINT2OCT 104 +#define EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE 137 +#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES 167 +#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP 105 +#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES 168 +#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP 128 +#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES 169 +#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP 129 +#define EC_F_EC_GROUP_CHECK 170 +#define EC_F_EC_GROUP_CHECK_DISCRIMINANT 171 +#define EC_F_EC_GROUP_COPY 106 +#define EC_F_EC_GROUP_GET0_GENERATOR 139 +#define EC_F_EC_GROUP_GET_COFACTOR 140 +#define EC_F_EC_GROUP_GET_CURVE_GF2M 172 +#define EC_F_EC_GROUP_GET_CURVE_GFP 130 +#define EC_F_EC_GROUP_GET_DEGREE 173 +#define EC_F_EC_GROUP_GET_ORDER 141 +#define EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS 193 +#define EC_F_EC_GROUP_GET_TRINOMIAL_BASIS 194 +#define EC_F_EC_GROUP_NEW 108 +#define EC_F_EC_GROUP_NEW_BY_CURVE_NAME 174 +#define EC_F_EC_GROUP_NEW_FROM_DATA 175 +#define EC_F_EC_GROUP_PRECOMPUTE_MULT 142 +#define EC_F_EC_GROUP_SET_CURVE_GF2M 176 +#define EC_F_EC_GROUP_SET_CURVE_GFP 109 +#define EC_F_EC_GROUP_SET_EXTRA_DATA 110 +#define EC_F_EC_GROUP_SET_GENERATOR 111 +#define EC_F_EC_KEY_CHECK_KEY 177 +#define EC_F_EC_KEY_COPY 178 +#define EC_F_EC_KEY_GENERATE_KEY 179 +#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_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 +#define EC_F_EC_POINT_DBL 115 +#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M 183 +#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP 116 +#define EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP 117 +#define EC_F_EC_POINT_INVERT 210 +#define EC_F_EC_POINT_IS_AT_INFINITY 118 +#define EC_F_EC_POINT_IS_ON_CURVE 119 +#define EC_F_EC_POINT_MAKE_AFFINE 120 +#define EC_F_EC_POINT_MUL 184 +#define EC_F_EC_POINT_NEW 121 +#define EC_F_EC_POINT_OCT2POINT 122 +#define EC_F_EC_POINT_POINT2OCT 123 +#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M 185 +#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP 124 +#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M 186 +#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP 125 +#define EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP 126 +#define EC_F_EC_POINT_SET_TO_INFINITY 127 +#define EC_F_EC_PRE_COMP_DUP 207 +#define EC_F_EC_PRE_COMP_NEW 196 +#define EC_F_EC_WNAF_MUL 187 +#define EC_F_EC_WNAF_PRECOMPUTE_MULT 188 +#define EC_F_I2D_ECPARAMETERS 190 +#define EC_F_I2D_ECPKPARAMETERS 191 +#define EC_F_I2D_ECPRIVATEKEY 192 +#define EC_F_I2O_ECPUBLICKEY 151 +#define EC_F_O2I_ECPUBLICKEY 152 + +/* Reason codes. */ +#define EC_R_ASN1_ERROR 115 +#define EC_R_ASN1_UNKNOWN_FIELD 116 +#define EC_R_BUFFER_TOO_SMALL 100 +#define EC_R_D2I_ECPKPARAMETERS_FAILURE 117 +#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_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_ENCODING 102 +#define EC_R_INVALID_FIELD 103 +#define EC_R_INVALID_FORM 104 +#define EC_R_INVALID_GROUP_ORDER 122 +#define EC_R_INVALID_PENTANOMIAL_BASIS 132 +#define EC_R_INVALID_PRIVATE_KEY 123 +#define EC_R_INVALID_TRINOMIAL_BASIS 137 +#define EC_R_MISSING_PARAMETERS 124 +#define EC_R_MISSING_PRIVATE_KEY 125 +#define EC_R_NOT_A_NIST_PRIME 135 +#define EC_R_NOT_A_SUPPORTED_NIST_PRIME 136 +#define EC_R_NOT_IMPLEMENTED 126 +#define EC_R_NOT_INITIALIZED 111 +#define EC_R_NO_FIELD_MOD 133 +#define EC_R_PASSED_NULL_PARAMETER 134 +#define EC_R_PKPARAMETERS2GROUP_FAILURE 127 +#define EC_R_POINT_AT_INFINITY 106 +#define EC_R_POINT_IS_NOT_ON_CURVE 107 +#define EC_R_SLOT_FULL 108 +#define EC_R_UNDEFINED_GENERATOR 113 +#define EC_R_UNDEFINED_ORDER 128 +#define EC_R_UNKNOWN_GROUP 129 +#define EC_R_UNKNOWN_ORDER 114 +#define EC_R_UNSUPPORTED_FIELD 131 +#define EC_R_WRONG_ORDER 130 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/openssl/crypto/ec/ec2_mult.c b/openssl/crypto/ec/ec2_mult.c new file mode 100644 index 000000000..ff368fd7d --- /dev/null +++ b/openssl/crypto/ec/ec2_mult.c @@ -0,0 +1,380 @@ +/* crypto/ec/ec2_mult.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-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). + * + */ + +#include <openssl/err.h> + +#include "ec_lcl.h" + + +/* 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". + * 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) + { + BIGNUM *t1; + int ret = 0; + + /* Since Mdouble is static we can guarantee that ctx != NULL. */ + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + if (t1 == NULL) goto err; + + if (!group->meth->field_sqr(group, x, x, ctx)) goto err; + if (!group->meth->field_sqr(group, t1, z, ctx)) goto err; + if (!group->meth->field_mul(group, z, x, t1, ctx)) goto err; + if (!group->meth->field_sqr(group, x, x, ctx)) goto err; + if (!group->meth->field_sqr(group, t1, t1, ctx)) goto err; + if (!group->meth->field_mul(group, t1, &group->b, t1, ctx)) goto err; + if (!BN_GF2m_add(x, x, t1)) goto err; + + ret = 1; + + err: + BN_CTX_end(ctx); + return ret; + } + +/* 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". + */ +static int gf2m_Madd(const EC_GROUP *group, const BIGNUM *x, BIGNUM *x1, BIGNUM *z1, + const BIGNUM *x2, const BIGNUM *z2, BN_CTX *ctx) + { + BIGNUM *t1, *t2; + int ret = 0; + + /* Since Madd is static we can guarantee that ctx != NULL. */ + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t2 == NULL) goto err; + + if (!BN_copy(t1, x)) goto err; + if (!group->meth->field_mul(group, x1, x1, z2, ctx)) goto err; + if (!group->meth->field_mul(group, z1, z1, x2, ctx)) goto err; + if (!group->meth->field_mul(group, t2, x1, z1, ctx)) goto err; + if (!BN_GF2m_add(z1, z1, x1)) goto err; + if (!group->meth->field_sqr(group, z1, z1, ctx)) goto err; + if (!group->meth->field_mul(group, x1, z1, t1, ctx)) goto err; + if (!BN_GF2m_add(x1, x1, t2)) goto err; + + ret = 1; + + err: + BN_CTX_end(ctx); + return ret; + } + +/* 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". + * Returns: + * 0 on error + * 1 if return value should be the point at infinity + * 2 otherwise + */ +static int gf2m_Mxy(const EC_GROUP *group, const BIGNUM *x, const BIGNUM *y, BIGNUM *x1, + BIGNUM *z1, BIGNUM *x2, BIGNUM *z2, BN_CTX *ctx) + { + BIGNUM *t3, *t4, *t5; + int ret = 0; + + if (BN_is_zero(z1)) + { + BN_zero(x2); + BN_zero(z2); + return 1; + } + + if (BN_is_zero(z2)) + { + if (!BN_copy(x2, x)) return 0; + if (!BN_GF2m_add(z2, x, y)) return 0; + return 2; + } + + /* Since Mxy is static we can guarantee that ctx != NULL. */ + BN_CTX_start(ctx); + t3 = BN_CTX_get(ctx); + t4 = BN_CTX_get(ctx); + t5 = BN_CTX_get(ctx); + if (t5 == NULL) goto err; + + if (!BN_one(t5)) goto err; + + if (!group->meth->field_mul(group, t3, z1, z2, ctx)) goto err; + + if (!group->meth->field_mul(group, z1, z1, x, ctx)) goto err; + if (!BN_GF2m_add(z1, z1, x1)) goto err; + if (!group->meth->field_mul(group, z2, z2, x, ctx)) goto err; + if (!group->meth->field_mul(group, x1, z2, x1, ctx)) goto err; + if (!BN_GF2m_add(z2, z2, x2)) goto err; + + if (!group->meth->field_mul(group, z2, z2, z1, ctx)) goto err; + if (!group->meth->field_sqr(group, t4, x, ctx)) goto err; + if (!BN_GF2m_add(t4, t4, y)) goto err; + if (!group->meth->field_mul(group, t4, t4, t3, ctx)) goto err; + if (!BN_GF2m_add(t4, t4, z2)) goto err; + + if (!group->meth->field_mul(group, t3, t3, x, ctx)) goto err; + if (!group->meth->field_div(group, t3, t5, t3, ctx)) goto err; + if (!group->meth->field_mul(group, t4, t3, t4, ctx)) goto err; + if (!group->meth->field_mul(group, x2, x1, t3, ctx)) goto err; + if (!BN_GF2m_add(z2, x2, x)) goto err; + + if (!group->meth->field_mul(group, z2, z2, t4, ctx)) goto err; + if (!BN_GF2m_add(z2, z2, y)) goto err; + + ret = 2; + + err: + BN_CTX_end(ctx); + return ret; + } + +/* 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". + */ +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; + + if (r == point) + { + ECerr(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY, EC_R_INVALID_ARGUMENT); + return 0; + } + + /* if result should be point at infinity */ + if ((scalar == NULL) || BN_is_zero(scalar) || (point == NULL) || + EC_POINT_is_at_infinity(group, point)) + { + return EC_POINT_set_to_infinity(group, r); + } + + /* only support affine coordinates */ + if (!point->Z_is_one) return 0; + + /* Since point_multiply is static we can guarantee that ctx != NULL. */ + BN_CTX_start(ctx); + x1 = BN_CTX_get(ctx); + z1 = BN_CTX_get(ctx); + if (z1 == NULL) goto err; + + x2 = &r->X; + z2 = &r->Y; + + if (!BN_GF2m_mod_arr(x1, &point->X, group->poly)) goto err; /* x1 = x */ + if (!BN_one(z1)) goto err; /* z1 = 1 */ + if (!group->meth->field_sqr(group, z2, x1, ctx)) goto err; /* z2 = x1^2 = x^2 */ + if (!group->meth->field_sqr(group, x2, z2, ctx)) goto err; + 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; + mask = BN_TBIT; + while (!(scalar->d[i] & mask)) { mask >>= 1; j--; } + mask >>= 1; j--; + /* if top most bit was at word break, go to next word */ + if (!mask) + { + i--; j = BN_BITS2 - 1; + mask = BN_TBIT; + } + + for (; i >= 0; i--) + { + for (; j >= 0; j--) + { + if (scalar->d[i] & mask) + { + if (!gf2m_Madd(group, &point->X, x1, z1, x2, z2, ctx)) goto err; + if (!gf2m_Mdouble(group, x2, z2, ctx)) goto err; + } + else + { + if (!gf2m_Madd(group, &point->X, x2, z2, x1, z1, ctx)) goto err; + if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err; + } + mask >>= 1; + } + j = BN_BITS2 - 1; + mask = BN_TBIT; + } + + /* convert out of "projective" coordinates */ + i = gf2m_Mxy(group, &point->X, &point->Y, x1, z1, x2, z2, ctx); + if (i == 0) goto err; + else if (i == 1) + { + if (!EC_POINT_set_to_infinity(group, r)) goto err; + } + else + { + if (!BN_one(&r->Z)) goto err; + r->Z_is_one = 1; + } + + /* GF(2^m) field elements should always have BIGNUM::neg = 0 */ + BN_set_negative(&r->X, 0); + BN_set_negative(&r->Y, 0); + + ret = 1; + + err: + BN_CTX_end(ctx); + return ret; + } + + +/* Computes the sum + * scalar*group->generator + scalars[0]*points[0] + ... + scalars[num-1]*points[num-1] + * gracefully ignoring NULL scalar values. + */ +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 *ctx) + { + BN_CTX *new_ctx = NULL; + int ret = 0; + size_t i; + EC_POINT *p=NULL; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + /* This implementation is more efficient than the wNAF implementation for 2 + * or fewer points. Use the ec_wNAF_mul implementation for 3 or more points, + * or if we can perform a fast multiplication based on precomputation. + */ + if ((scalar && (num > 1)) || (num > 2) || (num == 0 && EC_GROUP_have_precompute_mult(group))) + { + ret = ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx); + goto err; + } + + if ((p = EC_POINT_new(group)) == NULL) goto err; + + if (!EC_POINT_set_to_infinity(group, r)) goto err; + + if (scalar) + { + if (!ec_GF2m_montgomery_point_multiply(group, p, scalar, group->generator, ctx)) goto err; + if (BN_is_negative(scalar)) + if (!group->meth->invert(group, p, ctx)) goto err; + if (!group->meth->add(group, r, r, p, ctx)) goto err; + } + + for (i = 0; i < num; i++) + { + if (!ec_GF2m_montgomery_point_multiply(group, p, scalars[i], points[i], ctx)) goto err; + if (BN_is_negative(scalars[i])) + if (!group->meth->invert(group, p, ctx)) goto err; + if (!group->meth->add(group, r, r, p, ctx)) goto err; + } + + ret = 1; + + err: + if (p) EC_POINT_free(p); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +/* Precomputation for point multiplication: fall back to wNAF methods + * because ec_GF2m_simple_mul() uses ec_wNAF_mul() if appropriate */ + +int ec_GF2m_precompute_mult(EC_GROUP *group, BN_CTX *ctx) + { + return ec_wNAF_precompute_mult(group, ctx); + } + +int ec_GF2m_have_precompute_mult(const EC_GROUP *group) + { + return ec_wNAF_have_precompute_mult(group); + } diff --git a/openssl/crypto/ec/ec2_smpl.c b/openssl/crypto/ec/ec2_smpl.c new file mode 100644 index 000000000..5cd1eac41 --- /dev/null +++ b/openssl/crypto/ec/ec2_smpl.c @@ -0,0 +1,971 @@ +/* crypto/ec/ec2_smpl.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-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). + * + */ + +#include <openssl/err.h> + +#include "ec_lcl.h" + + +const EC_METHOD *EC_GF2m_simple_method(void) + { + static const EC_METHOD ret = { + NID_X9_62_characteristic_two_field, + ec_GF2m_simple_group_init, + ec_GF2m_simple_group_finish, + ec_GF2m_simple_group_clear_finish, + ec_GF2m_simple_group_copy, + ec_GF2m_simple_group_set_curve, + ec_GF2m_simple_group_get_curve, + ec_GF2m_simple_group_get_degree, + ec_GF2m_simple_group_check_discriminant, + ec_GF2m_simple_point_init, + ec_GF2m_simple_point_finish, + ec_GF2m_simple_point_clear_finish, + ec_GF2m_simple_point_copy, + ec_GF2m_simple_point_set_to_infinity, + 0 /* set_Jprojective_coordinates_GFp */, + 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, + ec_GF2m_simple_add, + ec_GF2m_simple_dbl, + ec_GF2m_simple_invert, + ec_GF2m_simple_is_at_infinity, + ec_GF2m_simple_is_on_curve, + ec_GF2m_simple_cmp, + ec_GF2m_simple_make_affine, + ec_GF2m_simple_points_make_affine, + + /* the following three method functions are defined in ec2_mult.c */ + ec_GF2m_simple_mul, + ec_GF2m_precompute_mult, + ec_GF2m_have_precompute_mult, + + ec_GF2m_simple_field_mul, + ec_GF2m_simple_field_sqr, + ec_GF2m_simple_field_div, + 0 /* field_encode */, + 0 /* field_decode */, + 0 /* field_set_to_one */ }; + + return &ret; + } + + +/* Initialize a GF(2^m)-based EC_GROUP structure. + * Note that all other members are handled by EC_GROUP_new. + */ +int ec_GF2m_simple_group_init(EC_GROUP *group) + { + BN_init(&group->field); + BN_init(&group->a); + BN_init(&group->b); + return 1; + } + + +/* Free a GF(2^m)-based EC_GROUP structure. + * Note that all other members are handled by EC_GROUP_free. + */ +void ec_GF2m_simple_group_finish(EC_GROUP *group) + { + BN_free(&group->field); + BN_free(&group->a); + BN_free(&group->b); + } + + +/* Clear and free a GF(2^m)-based EC_GROUP structure. + * Note that all other members are handled by EC_GROUP_clear_free. + */ +void ec_GF2m_simple_group_clear_finish(EC_GROUP *group) + { + BN_clear_free(&group->field); + BN_clear_free(&group->a); + BN_clear_free(&group->b); + group->poly[0] = 0; + group->poly[1] = 0; + group->poly[2] = 0; + group->poly[3] = 0; + group->poly[4] = 0; + } + + +/* Copy a GF(2^m)-based EC_GROUP structure. + * Note that all other members are handled by EC_GROUP_copy. + */ +int ec_GF2m_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) + { + int i; + if (!BN_copy(&dest->field, &src->field)) return 0; + if (!BN_copy(&dest->a, &src->a)) return 0; + if (!BN_copy(&dest->b, &src->b)) return 0; + dest->poly[0] = src->poly[0]; + dest->poly[1] = src->poly[1]; + dest->poly[2] = src->poly[2]; + dest->poly[3] = src->poly[3]; + dest->poly[4] = src->poly[4]; + bn_wexpand(&dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2); + bn_wexpand(&dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2); + 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; + } + + +/* Set the curve parameters of an EC_GROUP structure. */ +int ec_GF2m_simple_group_set_curve(EC_GROUP *group, + const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + int ret = 0, i; + + /* group->field */ + if (!BN_copy(&group->field, p)) goto err; + i = BN_GF2m_poly2arr(&group->field, group->poly, 5); + if ((i != 5) && (i != 3)) + { + ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE, EC_R_UNSUPPORTED_FIELD); + goto err; + } + + /* group->a */ + if (!BN_GF2m_mod_arr(&group->a, a, group->poly)) goto err; + bn_wexpand(&group->a, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2); + for (i = group->a.top; i < group->a.dmax; i++) group->a.d[i] = 0; + + /* group->b */ + if (!BN_GF2m_mod_arr(&group->b, b, group->poly)) goto err; + bn_wexpand(&group->b, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2); + for (i = group->b.top; i < group->b.dmax; i++) group->b.d[i] = 0; + + ret = 1; + err: + return ret; + } + + +/* Get the curve parameters of an EC_GROUP structure. + * If p, a, or b are NULL then there values will not be set but the method will return with success. + */ +int ec_GF2m_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) + { + int ret = 0; + + if (p != NULL) + { + if (!BN_copy(p, &group->field)) return 0; + } + + if (a != NULL) + { + if (!BN_copy(a, &group->a)) goto err; + } + + if (b != NULL) + { + if (!BN_copy(b, &group->b)) goto err; + } + + ret = 1; + + err: + return ret; + } + + +/* Gets the degree of the field. For a curve over GF(2^m) this is the value m. */ +int ec_GF2m_simple_group_get_degree(const EC_GROUP *group) + { + return BN_num_bits(&group->field)-1; + } + + +/* Checks the discriminant of the curve. + * y^2 + x*y = x^3 + a*x^2 + b is an elliptic curve <=> b != 0 (mod p) + */ +int ec_GF2m_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) + { + int ret = 0; + BIGNUM *b; + BN_CTX *new_ctx = NULL; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + { + ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT, ERR_R_MALLOC_FAILURE); + goto err; + } + } + BN_CTX_start(ctx); + b = BN_CTX_get(ctx); + if (b == NULL) goto err; + + if (!BN_GF2m_mod_arr(b, &group->b, group->poly)) goto err; + + /* check the discriminant: + * y^2 + x*y = x^3 + a*x^2 + b is an elliptic curve <=> b != 0 (mod p) + */ + if (BN_is_zero(b)) goto err; + + ret = 1; + +err: + if (ctx != NULL) + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +/* Initializes an EC_POINT. */ +int ec_GF2m_simple_point_init(EC_POINT *point) + { + BN_init(&point->X); + BN_init(&point->Y); + BN_init(&point->Z); + return 1; + } + + +/* Frees an EC_POINT. */ +void ec_GF2m_simple_point_finish(EC_POINT *point) + { + BN_free(&point->X); + BN_free(&point->Y); + BN_free(&point->Z); + } + + +/* Clears and frees an EC_POINT. */ +void ec_GF2m_simple_point_clear_finish(EC_POINT *point) + { + BN_clear_free(&point->X); + BN_clear_free(&point->Y); + BN_clear_free(&point->Z); + point->Z_is_one = 0; + } + + +/* Copy the contents of one EC_POINT into another. Assumes dest is initialized. */ +int ec_GF2m_simple_point_copy(EC_POINT *dest, const EC_POINT *src) + { + if (!BN_copy(&dest->X, &src->X)) return 0; + if (!BN_copy(&dest->Y, &src->Y)) return 0; + if (!BN_copy(&dest->Z, &src->Z)) return 0; + dest->Z_is_one = src->Z_is_one; + + return 1; + } + + +/* Set an EC_POINT to the point at infinity. + * A point at infinity is represented by having Z=0. + */ +int ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point) + { + point->Z_is_one = 0; + BN_zero(&point->Z); + return 1; + } + + +/* Set the coordinates of an EC_POINT using affine coordinates. + * Note that the simple implementation only uses affine coordinates. + */ +int ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx) + { + int ret = 0; + if (x == NULL || y == NULL) + { + ECerr(EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (!BN_copy(&point->X, x)) goto err; + BN_set_negative(&point->X, 0); + if (!BN_copy(&point->Y, y)) goto err; + BN_set_negative(&point->Y, 0); + if (!BN_copy(&point->Z, BN_value_one())) goto err; + BN_set_negative(&point->Z, 0); + point->Z_is_one = 1; + ret = 1; + + err: + return ret; + } + + +/* Gets the affine coordinates of an EC_POINT. + * Note that the simple implementation only uses affine coordinates. + */ +int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, + BIGNUM *x, BIGNUM *y, BN_CTX *ctx) + { + int ret = 0; + + if (EC_POINT_is_at_infinity(group, point)) + { + ECerr(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES, EC_R_POINT_AT_INFINITY); + return 0; + } + + if (BN_cmp(&point->Z, BN_value_one())) + { + ECerr(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (x != NULL) + { + if (!BN_copy(x, &point->X)) goto err; + BN_set_negative(x, 0); + } + if (y != NULL) + { + if (!BN_copy(y, &point->Y)) goto err; + BN_set_negative(y, 0); + } + ret = 1; + + err: + 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. + */ +int ec_GF2m_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + BIGNUM *x0, *y0, *x1, *y1, *x2, *y2, *s, *t; + int ret = 0; + + if (EC_POINT_is_at_infinity(group, a)) + { + if (!EC_POINT_copy(r, b)) return 0; + return 1; + } + + if (EC_POINT_is_at_infinity(group, b)) + { + if (!EC_POINT_copy(r, a)) return 0; + return 1; + } + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + BN_CTX_start(ctx); + x0 = BN_CTX_get(ctx); + y0 = BN_CTX_get(ctx); + x1 = BN_CTX_get(ctx); + y1 = BN_CTX_get(ctx); + x2 = BN_CTX_get(ctx); + y2 = BN_CTX_get(ctx); + s = BN_CTX_get(ctx); + t = BN_CTX_get(ctx); + if (t == NULL) goto err; + + if (a->Z_is_one) + { + if (!BN_copy(x0, &a->X)) goto err; + if (!BN_copy(y0, &a->Y)) goto err; + } + else + { + if (!EC_POINT_get_affine_coordinates_GF2m(group, a, x0, y0, ctx)) goto err; + } + if (b->Z_is_one) + { + if (!BN_copy(x1, &b->X)) goto err; + if (!BN_copy(y1, &b->Y)) goto err; + } + else + { + if (!EC_POINT_get_affine_coordinates_GF2m(group, b, x1, y1, ctx)) goto err; + } + + + if (BN_GF2m_cmp(x0, x1)) + { + if (!BN_GF2m_add(t, x0, x1)) goto err; + if (!BN_GF2m_add(s, y0, y1)) goto err; + if (!group->meth->field_div(group, s, s, t, ctx)) goto err; + if (!group->meth->field_sqr(group, x2, s, ctx)) goto err; + if (!BN_GF2m_add(x2, x2, &group->a)) goto err; + if (!BN_GF2m_add(x2, x2, s)) goto err; + if (!BN_GF2m_add(x2, x2, t)) goto err; + } + else + { + if (BN_GF2m_cmp(y0, y1) || BN_is_zero(x1)) + { + if (!EC_POINT_set_to_infinity(group, r)) goto err; + ret = 1; + goto err; + } + if (!group->meth->field_div(group, s, y1, x1, ctx)) goto err; + if (!BN_GF2m_add(s, s, x1)) goto err; + + if (!group->meth->field_sqr(group, x2, s, ctx)) goto err; + if (!BN_GF2m_add(x2, x2, s)) goto err; + if (!BN_GF2m_add(x2, x2, &group->a)) goto err; + } + + if (!BN_GF2m_add(y2, x1, x2)) goto err; + if (!group->meth->field_mul(group, y2, y2, s, ctx)) goto err; + if (!BN_GF2m_add(y2, y2, x2)) goto err; + if (!BN_GF2m_add(y2, y2, y1)) goto err; + + if (!EC_POINT_set_affine_coordinates_GF2m(group, r, x2, y2, ctx)) goto err; + + ret = 1; + + err: + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +/* Computes 2 * a and stores the result in r. r could be a. + * Uses algorithm A.10.2 of IEEE P1363. + */ +int ec_GF2m_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) + { + return ec_GF2m_simple_add(group, r, a, a, ctx); + } + + +int ec_GF2m_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) + { + if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y)) + /* point is its own inverse */ + return 1; + + if (!EC_POINT_make_affine(group, point, ctx)) return 0; + return BN_GF2m_add(&point->Y, &point->X, &point->Y); + } + + +/* Indicates whether the given point is the point at infinity. */ +int ec_GF2m_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) + { + return BN_is_zero(&point->Z); + } + + +/* Determines whether the given EC_POINT is an actual point on the curve defined + * in the EC_GROUP. A point is valid if it satisfies the Weierstrass equation: + * y^2 + x*y = x^3 + a*x^2 + b. + */ +int ec_GF2m_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) + { + int ret = -1; + BN_CTX *new_ctx = NULL; + BIGNUM *lh, *y2; + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + + if (EC_POINT_is_at_infinity(group, point)) + return 1; + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + + /* only support affine coordinates */ + if (!point->Z_is_one) goto err; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return -1; + } + + BN_CTX_start(ctx); + y2 = BN_CTX_get(ctx); + lh = BN_CTX_get(ctx); + if (lh == NULL) goto err; + + /* We have a curve defined by a Weierstrass equation + * y^2 + x*y = x^3 + a*x^2 + b. + * <=> x^3 + a*x^2 + x*y + b + y^2 = 0 + * <=> ((x + a) * x + y ) * x + b + y^2 = 0 + */ + if (!BN_GF2m_add(lh, &point->X, &group->a)) goto err; + if (!field_mul(group, lh, lh, &point->X, ctx)) goto err; + if (!BN_GF2m_add(lh, lh, &point->Y)) goto err; + if (!field_mul(group, lh, lh, &point->X, ctx)) goto err; + if (!BN_GF2m_add(lh, lh, &group->b)) goto err; + if (!field_sqr(group, y2, &point->Y, ctx)) goto err; + if (!BN_GF2m_add(lh, lh, y2)) goto err; + ret = BN_is_zero(lh); + err: + if (ctx) BN_CTX_end(ctx); + if (new_ctx) BN_CTX_free(new_ctx); + return ret; + } + + +/* Indicates whether two points are equal. + * Return values: + * -1 error + * 0 equal (in affine coordinates) + * 1 not equal + */ +int ec_GF2m_simple_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) + { + BIGNUM *aX, *aY, *bX, *bY; + BN_CTX *new_ctx = NULL; + int ret = -1; + + if (EC_POINT_is_at_infinity(group, a)) + { + return EC_POINT_is_at_infinity(group, b) ? 0 : 1; + } + + if (a->Z_is_one && b->Z_is_one) + { + return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; + } + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return -1; + } + + BN_CTX_start(ctx); + aX = BN_CTX_get(ctx); + aY = BN_CTX_get(ctx); + bX = BN_CTX_get(ctx); + bY = BN_CTX_get(ctx); + if (bY == NULL) goto err; + + if (!EC_POINT_get_affine_coordinates_GF2m(group, a, aX, aY, ctx)) goto err; + if (!EC_POINT_get_affine_coordinates_GF2m(group, b, bX, bY, ctx)) goto err; + ret = ((BN_cmp(aX, bX) == 0) && BN_cmp(aY, bY) == 0) ? 0 : 1; + + err: + if (ctx) BN_CTX_end(ctx); + if (new_ctx) BN_CTX_free(new_ctx); + return ret; + } + + +/* Forces the given EC_POINT to internally use affine coordinates. */ +int ec_GF2m_simple_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + BIGNUM *x, *y; + int ret = 0; + + if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) + return 1; + + 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 (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err; + if (!BN_copy(&point->X, x)) goto err; + if (!BN_copy(&point->Y, y)) goto err; + if (!BN_one(&point->Z)) goto err; + + ret = 1; + + err: + if (ctx) BN_CTX_end(ctx); + if (new_ctx) BN_CTX_free(new_ctx); + return ret; + } + + +/* Forces each of the EC_POINTs in the given array to use affine coordinates. */ +int ec_GF2m_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx) + { + size_t i; + + for (i = 0; i < num; i++) + { + if (!group->meth->make_affine(group, points[i], ctx)) return 0; + } + + return 1; + } + + +/* Wrapper to simple binary polynomial field multiplication implementation. */ +int ec_GF2m_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + return BN_GF2m_mod_mul_arr(r, a, b, group->poly, ctx); + } + + +/* Wrapper to simple binary polynomial field squaring implementation. */ +int ec_GF2m_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) + { + return BN_GF2m_mod_sqr_arr(r, a, group->poly, ctx); + } + + +/* Wrapper to simple binary polynomial field division implementation. */ +int ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + return BN_GF2m_mod_div(r, a, b, &group->field, ctx); + } diff --git a/openssl/crypto/ec/ec2_smpt.c b/openssl/crypto/ec/ec2_smpt.c new file mode 100644 index 000000000..72a8d5705 --- /dev/null +++ b/openssl/crypto/ec/ec2_smpt.c @@ -0,0 +1,141 @@ +/* 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/openssl/crypto/ec/ec_asn1.c b/openssl/crypto/ec/ec_asn1.c new file mode 100644 index 000000000..ae5553985 --- /dev/null +++ b/openssl/crypto/ec/ec_asn1.c @@ -0,0 +1,1429 @@ +/* crypto/ec/ec_asn1.c */ +/* + * Written by Nils Larsch for the OpenSSL project. + */ +/* ==================================================================== + * Copyright (c) 2000-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 + * 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 <string.h> +#include "ec_lcl.h" +#include <openssl/err.h> +#include <openssl/asn1t.h> +#include <openssl/objects.h> + + +int EC_GROUP_get_basis_type(const EC_GROUP *group) + { + int i=0; + + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != + NID_X9_62_characteristic_two_field) + /* everything else is currently not supported */ + return 0; + + while (group->poly[i] != 0) + i++; + + if (i == 4) + return NID_X9_62_ppBasis; + else if (i == 2) + return NID_X9_62_tpBasis; + else + /* everything else is currently not supported */ + return 0; + } + +int EC_GROUP_get_trinomial_basis(const EC_GROUP *group, unsigned int *k) + { + if (group == NULL) + return 0; + + if (EC_GROUP_method_of(group)->group_set_curve != ec_GF2m_simple_group_set_curve + || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] == 0))) + { + ECerr(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + if (k) + *k = group->poly[1]; + + return 1; + } + +int EC_GROUP_get_pentanomial_basis(const EC_GROUP *group, unsigned int *k1, + unsigned int *k2, unsigned int *k3) + { + if (group == NULL) + return 0; + + if (EC_GROUP_method_of(group)->group_set_curve != ec_GF2m_simple_group_set_curve + || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] != 0) && (group->poly[3] != 0) && (group->poly[4] == 0))) + { + ECerr(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + if (k1) + *k1 = group->poly[3]; + if (k2) + *k2 = group->poly[2]; + if (k3) + *k3 = group->poly[1]; + + return 1; + } + + + +/* some structures needed for the asn1 encoding */ +typedef struct x9_62_pentanomial_st { + long k1; + long k2; + long k3; + } X9_62_PENTANOMIAL; + +typedef struct x9_62_characteristic_two_st { + long m; + ASN1_OBJECT *type; + union { + char *ptr; + /* NID_X9_62_onBasis */ + ASN1_NULL *onBasis; + /* NID_X9_62_tpBasis */ + ASN1_INTEGER *tpBasis; + /* NID_X9_62_ppBasis */ + X9_62_PENTANOMIAL *ppBasis; + /* anything else */ + ASN1_TYPE *other; + } p; + } X9_62_CHARACTERISTIC_TWO; + +typedef struct x9_62_fieldid_st { + ASN1_OBJECT *fieldType; + union { + char *ptr; + /* NID_X9_62_prime_field */ + ASN1_INTEGER *prime; + /* NID_X9_62_characteristic_two_field */ + X9_62_CHARACTERISTIC_TWO *char_two; + /* anything else */ + ASN1_TYPE *other; + } p; + } X9_62_FIELDID; + +typedef struct x9_62_curve_st { + ASN1_OCTET_STRING *a; + ASN1_OCTET_STRING *b; + ASN1_BIT_STRING *seed; + } X9_62_CURVE; + +typedef struct ec_parameters_st { + long version; + X9_62_FIELDID *fieldID; + X9_62_CURVE *curve; + ASN1_OCTET_STRING *base; + ASN1_INTEGER *order; + ASN1_INTEGER *cofactor; + } ECPARAMETERS; + +struct ecpk_parameters_st { + int type; + union { + ASN1_OBJECT *named_curve; + ECPARAMETERS *parameters; + ASN1_NULL *implicitlyCA; + } value; + }/* ECPKPARAMETERS */; + +/* SEC1 ECPrivateKey */ +typedef struct ec_privatekey_st { + long version; + ASN1_OCTET_STRING *privateKey; + ECPKPARAMETERS *parameters; + ASN1_BIT_STRING *publicKey; + } EC_PRIVATEKEY; + +/* the OpenSSL ASN.1 definitions */ +ASN1_SEQUENCE(X9_62_PENTANOMIAL) = { + ASN1_SIMPLE(X9_62_PENTANOMIAL, k1, LONG), + ASN1_SIMPLE(X9_62_PENTANOMIAL, k2, LONG), + ASN1_SIMPLE(X9_62_PENTANOMIAL, k3, LONG) +} ASN1_SEQUENCE_END(X9_62_PENTANOMIAL) + +DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_PENTANOMIAL) + +ASN1_ADB_TEMPLATE(char_two_def) = ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.other, ASN1_ANY); + +ASN1_ADB(X9_62_CHARACTERISTIC_TWO) = { + ADB_ENTRY(NID_X9_62_onBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.onBasis, ASN1_NULL)), + ADB_ENTRY(NID_X9_62_tpBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.tpBasis, ASN1_INTEGER)), + ADB_ENTRY(NID_X9_62_ppBasis, ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, p.ppBasis, X9_62_PENTANOMIAL)) +} ASN1_ADB_END(X9_62_CHARACTERISTIC_TWO, 0, type, 0, &char_two_def_tt, NULL); + +ASN1_SEQUENCE(X9_62_CHARACTERISTIC_TWO) = { + ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, m, LONG), + ASN1_SIMPLE(X9_62_CHARACTERISTIC_TWO, type, ASN1_OBJECT), + ASN1_ADB_OBJECT(X9_62_CHARACTERISTIC_TWO) +} ASN1_SEQUENCE_END(X9_62_CHARACTERISTIC_TWO) + +DECLARE_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X9_62_CHARACTERISTIC_TWO) + +ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY); + +ASN1_ADB(X9_62_FIELDID) = { + ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)), + ADB_ENTRY(NID_X9_62_characteristic_two_field, ASN1_SIMPLE(X9_62_FIELDID, p.char_two, X9_62_CHARACTERISTIC_TWO)) +} ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL); + +ASN1_SEQUENCE(X9_62_FIELDID) = { + ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT), + ASN1_ADB_OBJECT(X9_62_FIELDID) +} ASN1_SEQUENCE_END(X9_62_FIELDID) + +ASN1_SEQUENCE(X9_62_CURVE) = { + ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING), + ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING), + ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(X9_62_CURVE) + +ASN1_SEQUENCE(ECPARAMETERS) = { + ASN1_SIMPLE(ECPARAMETERS, version, LONG), + ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID), + ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE), + ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING), + ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER), + ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER) +} ASN1_SEQUENCE_END(ECPARAMETERS) + +DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS) + +ASN1_CHOICE(ECPKPARAMETERS) = { + ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT), + ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS), + ASN1_SIMPLE(ECPKPARAMETERS, value.implicitlyCA, ASN1_NULL) +} ASN1_CHOICE_END(ECPKPARAMETERS) + +DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS) +IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS) + +ASN1_SEQUENCE(EC_PRIVATEKEY) = { + ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG), + ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING), + ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0), + ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1) +} ASN1_SEQUENCE_END(EC_PRIVATEKEY) + +DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY) +IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY) + +/* some declarations of internal function */ + +/* ec_asn1_group2field() sets the values in a X9_62_FIELDID object */ +static int ec_asn1_group2fieldid(const EC_GROUP *, X9_62_FIELDID *); +/* ec_asn1_group2curve() sets the values in a X9_62_CURVE object */ +static int ec_asn1_group2curve(const EC_GROUP *, X9_62_CURVE *); +/* ec_asn1_parameters2group() creates a EC_GROUP object from a + * ECPARAMETERS object */ +static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *); +/* ec_asn1_group2parameters() creates a ECPARAMETERS object from a + * EC_GROUP object */ +static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *,ECPARAMETERS *); +/* ec_asn1_pkparameters2group() creates a EC_GROUP object from a + * ECPKPARAMETERS object */ +static EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *); +/* ec_asn1_group2pkparameters() creates a ECPKPARAMETERS object from a + * EC_GROUP object */ +static ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *, + ECPKPARAMETERS *); + + +/* the function definitions */ + +static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field) + { + int ok=0, nid; + BIGNUM *tmp = NULL; + + if (group == NULL || field == NULL) + return 0; + + /* clear the old values (if necessary) */ + if (field->fieldType != NULL) + ASN1_OBJECT_free(field->fieldType); + if (field->p.other != NULL) + ASN1_TYPE_free(field->p.other); + + nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); + /* set OID for the field */ + if ((field->fieldType = OBJ_nid2obj(nid)) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB); + goto err; + } + + if (nid == NID_X9_62_prime_field) + { + if ((tmp = BN_new()) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); + goto err; + } + /* the parameters are specified by the prime number p */ + if (!EC_GROUP_get_curve_GFp(group, tmp, NULL, NULL, NULL)) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB); + goto err; + } + /* set the prime number */ + field->p.prime = BN_to_ASN1_INTEGER(tmp,NULL); + if (field->p.prime == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB); + goto err; + } + } + else /* nid == NID_X9_62_characteristic_two_field */ + { + int field_type; + X9_62_CHARACTERISTIC_TWO *char_two; + + field->p.char_two = X9_62_CHARACTERISTIC_TWO_new(); + char_two = field->p.char_two; + + if (char_two == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); + goto err; + } + + char_two->m = (long)EC_GROUP_get_degree(group); + + field_type = EC_GROUP_get_basis_type(group); + + if (field_type == 0) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_EC_LIB); + goto err; + } + /* set base type OID */ + if ((char_two->type = OBJ_nid2obj(field_type)) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_OBJ_LIB); + goto err; + } + + if (field_type == NID_X9_62_tpBasis) + { + unsigned int k; + + if (!EC_GROUP_get_trinomial_basis(group, &k)) + goto err; + + char_two->p.tpBasis = ASN1_INTEGER_new(); + if (!char_two->p.tpBasis) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!ASN1_INTEGER_set(char_two->p.tpBasis, (long)k)) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, + ERR_R_ASN1_LIB); + goto err; + } + } + else if (field_type == NID_X9_62_ppBasis) + { + unsigned int k1, k2, k3; + + if (!EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3)) + goto err; + + char_two->p.ppBasis = X9_62_PENTANOMIAL_new(); + if (!char_two->p.ppBasis) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* set k? values */ + char_two->p.ppBasis->k1 = (long)k1; + char_two->p.ppBasis->k2 = (long)k2; + char_two->p.ppBasis->k3 = (long)k3; + } + else /* field_type == NID_X9_62_onBasis */ + { + /* for ONB the parameters are (asn1) NULL */ + char_two->p.onBasis = ASN1_NULL_new(); + if (!char_two->p.onBasis) + { + ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_MALLOC_FAILURE); + goto err; + } + } + } + + ok = 1; + +err : if (tmp) + BN_free(tmp); + return(ok); +} + +static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve) + { + int ok=0, nid; + BIGNUM *tmp_1=NULL, *tmp_2=NULL; + unsigned char *buffer_1=NULL, *buffer_2=NULL, + *a_buf=NULL, *b_buf=NULL; + size_t len_1, len_2; + unsigned char char_zero = 0; + + if (!group || !curve || !curve->a || !curve->b) + return 0; + + if ((tmp_1 = BN_new()) == NULL || (tmp_2 = BN_new()) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE); + goto err; + } + + nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); + + /* get a and b */ + if (nid == NID_X9_62_prime_field) + { + if (!EC_GROUP_get_curve_GFp(group, NULL, tmp_1, tmp_2, NULL)) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB); + goto err; + } + } + else /* nid == NID_X9_62_characteristic_two_field */ + { + if (!EC_GROUP_get_curve_GF2m(group, NULL, tmp_1, tmp_2, NULL)) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_EC_LIB); + goto err; + } + } + + len_1 = (size_t)BN_num_bytes(tmp_1); + len_2 = (size_t)BN_num_bytes(tmp_2); + + if (len_1 == 0) + { + /* len_1 == 0 => a == 0 */ + a_buf = &char_zero; + len_1 = 1; + } + else + { + if ((buffer_1 = OPENSSL_malloc(len_1)) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, + ERR_R_MALLOC_FAILURE); + goto err; + } + if ( (len_1 = BN_bn2bin(tmp_1, buffer_1)) == 0) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB); + goto err; + } + a_buf = buffer_1; + } + + if (len_2 == 0) + { + /* len_2 == 0 => b == 0 */ + b_buf = &char_zero; + len_2 = 1; + } + else + { + if ((buffer_2 = OPENSSL_malloc(len_2)) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, + ERR_R_MALLOC_FAILURE); + goto err; + } + if ( (len_2 = BN_bn2bin(tmp_2, buffer_2)) == 0) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_BN_LIB); + goto err; + } + b_buf = buffer_2; + } + + /* set a and b */ + if (!M_ASN1_OCTET_STRING_set(curve->a, a_buf, len_1) || + !M_ASN1_OCTET_STRING_set(curve->b, b_buf, len_2)) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB); + goto err; + } + + /* set the seed (optional) */ + if (group->seed) + { + if (!curve->seed) + if ((curve->seed = ASN1_BIT_STRING_new()) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_MALLOC_FAILURE); + goto err; + } + curve->seed->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + curve->seed->flags |= ASN1_STRING_FLAG_BITS_LEFT; + if (!ASN1_BIT_STRING_set(curve->seed, group->seed, + (int)group->seed_len)) + { + ECerr(EC_F_EC_ASN1_GROUP2CURVE, ERR_R_ASN1_LIB); + goto err; + } + } + else + { + if (curve->seed) + { + ASN1_BIT_STRING_free(curve->seed); + curve->seed = NULL; + } + } + + ok = 1; + +err: if (buffer_1) + OPENSSL_free(buffer_1); + if (buffer_2) + OPENSSL_free(buffer_2); + if (tmp_1) + BN_free(tmp_1); + if (tmp_2) + BN_free(tmp_2); + return(ok); + } + +static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *group, + ECPARAMETERS *param) + { + int ok=0; + size_t len=0; + ECPARAMETERS *ret=NULL; + BIGNUM *tmp=NULL; + unsigned char *buffer=NULL; + const EC_POINT *point=NULL; + point_conversion_form_t form; + + if ((tmp = BN_new()) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (param == NULL) + { + if ((ret = ECPARAMETERS_new()) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, + ERR_R_MALLOC_FAILURE); + goto err; + } + } + else + ret = param; + + /* set the version (always one) */ + ret->version = (long)0x1; + + /* set the fieldID */ + if (!ec_asn1_group2fieldid(group, ret->fieldID)) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB); + goto err; + } + + /* set the curve */ + if (!ec_asn1_group2curve(group, ret->curve)) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB); + goto err; + } + + /* set the base point */ + if ((point = EC_GROUP_get0_generator(group)) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, EC_R_UNDEFINED_GENERATOR); + goto err; + } + + form = EC_GROUP_get_point_conversion_form(group); + + len = EC_POINT_point2oct(group, point, form, NULL, len, NULL); + if (len == 0) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB); + goto err; + } + if ((buffer = OPENSSL_malloc(len)) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!EC_POINT_point2oct(group, point, form, buffer, len, NULL)) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB); + goto err; + } + if (ret->base == NULL && (ret->base = ASN1_OCTET_STRING_new()) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!ASN1_OCTET_STRING_set(ret->base, buffer, len)) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB); + goto err; + } + + /* set the order */ + if (!EC_GROUP_get_order(group, tmp, NULL)) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB); + goto err; + } + ret->order = BN_to_ASN1_INTEGER(tmp, ret->order); + if (ret->order == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB); + goto err; + } + + /* set the cofactor (optional) */ + if (EC_GROUP_get_cofactor(group, tmp, NULL)) + { + ret->cofactor = BN_to_ASN1_INTEGER(tmp, ret->cofactor); + if (ret->cofactor == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_ASN1_LIB); + goto err; + } + } + + ok = 1; + +err : if(!ok) + { + if (ret && !param) + ECPARAMETERS_free(ret); + ret = NULL; + } + if (tmp) + BN_free(tmp); + if (buffer) + OPENSSL_free(buffer); + return(ret); + } + +ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *group, + ECPKPARAMETERS *params) + { + int ok = 1, tmp; + ECPKPARAMETERS *ret = params; + + if (ret == NULL) + { + if ((ret = ECPKPARAMETERS_new()) == NULL) + { + ECerr(EC_F_EC_ASN1_GROUP2PKPARAMETERS, + ERR_R_MALLOC_FAILURE); + return NULL; + } + } + else + { + if (ret->type == 0 && ret->value.named_curve) + ASN1_OBJECT_free(ret->value.named_curve); + else if (ret->type == 1 && ret->value.parameters) + ECPARAMETERS_free(ret->value.parameters); + } + + if (EC_GROUP_get_asn1_flag(group)) + { + /* use the asn1 OID to describe the + * the elliptic curve parameters + */ + tmp = EC_GROUP_get_curve_name(group); + if (tmp) + { + ret->type = 0; + if ((ret->value.named_curve = OBJ_nid2obj(tmp)) == NULL) + ok = 0; + } + else + /* we don't kmow the nid => ERROR */ + ok = 0; + } + else + { + /* use the ECPARAMETERS structure */ + ret->type = 1; + if ((ret->value.parameters = ec_asn1_group2parameters( + group, NULL)) == NULL) + ok = 0; + } + + if (!ok) + { + ECPKPARAMETERS_free(ret); + return NULL; + } + return ret; + } + +static EC_GROUP *ec_asn1_parameters2group(const ECPARAMETERS *params) + { + int ok = 0, tmp; + EC_GROUP *ret = NULL; + BIGNUM *p = NULL, *a = NULL, *b = NULL; + EC_POINT *point=NULL; + long field_bits; + + if (!params->fieldID || !params->fieldID->fieldType || + !params->fieldID->p.ptr) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR); + goto err; + } + + /* now extract the curve parameters a and b */ + if (!params->curve || !params->curve->a || + !params->curve->a->data || !params->curve->b || + !params->curve->b->data) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR); + goto err; + } + a = BN_bin2bn(params->curve->a->data, params->curve->a->length, NULL); + if (a == NULL) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_BN_LIB); + goto err; + } + b = BN_bin2bn(params->curve->b->data, params->curve->b->length, NULL); + if (b == NULL) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_BN_LIB); + goto err; + } + + /* get the field parameters */ + tmp = OBJ_obj2nid(params->fieldID->fieldType); + + if (tmp == NID_X9_62_characteristic_two_field) + { + X9_62_CHARACTERISTIC_TWO *char_two; + + char_two = params->fieldID->p.char_two; + + field_bits = char_two->m; + if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_FIELD_TOO_LARGE); + goto err; + } + + if ((p = BN_new()) == NULL) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* get the base type */ + tmp = OBJ_obj2nid(char_two->type); + + if (tmp == NID_X9_62_tpBasis) + { + long tmp_long; + + if (!char_two->p.tpBasis) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR); + goto err; + } + + tmp_long = ASN1_INTEGER_get(char_two->p.tpBasis); + + if (!(char_two->m > tmp_long && tmp_long > 0)) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_TRINOMIAL_BASIS); + goto err; + } + + /* create the polynomial */ + if (!BN_set_bit(p, (int)char_two->m)) + goto err; + if (!BN_set_bit(p, (int)tmp_long)) + goto err; + if (!BN_set_bit(p, 0)) + goto err; + } + else if (tmp == NID_X9_62_ppBasis) + { + X9_62_PENTANOMIAL *penta; + + penta = char_two->p.ppBasis; + if (!penta) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR); + goto err; + } + + if (!(char_two->m > penta->k3 && penta->k3 > penta->k2 && penta->k2 > penta->k1 && penta->k1 > 0)) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_PENTANOMIAL_BASIS); + goto err; + } + + /* create the polynomial */ + if (!BN_set_bit(p, (int)char_two->m)) goto err; + if (!BN_set_bit(p, (int)penta->k1)) goto err; + if (!BN_set_bit(p, (int)penta->k2)) goto err; + if (!BN_set_bit(p, (int)penta->k3)) goto err; + if (!BN_set_bit(p, 0)) goto err; + } + else if (tmp == NID_X9_62_onBasis) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_NOT_IMPLEMENTED); + goto err; + } + else /* error */ + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR); + goto err; + } + + /* create the EC_GROUP structure */ + ret = EC_GROUP_new_curve_GF2m(p, a, b, NULL); + } + else if (tmp == NID_X9_62_prime_field) + { + /* we have a curve over a prime field */ + /* extract the prime number */ + if (!params->fieldID->p.prime) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR); + goto err; + } + p = ASN1_INTEGER_to_BN(params->fieldID->p.prime, NULL); + if (p == NULL) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB); + goto err; + } + + if (BN_is_negative(p) || BN_is_zero(p)) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_FIELD); + goto err; + } + + field_bits = BN_num_bits(p); + if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_FIELD_TOO_LARGE); + goto err; + } + + /* create the EC_GROUP structure */ + ret = EC_GROUP_new_curve_GFp(p, a, b, NULL); + } + else + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_FIELD); + goto err; + } + + if (ret == NULL) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB); + goto err; + } + + /* extract seed (optional) */ + if (params->curve->seed != NULL) + { + if (ret->seed != NULL) + OPENSSL_free(ret->seed); + if (!(ret->seed = OPENSSL_malloc(params->curve->seed->length))) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, + ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(ret->seed, params->curve->seed->data, + params->curve->seed->length); + ret->seed_len = params->curve->seed->length; + } + + if (!params->order || !params->base || !params->base->data) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_ASN1_ERROR); + goto err; + } + + if ((point = EC_POINT_new(ret)) == NULL) goto err; + + /* set the point conversion form */ + EC_GROUP_set_point_conversion_form(ret, (point_conversion_form_t) + (params->base->data[0] & ~0x01)); + + /* extract the ec point */ + if (!EC_POINT_oct2point(ret, point, params->base->data, + params->base->length, NULL)) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB); + goto err; + } + + /* extract the order */ + if ((a = ASN1_INTEGER_to_BN(params->order, a)) == NULL) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB); + goto err; + } + if (BN_is_negative(a) || BN_is_zero(a)) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_GROUP_ORDER); + goto err; + } + if (BN_num_bits(a) > (int)field_bits + 1) /* Hasse bound */ + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, EC_R_INVALID_GROUP_ORDER); + goto err; + } + + /* extract the cofactor (optional) */ + if (params->cofactor == NULL) + { + if (b) + { + BN_free(b); + b = NULL; + } + } + else + if ((b = ASN1_INTEGER_to_BN(params->cofactor, b)) == NULL) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_ASN1_LIB); + goto err; + } + /* set the generator, order and cofactor (if present) */ + if (!EC_GROUP_set_generator(ret, point, a, b)) + { + ECerr(EC_F_EC_ASN1_PARAMETERS2GROUP, ERR_R_EC_LIB); + goto err; + } + + ok = 1; + +err: if (!ok) + { + if (ret) + EC_GROUP_clear_free(ret); + ret = NULL; + } + + if (p) + BN_free(p); + if (a) + BN_free(a); + if (b) + BN_free(b); + if (point) + EC_POINT_free(point); + return(ret); +} + +EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params) + { + EC_GROUP *ret=NULL; + int tmp=0; + + if (params == NULL) + { + ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, + EC_R_MISSING_PARAMETERS); + return NULL; + } + + if (params->type == 0) + { /* the curve is given by an OID */ + tmp = OBJ_obj2nid(params->value.named_curve); + if ((ret = EC_GROUP_new_by_curve_name(tmp)) == NULL) + { + ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, + EC_R_EC_GROUP_NEW_BY_NAME_FAILURE); + return NULL; + } + EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_NAMED_CURVE); + } + else if (params->type == 1) + { /* the parameters are given by a ECPARAMETERS + * structure */ + ret = ec_asn1_parameters2group(params->value.parameters); + if (!ret) + { + ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, ERR_R_EC_LIB); + return NULL; + } + EC_GROUP_set_asn1_flag(ret, 0x0); + } + else if (params->type == 2) + { /* implicitlyCA */ + return NULL; + } + else + { + ECerr(EC_F_EC_ASN1_PKPARAMETERS2GROUP, EC_R_ASN1_ERROR); + return NULL; + } + + return ret; + } + +/* EC_GROUP <-> DER encoding of ECPKPARAMETERS */ + +EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len) + { + EC_GROUP *group = NULL; + ECPKPARAMETERS *params = NULL; + + if ((params = d2i_ECPKPARAMETERS(NULL, in, len)) == NULL) + { + ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_D2I_ECPKPARAMETERS_FAILURE); + ECPKPARAMETERS_free(params); + return NULL; + } + + if ((group = ec_asn1_pkparameters2group(params)) == NULL) + { + ECerr(EC_F_D2I_ECPKPARAMETERS, EC_R_PKPARAMETERS2GROUP_FAILURE); + return NULL; + } + + + if (a && *a) + EC_GROUP_clear_free(*a); + if (a) + *a = group; + + ECPKPARAMETERS_free(params); + return(group); + } + +int i2d_ECPKParameters(const EC_GROUP *a, unsigned char **out) + { + int ret=0; + ECPKPARAMETERS *tmp = ec_asn1_group2pkparameters(a, NULL); + if (tmp == NULL) + { + ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_GROUP2PKPARAMETERS_FAILURE); + return 0; + } + if ((ret = i2d_ECPKPARAMETERS(tmp, out)) == 0) + { + ECerr(EC_F_I2D_ECPKPARAMETERS, EC_R_I2D_ECPKPARAMETERS_FAILURE); + ECPKPARAMETERS_free(tmp); + return 0; + } + ECPKPARAMETERS_free(tmp); + return(ret); + } + +/* some EC_KEY functions */ + +EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len) + { + int ok=0; + EC_KEY *ret=NULL; + EC_PRIVATEKEY *priv_key=NULL; + + if ((priv_key = EC_PRIVATEKEY_new()) == NULL) + { + ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if ((priv_key = d2i_EC_PRIVATEKEY(&priv_key, in, len)) == NULL) + { + ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB); + EC_PRIVATEKEY_free(priv_key); + return NULL; + } + + if (a == NULL || *a == NULL) + { + if ((ret = EC_KEY_new()) == NULL) + { + ECerr(EC_F_D2I_ECPRIVATEKEY, + ERR_R_MALLOC_FAILURE); + goto err; + } + if (a) + *a = ret; + } + else + ret = *a; + + if (priv_key->parameters) + { + if (ret->group) + EC_GROUP_clear_free(ret->group); + ret->group = ec_asn1_pkparameters2group(priv_key->parameters); + } + + if (ret->group == NULL) + { + ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB); + goto err; + } + + ret->version = priv_key->version; + + if (priv_key->privateKey) + { + ret->priv_key = BN_bin2bn( + M_ASN1_STRING_data(priv_key->privateKey), + M_ASN1_STRING_length(priv_key->privateKey), + ret->priv_key); + if (ret->priv_key == NULL) + { + ECerr(EC_F_D2I_ECPRIVATEKEY, + ERR_R_BN_LIB); + goto err; + } + } + else + { + ECerr(EC_F_D2I_ECPRIVATEKEY, + EC_R_MISSING_PRIVATE_KEY); + goto err; + } + + if (priv_key->publicKey) + { + const unsigned char *pub_oct; + size_t pub_oct_len; + + if (ret->pub_key) + EC_POINT_clear_free(ret->pub_key); + ret->pub_key = EC_POINT_new(ret->group); + if (ret->pub_key == NULL) + { + ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB); + goto err; + } + pub_oct = M_ASN1_STRING_data(priv_key->publicKey); + pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey); + /* save the point conversion form */ + ret->conv_form = (point_conversion_form_t)(pub_oct[0] & ~0x01); + if (!EC_POINT_oct2point(ret->group, ret->pub_key, + pub_oct, pub_oct_len, NULL)) + { + ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB); + goto err; + } + } + + ok = 1; +err: + if (!ok) + { + if (ret) + EC_KEY_free(ret); + ret = NULL; + } + + if (priv_key) + EC_PRIVATEKEY_free(priv_key); + + return(ret); + } + +int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out) + { + int ret=0, ok=0; + unsigned char *buffer=NULL; + size_t buf_len=0, tmp_len; + EC_PRIVATEKEY *priv_key=NULL; + + if (a == NULL || a->group == NULL || a->priv_key == NULL) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, + ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + if ((priv_key = EC_PRIVATEKEY_new()) == NULL) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, + ERR_R_MALLOC_FAILURE); + goto err; + } + + priv_key->version = a->version; + + buf_len = (size_t)BN_num_bytes(a->priv_key); + buffer = OPENSSL_malloc(buf_len); + if (buffer == NULL) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BN_bn2bin(a->priv_key, buffer)) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_BN_LIB); + goto err; + } + + if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len)) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB); + goto err; + } + + if (!(a->enc_flag & EC_PKEY_NO_PARAMETERS)) + { + if ((priv_key->parameters = ec_asn1_group2pkparameters( + a->group, priv_key->parameters)) == NULL) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB); + goto err; + } + } + + if (!(a->enc_flag & EC_PKEY_NO_PUBKEY)) + { + priv_key->publicKey = M_ASN1_BIT_STRING_new(); + if (priv_key->publicKey == NULL) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, + ERR_R_MALLOC_FAILURE); + goto err; + } + + tmp_len = EC_POINT_point2oct(a->group, a->pub_key, + a->conv_form, NULL, 0, NULL); + + if (tmp_len > buf_len) + { + unsigned char *tmp_buffer = OPENSSL_realloc(buffer, tmp_len); + if (!tmp_buffer) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_MALLOC_FAILURE); + goto err; + } + buffer = tmp_buffer; + buf_len = tmp_len; + } + + if (!EC_POINT_point2oct(a->group, a->pub_key, + a->conv_form, buffer, buf_len, NULL)) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB); + goto err; + } + + priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT; + if (!M_ASN1_BIT_STRING_set(priv_key->publicKey, buffer, + buf_len)) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_ASN1_LIB); + goto err; + } + } + + if ((ret = i2d_EC_PRIVATEKEY(priv_key, out)) == 0) + { + ECerr(EC_F_I2D_ECPRIVATEKEY, ERR_R_EC_LIB); + goto err; + } + ok=1; +err: + if (buffer) + OPENSSL_free(buffer); + if (priv_key) + EC_PRIVATEKEY_free(priv_key); + return(ok?ret:0); + } + +int i2d_ECParameters(EC_KEY *a, unsigned char **out) + { + if (a == NULL) + { + ECerr(EC_F_I2D_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + return i2d_ECPKParameters(a->group, out); + } + +EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len) + { + EC_KEY *ret; + + if (in == NULL || *in == NULL) + { + ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (a == NULL || *a == NULL) + { + if ((ret = EC_KEY_new()) == NULL) + { + ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_MALLOC_FAILURE); + return NULL; + } + if (a) + *a = ret; + } + else + ret = *a; + + if (!d2i_ECPKParameters(&ret->group, in, len)) + { + ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_EC_LIB); + return NULL; + } + + return ret; + } + +EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len) + { + EC_KEY *ret=NULL; + + if (a == NULL || (*a) == NULL || (*a)->group == NULL) + { + /* sorry, but a EC_GROUP-structur is necessary + * to set the public key */ + ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + ret = *a; + if (ret->pub_key == NULL && + (ret->pub_key = EC_POINT_new(ret->group)) == NULL) + { + ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_MALLOC_FAILURE); + return 0; + } + if (!EC_POINT_oct2point(ret->group, ret->pub_key, *in, len, NULL)) + { + ECerr(EC_F_O2I_ECPUBLICKEY, ERR_R_EC_LIB); + return 0; + } + /* save the point conversion form */ + ret->conv_form = (point_conversion_form_t)(*in[0] & ~0x01); + *in += len; + return ret; + } + +int i2o_ECPublicKey(EC_KEY *a, unsigned char **out) + { + size_t buf_len=0; + int new_buffer = 0; + + if (a == NULL) + { + ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + buf_len = EC_POINT_point2oct(a->group, a->pub_key, + a->conv_form, NULL, 0, NULL); + + if (out == NULL || buf_len == 0) + /* out == NULL => just return the length of the octet string */ + return buf_len; + + if (*out == NULL) + { + if ((*out = OPENSSL_malloc(buf_len)) == NULL) + { + ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_MALLOC_FAILURE); + return 0; + } + new_buffer = 1; + } + if (!EC_POINT_point2oct(a->group, a->pub_key, a->conv_form, + *out, buf_len, NULL)) + { + ECerr(EC_F_I2O_ECPUBLICKEY, ERR_R_EC_LIB); + OPENSSL_free(*out); + *out = NULL; + return 0; + } + if (!new_buffer) + *out += buf_len; + return buf_len; + } diff --git a/openssl/crypto/ec/ec_check.c b/openssl/crypto/ec/ec_check.c new file mode 100644 index 000000000..0e316b4b3 --- /dev/null +++ b/openssl/crypto/ec/ec_check.c @@ -0,0 +1,123 @@ +/* crypto/ec/ec_check.c */ +/* ==================================================================== + * 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). + * + */ + +#include "ec_lcl.h" +#include <openssl/err.h> + +int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx) + { + int ret = 0; + BIGNUM *order; + BN_CTX *new_ctx = NULL; + EC_POINT *point = NULL; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + { + ECerr(EC_F_EC_GROUP_CHECK, ERR_R_MALLOC_FAILURE); + goto err; + } + } + BN_CTX_start(ctx); + if ((order = BN_CTX_get(ctx)) == NULL) goto err; + + /* check the discriminant */ + if (!EC_GROUP_check_discriminant(group, ctx)) + { + ECerr(EC_F_EC_GROUP_CHECK, EC_R_DISCRIMINANT_IS_ZERO); + goto err; + } + + /* check the generator */ + if (group->generator == NULL) + { + ECerr(EC_F_EC_GROUP_CHECK, EC_R_UNDEFINED_GENERATOR); + goto err; + } + if (!EC_POINT_is_on_curve(group, group->generator, ctx)) + { + ECerr(EC_F_EC_GROUP_CHECK, EC_R_POINT_IS_NOT_ON_CURVE); + goto err; + } + + /* check the order of the generator */ + if ((point = EC_POINT_new(group)) == NULL) goto err; + if (!EC_GROUP_get_order(group, order, ctx)) goto err; + if (BN_is_zero(order)) + { + ECerr(EC_F_EC_GROUP_CHECK, EC_R_UNDEFINED_ORDER); + goto err; + } + + if (!EC_POINT_mul(group, point, order, NULL, NULL, ctx)) goto err; + if (!EC_POINT_is_at_infinity(group, point)) + { + ECerr(EC_F_EC_GROUP_CHECK, EC_R_INVALID_GROUP_ORDER); + goto err; + } + + ret = 1; + +err: + if (ctx != NULL) + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + if (point) + EC_POINT_free(point); + return ret; + } diff --git a/openssl/crypto/ec/ec_curve.c b/openssl/crypto/ec/ec_curve.c new file mode 100644 index 000000000..beac20969 --- /dev/null +++ b/openssl/crypto/ec/ec_curve.c @@ -0,0 +1,1270 @@ +/* crypto/ec/ec_curve.c */ +/* + * Written by Nils Larsch for the OpenSSL project. + */ +/* ==================================================================== + * Copyright (c) 1998-2004 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 the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#include "ec_lcl.h" +#include <openssl/err.h> +#include <openssl/obj_mac.h> + +typedef struct ec_curve_data_st { + 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 */ +} 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 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 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 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" + }; +/* 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 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 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 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 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 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" + }; +/* 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 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 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 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 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 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 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 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 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 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" + }; + +/* 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 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 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" + }; + +/* 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 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 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 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 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 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, +/* 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, +#endif + "SECG curve over a 163 bit binary field" + }; + +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) + */ +#if 0 + _EC_NIST_CHAR2_163B_SEED, 20, +#else + NULL, 0, +#endif + "NIST/SECG curve over a 163 bit binary field" + }; + +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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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" + }; + +/* IPSec curves */ +/* NOTE: The of curves over a extension field of non prime degree + * is not recommended (Weil-descent). + * 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!" + }; + +/* NOTE: The of curves over a extension field of non prime degree + * is not recommended (Weil-descent). + * 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!" + }; + +typedef struct _ec_list_element_st { + int nid; + const EC_CURVE_DATA *data; + } ec_list_element; + +static const ec_list_element curve_list[] = { + /* 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}, + /* 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}, + /* SECG secp256r1 is the same as X9.62 prime256v1 and hence omitted */ + { NID_secp384r1, &_EC_NIST_PRIME_384}, + { NID_secp521r1, &_EC_NIST_PRIME_521}, + /* 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}, + /* 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 }, + /* 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}, + /* 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}, + /* IPSec curves */ + { NID_ipsec3, &_EC_IPSEC_155_ID3}, + { NID_ipsec4, &_EC_IPSEC_185_ID4}, +}; + +static size_t curve_list_length = sizeof(curve_list)/sizeof(ec_list_element); + +static EC_GROUP *ec_group_new_from_data(const EC_CURVE_DATA *data) + { + 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; + int ok=0; + + 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)) + { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB); + goto err; + } + + if (data->field_type == NID_X9_62_prime_field) + { + if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) + { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); + goto err; + } + } + 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; + } + } + + 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)) + { + 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)) + { + 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)) + { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB); + goto err; + } + if (!EC_GROUP_set_generator(group, P, order, x)) + { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); + goto err; + } + if (data->seed) + { + if (!EC_GROUP_set_seed(group, data->seed, data->seed_len)) + { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); + goto err; + } + } + ok=1; +err: + if (!ok) + { + EC_GROUP_free(group); + group = NULL; + } + if (P) + EC_POINT_free(P); + if (ctx) + BN_CTX_free(ctx); + if (p) + BN_free(p); + if (a) + BN_free(a); + if (b) + BN_free(b); + if (order) + BN_free(order); + if (x) + BN_free(x); + if (y) + BN_free(y); + return group; + } + +EC_GROUP *EC_GROUP_new_by_curve_name(int nid) + { + size_t i; + EC_GROUP *ret = NULL; + + if (nid <= 0) + return NULL; + + for (i=0; i<curve_list_length; i++) + if (curve_list[i].nid == nid) + { + ret = ec_group_new_from_data(curve_list[i].data); + break; + } + + if (ret == NULL) + { + ECerr(EC_F_EC_GROUP_NEW_BY_CURVE_NAME, EC_R_UNKNOWN_GROUP); + return NULL; + } + + EC_GROUP_set_curve_name(ret, nid); + + return ret; + } + +size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems) + { + size_t i, min; + + if (r == NULL || nitems == 0) + return curve_list_length; + + min = nitems < curve_list_length ? nitems : curve_list_length; + + for (i = 0; i < min; i++) + { + r[i].nid = curve_list[i].nid; + r[i].comment = curve_list[i].data->comment; + } + + return curve_list_length; + } diff --git a/openssl/crypto/ec/ec_cvt.c b/openssl/crypto/ec/ec_cvt.c new file mode 100644 index 000000000..d45640bab --- /dev/null +++ b/openssl/crypto/ec/ec_cvt.c @@ -0,0 +1,144 @@ +/* crypto/ec/ec_cvt.c */ +/* + * Originally 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 the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#include <openssl/err.h> +#include "ec_lcl.h" + + +EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + const EC_METHOD *meth; + EC_GROUP *ret; + + meth = EC_GFp_nist_method(); + + ret = EC_GROUP_new(meth); + if (ret == NULL) + return NULL; + + if (!EC_GROUP_set_curve_GFp(ret, p, a, b, ctx)) + { + unsigned long err; + + err = ERR_peek_last_error(); + + if (!(ERR_GET_LIB(err) == ERR_LIB_EC && + ((ERR_GET_REASON(err) == EC_R_NOT_A_NIST_PRIME) || + (ERR_GET_REASON(err) == EC_R_NOT_A_SUPPORTED_NIST_PRIME)))) + { + /* real error */ + + EC_GROUP_clear_free(ret); + return NULL; + } + + + /* not an actual error, we just cannot use EC_GFp_nist_method */ + + ERR_clear_error(); + + EC_GROUP_clear_free(ret); + meth = EC_GFp_mont_method(); + + ret = EC_GROUP_new(meth); + if (ret == NULL) + return NULL; + + if (!EC_GROUP_set_curve_GFp(ret, p, a, b, ctx)) + { + EC_GROUP_clear_free(ret); + return NULL; + } + } + + return ret; + } + + +EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + const EC_METHOD *meth; + EC_GROUP *ret; + + meth = EC_GF2m_simple_method(); + + ret = EC_GROUP_new(meth); + if (ret == NULL) + return NULL; + + if (!EC_GROUP_set_curve_GF2m(ret, p, a, b, ctx)) + { + EC_GROUP_clear_free(ret); + return NULL; + } + + return ret; + } diff --git a/openssl/crypto/ec/ec_err.c b/openssl/crypto/ec/ec_err.c new file mode 100644 index 000000000..d04c89556 --- /dev/null +++ b/openssl/crypto/ec/ec_err.c @@ -0,0 +1,239 @@ +/* crypto/ec/ec_err.c */ +/* ==================================================================== + * Copyright (c) 1999-2007 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). + * + */ + +/* NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include <stdio.h> +#include <openssl/err.h> +#include <openssl/ec.h> + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +#define ERR_FUNC(func) ERR_PACK(ERR_LIB_EC,func,0) +#define ERR_REASON(reason) ERR_PACK(ERR_LIB_EC,0,reason) + +static ERR_STRING_DATA EC_str_functs[]= + { +{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_ECPARAMETERS_PRINT), "ECParameters_print"}, +{ERR_FUNC(EC_F_ECPARAMETERS_PRINT_FP), "ECParameters_print_fp"}, +{ERR_FUNC(EC_F_ECPKPARAMETERS_PRINT), "ECPKParameters_print"}, +{ERR_FUNC(EC_F_ECPKPARAMETERS_PRINT_FP), "ECPKParameters_print_fp"}, +{ERR_FUNC(EC_F_ECP_NIST_MOD_192), "ECP_NIST_MOD_192"}, +{ERR_FUNC(EC_F_ECP_NIST_MOD_224), "ECP_NIST_MOD_224"}, +{ERR_FUNC(EC_F_ECP_NIST_MOD_256), "ECP_NIST_MOD_256"}, +{ERR_FUNC(EC_F_ECP_NIST_MOD_521), "ECP_NIST_MOD_521"}, +{ERR_FUNC(EC_F_EC_ASN1_GROUP2CURVE), "EC_ASN1_GROUP2CURVE"}, +{ERR_FUNC(EC_F_EC_ASN1_GROUP2FIELDID), "EC_ASN1_GROUP2FIELDID"}, +{ERR_FUNC(EC_F_EC_ASN1_GROUP2PARAMETERS), "EC_ASN1_GROUP2PARAMETERS"}, +{ERR_FUNC(EC_F_EC_ASN1_GROUP2PKPARAMETERS), "EC_ASN1_GROUP2PKPARAMETERS"}, +{ERR_FUNC(EC_F_EC_ASN1_PARAMETERS2GROUP), "EC_ASN1_PARAMETERS2GROUP"}, +{ERR_FUNC(EC_F_EC_ASN1_PKPARAMETERS2GROUP), "EC_ASN1_PKPARAMETERS2GROUP"}, +{ERR_FUNC(EC_F_EC_EX_DATA_SET_DATA), "EC_EX_DATA_set_data"}, +{ERR_FUNC(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY), "EC_GF2M_MONTGOMERY_POINT_MULTIPLY"}, +{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT), "ec_GF2m_simple_group_check_discriminant"}, +{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE), "ec_GF2m_simple_group_set_curve"}, +{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_OCT2POINT), "ec_GF2m_simple_oct2point"}, +{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT2OCT), "ec_GF2m_simple_point2oct"}, +{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES), "ec_GF2m_simple_point_get_affine_coordinates"}, +{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES), "ec_GF2m_simple_point_set_affine_coordinates"}, +{ERR_FUNC(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES), "ec_GF2m_simple_set_compressed_coordinates"}, +{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_DECODE), "ec_GFp_mont_field_decode"}, +{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_ENCODE), "ec_GFp_mont_field_encode"}, +{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_MUL), "ec_GFp_mont_field_mul"}, +{ERR_FUNC(EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE), "ec_GFp_mont_field_set_to_one"}, +{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_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"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT), "ec_GFp_simple_group_check_discriminant"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE), "ec_GFp_simple_group_set_curve"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP), "EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR), "EC_GFP_SIMPLE_GROUP_SET_GENERATOR"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE), "ec_GFp_simple_make_affine"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_OCT2POINT), "ec_GFp_simple_oct2point"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT2OCT), "ec_GFp_simple_point2oct"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE), "ec_GFp_simple_points_make_affine"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES), "ec_GFp_simple_point_get_affine_coordinates"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP), "EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES), "ec_GFp_simple_point_set_affine_coordinates"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP), "EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES), "ec_GFp_simple_set_compressed_coordinates"}, +{ERR_FUNC(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP), "EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP"}, +{ERR_FUNC(EC_F_EC_GROUP_CHECK), "EC_GROUP_check"}, +{ERR_FUNC(EC_F_EC_GROUP_CHECK_DISCRIMINANT), "EC_GROUP_check_discriminant"}, +{ERR_FUNC(EC_F_EC_GROUP_COPY), "EC_GROUP_copy"}, +{ERR_FUNC(EC_F_EC_GROUP_GET0_GENERATOR), "EC_GROUP_get0_generator"}, +{ERR_FUNC(EC_F_EC_GROUP_GET_COFACTOR), "EC_GROUP_get_cofactor"}, +{ERR_FUNC(EC_F_EC_GROUP_GET_CURVE_GF2M), "EC_GROUP_get_curve_GF2m"}, +{ERR_FUNC(EC_F_EC_GROUP_GET_CURVE_GFP), "EC_GROUP_get_curve_GFp"}, +{ERR_FUNC(EC_F_EC_GROUP_GET_DEGREE), "EC_GROUP_get_degree"}, +{ERR_FUNC(EC_F_EC_GROUP_GET_ORDER), "EC_GROUP_get_order"}, +{ERR_FUNC(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS), "EC_GROUP_get_pentanomial_basis"}, +{ERR_FUNC(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS), "EC_GROUP_get_trinomial_basis"}, +{ERR_FUNC(EC_F_EC_GROUP_NEW), "EC_GROUP_new"}, +{ERR_FUNC(EC_F_EC_GROUP_NEW_BY_CURVE_NAME), "EC_GROUP_new_by_curve_name"}, +{ERR_FUNC(EC_F_EC_GROUP_NEW_FROM_DATA), "EC_GROUP_NEW_FROM_DATA"}, +{ERR_FUNC(EC_F_EC_GROUP_PRECOMPUTE_MULT), "EC_GROUP_precompute_mult"}, +{ERR_FUNC(EC_F_EC_GROUP_SET_CURVE_GF2M), "EC_GROUP_set_curve_GF2m"}, +{ERR_FUNC(EC_F_EC_GROUP_SET_CURVE_GFP), "EC_GROUP_set_curve_GFp"}, +{ERR_FUNC(EC_F_EC_GROUP_SET_EXTRA_DATA), "EC_GROUP_SET_EXTRA_DATA"}, +{ERR_FUNC(EC_F_EC_GROUP_SET_GENERATOR), "EC_GROUP_set_generator"}, +{ERR_FUNC(EC_F_EC_KEY_CHECK_KEY), "EC_KEY_check_key"}, +{ERR_FUNC(EC_F_EC_KEY_COPY), "EC_KEY_copy"}, +{ERR_FUNC(EC_F_EC_KEY_GENERATE_KEY), "EC_KEY_generate_key"}, +{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_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"}, +{ERR_FUNC(EC_F_EC_POINT_DBL), "EC_POINT_dbl"}, +{ERR_FUNC(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M), "EC_POINT_get_affine_coordinates_GF2m"}, +{ERR_FUNC(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP), "EC_POINT_get_affine_coordinates_GFp"}, +{ERR_FUNC(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP), "EC_POINT_get_Jprojective_coordinates_GFp"}, +{ERR_FUNC(EC_F_EC_POINT_INVERT), "EC_POINT_invert"}, +{ERR_FUNC(EC_F_EC_POINT_IS_AT_INFINITY), "EC_POINT_is_at_infinity"}, +{ERR_FUNC(EC_F_EC_POINT_IS_ON_CURVE), "EC_POINT_is_on_curve"}, +{ERR_FUNC(EC_F_EC_POINT_MAKE_AFFINE), "EC_POINT_make_affine"}, +{ERR_FUNC(EC_F_EC_POINT_MUL), "EC_POINT_mul"}, +{ERR_FUNC(EC_F_EC_POINT_NEW), "EC_POINT_new"}, +{ERR_FUNC(EC_F_EC_POINT_OCT2POINT), "EC_POINT_oct2point"}, +{ERR_FUNC(EC_F_EC_POINT_POINT2OCT), "EC_POINT_point2oct"}, +{ERR_FUNC(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M), "EC_POINT_set_affine_coordinates_GF2m"}, +{ERR_FUNC(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP), "EC_POINT_set_affine_coordinates_GFp"}, +{ERR_FUNC(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M), "EC_POINT_set_compressed_coordinates_GF2m"}, +{ERR_FUNC(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP), "EC_POINT_set_compressed_coordinates_GFp"}, +{ERR_FUNC(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP), "EC_POINT_set_Jprojective_coordinates_GFp"}, +{ERR_FUNC(EC_F_EC_POINT_SET_TO_INFINITY), "EC_POINT_set_to_infinity"}, +{ERR_FUNC(EC_F_EC_PRE_COMP_DUP), "EC_PRE_COMP_DUP"}, +{ERR_FUNC(EC_F_EC_PRE_COMP_NEW), "EC_PRE_COMP_NEW"}, +{ERR_FUNC(EC_F_EC_WNAF_MUL), "ec_wNAF_mul"}, +{ERR_FUNC(EC_F_EC_WNAF_PRECOMPUTE_MULT), "ec_wNAF_precompute_mult"}, +{ERR_FUNC(EC_F_I2D_ECPARAMETERS), "i2d_ECParameters"}, +{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_O2I_ECPUBLICKEY), "o2i_ECPublicKey"}, +{0,NULL} + }; + +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_BUFFER_TOO_SMALL) ,"buffer too small"}, +{ERR_REASON(EC_R_D2I_ECPKPARAMETERS_FAILURE),"d2i ecpkparameters failure"}, +{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_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_ENCODING) ,"invalid encoding"}, +{ERR_REASON(EC_R_INVALID_FIELD) ,"invalid field"}, +{ERR_REASON(EC_R_INVALID_FORM) ,"invalid form"}, +{ERR_REASON(EC_R_INVALID_GROUP_ORDER) ,"invalid group order"}, +{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_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"}, +{ERR_REASON(EC_R_NOT_A_SUPPORTED_NIST_PRIME),"not a supported NIST prime"}, +{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_PASSED_NULL_PARAMETER) ,"passed null parameter"}, +{ERR_REASON(EC_R_PKPARAMETERS2GROUP_FAILURE),"pkparameters2group failure"}, +{ERR_REASON(EC_R_POINT_AT_INFINITY) ,"point at infinity"}, +{ERR_REASON(EC_R_POINT_IS_NOT_ON_CURVE) ,"point is not on curve"}, +{ERR_REASON(EC_R_SLOT_FULL) ,"slot full"}, +{ERR_REASON(EC_R_UNDEFINED_GENERATOR) ,"undefined generator"}, +{ERR_REASON(EC_R_UNDEFINED_ORDER) ,"undefined order"}, +{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_ORDER) ,"wrong order"}, +{0,NULL} + }; + +#endif + +void ERR_load_EC_strings(void) + { +#ifndef OPENSSL_NO_ERR + + if (ERR_func_error_string(EC_str_functs[0].error) == NULL) + { + ERR_load_strings(0,EC_str_functs); + ERR_load_strings(0,EC_str_reasons); + } +#endif + } diff --git a/openssl/crypto/ec/ec_key.c b/openssl/crypto/ec/ec_key.c new file mode 100644 index 000000000..12fb0e6d6 --- /dev/null +++ b/openssl/crypto/ec/ec_key.c @@ -0,0 +1,457 @@ +/* crypto/ec/ec_key.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 <string.h> +#include "ec_lcl.h" +#include <openssl/err.h> +#include <string.h> + +EC_KEY *EC_KEY_new(void) + { + EC_KEY *ret; + + ret=(EC_KEY *)OPENSSL_malloc(sizeof(EC_KEY)); + if (ret == NULL) + { + ECerr(EC_F_EC_KEY_NEW, ERR_R_MALLOC_FAILURE); + return(NULL); + } + + ret->version = 1; + ret->group = NULL; + ret->pub_key = NULL; + ret->priv_key= NULL; + ret->enc_flag= 0; + ret->conv_form = POINT_CONVERSION_UNCOMPRESSED; + ret->references= 1; + ret->method_data = NULL; + return(ret); + } + +EC_KEY *EC_KEY_new_by_curve_name(int nid) + { + EC_KEY *ret = EC_KEY_new(); + if (ret == NULL) + return NULL; + ret->group = EC_GROUP_new_by_curve_name(nid); + if (ret->group == NULL) + { + EC_KEY_free(ret); + return NULL; + } + return ret; + } + +void EC_KEY_free(EC_KEY *r) + { + int i; + + if (r == NULL) return; + + i=CRYPTO_add(&r->references,-1,CRYPTO_LOCK_EC); +#ifdef REF_PRINT + REF_PRINT("EC_KEY",r); +#endif + if (i > 0) return; +#ifdef REF_CHECK + if (i < 0) + { + fprintf(stderr,"EC_KEY_free, bad reference count\n"); + abort(); + } +#endif + + if (r->group != NULL) + EC_GROUP_free(r->group); + if (r->pub_key != NULL) + EC_POINT_free(r->pub_key); + if (r->priv_key != NULL) + BN_clear_free(r->priv_key); + + EC_EX_DATA_free_all_data(&r->method_data); + + OPENSSL_cleanse((void *)r, sizeof(EC_KEY)); + + OPENSSL_free(r); + } + +EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) + { + EC_EXTRA_DATA *d; + + if (dest == NULL || src == NULL) + { + ECerr(EC_F_EC_KEY_COPY, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + /* copy the parameters */ + if (src->group) + { + const EC_METHOD *meth = EC_GROUP_method_of(src->group); + /* clear the old group */ + if (dest->group) + EC_GROUP_free(dest->group); + dest->group = EC_GROUP_new(meth); + if (dest->group == NULL) + return NULL; + if (!EC_GROUP_copy(dest->group, src->group)) + return NULL; + } + /* copy the public key */ + if (src->pub_key && src->group) + { + if (dest->pub_key) + EC_POINT_free(dest->pub_key); + dest->pub_key = EC_POINT_new(src->group); + if (dest->pub_key == NULL) + return NULL; + if (!EC_POINT_copy(dest->pub_key, src->pub_key)) + return NULL; + } + /* copy the private key */ + if (src->priv_key) + { + if (dest->priv_key == NULL) + { + dest->priv_key = BN_new(); + if (dest->priv_key == NULL) + return NULL; + } + if (!BN_copy(dest->priv_key, src->priv_key)) + return NULL; + } + /* copy method/extra data */ + EC_EX_DATA_free_all_data(&dest->method_data); + + for (d = src->method_data; d != NULL; d = d->next) + { + void *t = d->dup_func(d->data); + + if (t == NULL) + return 0; + if (!EC_EX_DATA_set_data(&dest->method_data, t, d->dup_func, d->free_func, d->clear_free_func)) + return 0; + } + + /* copy the rest */ + dest->enc_flag = src->enc_flag; + dest->conv_form = src->conv_form; + dest->version = src->version; + + return dest; + } + +EC_KEY *EC_KEY_dup(const EC_KEY *ec_key) + { + EC_KEY *ret = EC_KEY_new(); + if (ret == NULL) + return NULL; + if (EC_KEY_copy(ret, ec_key) == NULL) + { + EC_KEY_free(ret); + return NULL; + } + return ret; + } + +int EC_KEY_up_ref(EC_KEY *r) + { + int i = CRYPTO_add(&r->references, 1, CRYPTO_LOCK_EC); +#ifdef REF_PRINT + REF_PRINT("EC_KEY",r); +#endif +#ifdef REF_CHECK + if (i < 2) + { + fprintf(stderr, "EC_KEY_up, bad reference count\n"); + abort(); + } +#endif + return ((i > 1) ? 1 : 0); + } + +int EC_KEY_generate_key(EC_KEY *eckey) + { + int ok = 0; + BN_CTX *ctx = NULL; + BIGNUM *priv_key = NULL, *order = NULL; + EC_POINT *pub_key = NULL; + + if (!eckey || !eckey->group) + { + ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((order = BN_new()) == NULL) goto err; + if ((ctx = BN_CTX_new()) == NULL) goto err; + + if (eckey->priv_key == NULL) + { + priv_key = BN_new(); + if (priv_key == NULL) + goto err; + } + else + priv_key = eckey->priv_key; + + if (!EC_GROUP_get_order(eckey->group, order, ctx)) + goto err; + + do + if (!BN_rand_range(priv_key, order)) + goto err; + while (BN_is_zero(priv_key)); + + if (eckey->pub_key == NULL) + { + pub_key = EC_POINT_new(eckey->group); + if (pub_key == NULL) + goto err; + } + else + pub_key = eckey->pub_key; + + if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx)) + goto err; + + eckey->priv_key = priv_key; + eckey->pub_key = pub_key; + + ok=1; + +err: + if (order) + BN_free(order); + if (pub_key != NULL && eckey->pub_key == NULL) + EC_POINT_free(pub_key); + if (priv_key != NULL && eckey->priv_key == NULL) + BN_free(priv_key); + if (ctx != NULL) + BN_CTX_free(ctx); + return(ok); + } + +int EC_KEY_check_key(const EC_KEY *eckey) + { + int ok = 0; + BN_CTX *ctx = NULL; + const BIGNUM *order = NULL; + EC_POINT *point = NULL; + + if (!eckey || !eckey->group || !eckey->pub_key) + { + ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if ((ctx = BN_CTX_new()) == NULL) + goto err; + if ((point = EC_POINT_new(eckey->group)) == NULL) + goto err; + + /* testing whether the pub_key is on the elliptic curve */ + if (!EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx)) + { + ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_POINT_IS_NOT_ON_CURVE); + goto err; + } + /* testing whether pub_key * order is the point at infinity */ + order = &eckey->group->order; + if (BN_is_zero(order)) + { + ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_INVALID_GROUP_ORDER); + goto err; + } + if (!EC_POINT_mul(eckey->group, point, NULL, eckey->pub_key, order, ctx)) + { + ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_is_at_infinity(eckey->group, point)) + { + ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_WRONG_ORDER); + goto err; + } + /* in case the priv_key is present : + * check if generator * priv_key == pub_key + */ + if (eckey->priv_key) + { + if (BN_cmp(eckey->priv_key, order) >= 0) + { + ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_WRONG_ORDER); + goto err; + } + if (!EC_POINT_mul(eckey->group, point, eckey->priv_key, + NULL, NULL, ctx)) + { + ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_EC_LIB); + goto err; + } + if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, + ctx) != 0) + { + ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_INVALID_PRIVATE_KEY); + goto err; + } + } + ok = 1; +err: + if (ctx != NULL) + BN_CTX_free(ctx); + if (point != NULL) + EC_POINT_free(point); + return(ok); + } + +const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) + { + return key->group; + } + +int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) + { + if (key->group != NULL) + EC_GROUP_free(key->group); + key->group = EC_GROUP_dup(group); + return (key->group == NULL) ? 0 : 1; + } + +const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) + { + return key->priv_key; + } + +int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) + { + if (key->priv_key) + BN_clear_free(key->priv_key); + key->priv_key = BN_dup(priv_key); + return (key->priv_key == NULL) ? 0 : 1; + } + +const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) + { + return key->pub_key; + } + +int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) + { + if (key->pub_key != NULL) + EC_POINT_free(key->pub_key); + key->pub_key = EC_POINT_dup(pub_key, key->group); + return (key->pub_key == NULL) ? 0 : 1; + } + +unsigned int EC_KEY_get_enc_flags(const EC_KEY *key) + { + return key->enc_flag; + } + +void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags) + { + key->enc_flag = flags; + } + +point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key) + { + return key->conv_form; + } + +void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform) + { + key->conv_form = cform; + if (key->group != NULL) + EC_GROUP_set_point_conversion_form(key->group, cform); + } + +void *EC_KEY_get_key_method_data(EC_KEY *key, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) + { + return EC_EX_DATA_get_data(key->method_data, dup_func, free_func, clear_free_func); + } + +void EC_KEY_insert_key_method_data(EC_KEY *key, void *data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) + { + EC_EXTRA_DATA *ex_data; + CRYPTO_w_lock(CRYPTO_LOCK_EC); + ex_data = EC_EX_DATA_get_data(key->method_data, dup_func, free_func, clear_free_func); + if (ex_data == NULL) + EC_EX_DATA_set_data(&key->method_data, data, dup_func, free_func, clear_free_func); + CRYPTO_w_unlock(CRYPTO_LOCK_EC); + } + +void EC_KEY_set_asn1_flag(EC_KEY *key, int flag) + { + if (key->group != NULL) + EC_GROUP_set_asn1_flag(key->group, flag); + } + +int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx) + { + if (key->group == NULL) + return 0; + return EC_GROUP_precompute_mult(key->group, ctx); + } diff --git a/openssl/crypto/ec/ec_lcl.h b/openssl/crypto/ec/ec_lcl.h new file mode 100644 index 000000000..fdd7aa275 --- /dev/null +++ b/openssl/crypto/ec/ec_lcl.h @@ -0,0 +1,390 @@ +/* crypto/ec/ec_lcl.h */ +/* + * 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. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + + +#include <stdlib.h> + +#include <openssl/obj_mac.h> +#include <openssl/ec.h> +#include <openssl/bn.h> + +#if defined(__SUNPRO_C) +# if __SUNPRO_C >= 0x520 +# pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE) +# endif +#endif + +/* Structure details are not part of the exported interface, + * so all this may change in future versions. */ + +struct ec_method_st { + /* used by EC_METHOD_get_field_type: */ + int field_type; /* a NID */ + + /* used by EC_GROUP_new, EC_GROUP_free, EC_GROUP_clear_free, EC_GROUP_copy: */ + int (*group_init)(EC_GROUP *); + void (*group_finish)(EC_GROUP *); + void (*group_clear_finish)(EC_GROUP *); + int (*group_copy)(EC_GROUP *, const EC_GROUP *); + + /* used by EC_GROUP_set_curve_GFp, EC_GROUP_get_curve_GFp, */ + /* EC_GROUP_set_curve_GF2m, and EC_GROUP_get_curve_GF2m: */ + int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); + int (*group_get_curve)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *); + + /* used by EC_GROUP_get_degree: */ + int (*group_get_degree)(const EC_GROUP *); + + /* used by EC_GROUP_check: */ + int (*group_check_discriminant)(const EC_GROUP *, BN_CTX *); + + /* used by EC_POINT_new, EC_POINT_free, EC_POINT_clear_free, EC_POINT_copy: */ + int (*point_init)(EC_POINT *); + void (*point_finish)(EC_POINT *); + void (*point_clear_finish)(EC_POINT *); + int (*point_copy)(EC_POINT *, const EC_POINT *); + + /* used by EC_POINT_set_to_infinity, + * EC_POINT_set_Jprojective_coordinates_GFp, + * EC_POINT_get_Jprojective_coordinates_GFp, + * EC_POINT_set_affine_coordinates_GFp, ..._GF2m, + * EC_POINT_get_affine_coordinates_GFp, ..._GF2m, + * EC_POINT_set_compressed_coordinates_GFp, ..._GF2m: + */ + int (*point_set_to_infinity)(const EC_GROUP *, EC_POINT *); + int (*point_set_Jprojective_coordinates_GFp)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *); + int (*point_get_Jprojective_coordinates_GFp)(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *); + int (*point_set_affine_coordinates)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, BN_CTX *); + int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BN_CTX *); + int (*point_set_compressed_coordinates)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, BN_CTX *); + + /* used by EC_POINT_point2oct, EC_POINT_oct2point: */ + size_t (*point2oct)(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form, + unsigned char *buf, size_t len, BN_CTX *); + int (*oct2point)(const EC_GROUP *, EC_POINT *, + const unsigned char *buf, size_t len, BN_CTX *); + + /* used by EC_POINT_add, EC_POINT_dbl, ECP_POINT_invert: */ + int (*add)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *); + int (*dbl)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *); + int (*invert)(const EC_GROUP *, EC_POINT *, BN_CTX *); + + /* used by EC_POINT_is_at_infinity, EC_POINT_is_on_curve, EC_POINT_cmp: */ + int (*is_at_infinity)(const EC_GROUP *, const EC_POINT *); + int (*is_on_curve)(const EC_GROUP *, const EC_POINT *, BN_CTX *); + int (*point_cmp)(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *); + + /* used by EC_POINT_make_affine, EC_POINTs_make_affine: */ + int (*make_affine)(const EC_GROUP *, EC_POINT *, BN_CTX *); + int (*points_make_affine)(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *); + + /* used by EC_POINTs_mul, EC_POINT_mul, EC_POINT_precompute_mult, EC_POINT_have_precompute_mult + * (default implementations are used if the 'mul' pointer is 0): */ + int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *); + int (*precompute_mult)(EC_GROUP *group, BN_CTX *); + int (*have_precompute_mult)(const EC_GROUP *group); + + + /* internal functions */ + + /* 'field_mul', 'field_sqr', and 'field_div' can be used by 'add' and 'dbl' so that + * the same implementations of point operations can be used with different + * optimized implementations of expensive field operations: */ + int (*field_mul)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); + int (*field_div)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); + + int (*field_encode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); /* e.g. to Montgomery */ + int (*field_decode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); /* e.g. from Montgomery */ + int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *); +} /* EC_METHOD */; + +typedef struct ec_extra_data_st { + struct ec_extra_data_st *next; + void *data; + void *(*dup_func)(void *); + void (*free_func)(void *); + void (*clear_free_func)(void *); +} EC_EXTRA_DATA; /* used in EC_GROUP */ + +struct ec_group_st { + const EC_METHOD *meth; + + EC_POINT *generator; /* optional */ + BIGNUM order, cofactor; + + int curve_name;/* optional NID for named curve */ + int asn1_flag; /* flag to control the asn1 encoding */ + point_conversion_form_t asn1_form; + + unsigned char *seed; /* optional seed for parameters (appears in ASN1) */ + size_t seed_len; + + EC_EXTRA_DATA *extra_data; /* linked list */ + + /* The following members are handled by the method functions, + * even if they appear generic */ + + BIGNUM field; /* Field specification. + * For curves over GF(p), this is the modulus; + * for curves over GF(2^m), this is the + * 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. + */ + + BIGNUM a, b; /* Curve coefficients. + * (Here the assumption is that BIGNUMs can be used + * or abused for all kinds of fields, not just GF(p).) + * For characteristic > 3, the curve is defined + * by a Weierstrass equation of the form + * y^2 = x^3 + a*x + b. + * For characteristic 2, the curve is defined by + * an equation of the form + * y^2 + x*y = x^3 + a*x^2 + b. + */ + + int a_is_minus3; /* enable optimized point arithmetics for special case */ + + void *field_data1; /* method-specific (e.g., Montgomery structure) */ + void *field_data2; /* method-specific */ + int (*field_mod_func)(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); /* method-specific */ +} /* EC_GROUP */; + +struct ec_key_st { + int version; + + EC_GROUP *group; + + EC_POINT *pub_key; + BIGNUM *priv_key; + + unsigned int enc_flag; + point_conversion_form_t conv_form; + + int references; + + EC_EXTRA_DATA *method_data; +} /* EC_KEY */; + +/* Basically a 'mixin' for extra data, but available for EC_GROUPs/EC_KEYs only + * (with visibility limited to 'package' level for now). + * We use the function pointers as index for retrieval; this obviates + * global ex_data-style index tables. + */ +int EC_EX_DATA_set_data(EC_EXTRA_DATA **, void *data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)); +void *EC_EX_DATA_get_data(const EC_EXTRA_DATA *, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)); +void EC_EX_DATA_free_data(EC_EXTRA_DATA **, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)); +void EC_EX_DATA_clear_free_data(EC_EXTRA_DATA **, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)); +void EC_EX_DATA_free_all_data(EC_EXTRA_DATA **); +void EC_EX_DATA_clear_free_all_data(EC_EXTRA_DATA **); + + + +struct ec_point_st { + const EC_METHOD *meth; + + /* All members except 'meth' are handled by the method functions, + * even if they appear generic */ + + BIGNUM X; + BIGNUM Y; + BIGNUM Z; /* Jacobian projective coordinates: + * (X, Y, Z) represents (X/Z^2, Y/Z^3) if Z != 0 */ + int Z_is_one; /* enable optimized point arithmetics for special case */ +} /* EC_POINT */; + + + +/* method functions in ec_mult.c + * (ec_lib.c uses these as defaults if group->method->mul is 0) */ +int ec_wNAF_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_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *); +int ec_wNAF_have_precompute_mult(const EC_GROUP *group); + + +/* method functions in ecp_smpl.c */ +int ec_GFp_simple_group_init(EC_GROUP *); +void ec_GFp_simple_group_finish(EC_GROUP *); +void ec_GFp_simple_group_clear_finish(EC_GROUP *); +int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *); +int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *); +int ec_GFp_simple_group_get_degree(const EC_GROUP *); +int ec_GFp_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *); +int ec_GFp_simple_point_init(EC_POINT *); +void ec_GFp_simple_point_finish(EC_POINT *); +void ec_GFp_simple_point_clear_finish(EC_POINT *); +int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *); +int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *); +int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *); +int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *); +int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, BN_CTX *); +int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BN_CTX *); +int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, BN_CTX *); +size_t ec_GFp_simple_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form, + unsigned char *buf, size_t len, BN_CTX *); +int ec_GFp_simple_oct2point(const EC_GROUP *, EC_POINT *, + const unsigned char *buf, size_t len, BN_CTX *); +int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *); +int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *); +int ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *); +int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *); +int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *); +int ec_GFp_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *); +int ec_GFp_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *); +int ec_GFp_simple_points_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *); +int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); + + +/* method functions in ecp_mont.c */ +int ec_GFp_mont_group_init(EC_GROUP *); +int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +void ec_GFp_mont_group_finish(EC_GROUP *); +void ec_GFp_mont_group_clear_finish(EC_GROUP *); +int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *); +int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); +int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); +int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); +int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *); + + +/* method functions in ecp_nist.c */ +int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src); +int ec_GFp_nist_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int ec_GFp_nist_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int ec_GFp_nist_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); + + +/* method functions in ec2_smpl.c */ +int ec_GF2m_simple_group_init(EC_GROUP *); +void ec_GF2m_simple_group_finish(EC_GROUP *); +void ec_GF2m_simple_group_clear_finish(EC_GROUP *); +int ec_GF2m_simple_group_copy(EC_GROUP *, const EC_GROUP *); +int ec_GF2m_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int ec_GF2m_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *); +int ec_GF2m_simple_group_get_degree(const EC_GROUP *); +int ec_GF2m_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *); +int ec_GF2m_simple_point_init(EC_POINT *); +void ec_GF2m_simple_point_finish(EC_POINT *); +void ec_GF2m_simple_point_clear_finish(EC_POINT *); +int ec_GF2m_simple_point_copy(EC_POINT *, const EC_POINT *); +int ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *); +int ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, BN_CTX *); +int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BN_CTX *); +int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, BN_CTX *); +size_t ec_GF2m_simple_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form, + unsigned char *buf, size_t len, BN_CTX *); +int ec_GF2m_simple_oct2point(const EC_GROUP *, EC_POINT *, + const unsigned char *buf, size_t len, BN_CTX *); +int ec_GF2m_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *); +int ec_GF2m_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *); +int ec_GF2m_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *); +int ec_GF2m_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *); +int ec_GF2m_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *); +int ec_GF2m_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *); +int ec_GF2m_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *); +int ec_GF2m_simple_points_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *); +int ec_GF2m_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int ec_GF2m_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); +int ec_GF2m_simple_field_div(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); + + +/* 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); diff --git a/openssl/crypto/ec/ec_lib.c b/openssl/crypto/ec/ec_lib.c new file mode 100644 index 000000000..5af84376c --- /dev/null +++ b/openssl/crypto/ec/ec_lib.c @@ -0,0 +1,1164 @@ +/* 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" + +static const char EC_version[] = "EC" OPENSSL_VERSION_PTEXT; + + +/* functions for EC_GROUP objects */ + +EC_GROUP *EC_GROUP_new(const EC_METHOD *meth) + { + EC_GROUP *ret; + + if (meth == NULL) + { + ECerr(EC_F_EC_GROUP_NEW, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (meth->group_init == 0) + { + ECerr(EC_F_EC_GROUP_NEW, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return NULL; + } + + ret = OPENSSL_malloc(sizeof *ret); + if (ret == NULL) + { + ECerr(EC_F_EC_GROUP_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->meth = meth; + + ret->extra_data = NULL; + + ret->generator = NULL; + BN_init(&ret->order); + BN_init(&ret->cofactor); + + ret->curve_name = 0; + ret->asn1_flag = 0; + ret->asn1_form = POINT_CONVERSION_UNCOMPRESSED; + + ret->seed = NULL; + ret->seed_len = 0; + + if (!meth->group_init(ret)) + { + OPENSSL_free(ret); + return NULL; + } + + return ret; + } + + +void EC_GROUP_free(EC_GROUP *group) + { + if (!group) return; + + if (group->meth->group_finish != 0) + group->meth->group_finish(group); + + EC_EX_DATA_free_all_data(&group->extra_data); + + if (group->generator != NULL) + EC_POINT_free(group->generator); + BN_free(&group->order); + BN_free(&group->cofactor); + + if (group->seed) + OPENSSL_free(group->seed); + + OPENSSL_free(group); + } + + +void EC_GROUP_clear_free(EC_GROUP *group) + { + if (!group) return; + + if (group->meth->group_clear_finish != 0) + group->meth->group_clear_finish(group); + else if (group->meth->group_finish != 0) + group->meth->group_finish(group); + + EC_EX_DATA_clear_free_all_data(&group->extra_data); + + if (group->generator != NULL) + EC_POINT_clear_free(group->generator); + BN_clear_free(&group->order); + BN_clear_free(&group->cofactor); + + if (group->seed) + { + OPENSSL_cleanse(group->seed, group->seed_len); + OPENSSL_free(group->seed); + } + + OPENSSL_cleanse(group, sizeof *group); + OPENSSL_free(group); + } + + +int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src) + { + EC_EXTRA_DATA *d; + + if (dest->meth->group_copy == 0) + { + ECerr(EC_F_EC_GROUP_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (dest->meth != src->meth) + { + ECerr(EC_F_EC_GROUP_COPY, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (dest == src) + return 1; + + EC_EX_DATA_free_all_data(&dest->extra_data); + + for (d = src->extra_data; d != NULL; d = d->next) + { + void *t = d->dup_func(d->data); + + if (t == NULL) + return 0; + if (!EC_EX_DATA_set_data(&dest->extra_data, t, d->dup_func, d->free_func, d->clear_free_func)) + return 0; + } + + if (src->generator != NULL) + { + if (dest->generator == NULL) + { + dest->generator = EC_POINT_new(dest); + if (dest->generator == NULL) return 0; + } + if (!EC_POINT_copy(dest->generator, src->generator)) return 0; + } + else + { + /* src->generator == NULL */ + if (dest->generator != NULL) + { + EC_POINT_clear_free(dest->generator); + dest->generator = NULL; + } + } + + if (!BN_copy(&dest->order, &src->order)) return 0; + if (!BN_copy(&dest->cofactor, &src->cofactor)) return 0; + + dest->curve_name = src->curve_name; + dest->asn1_flag = src->asn1_flag; + dest->asn1_form = src->asn1_form; + + if (src->seed) + { + if (dest->seed) + OPENSSL_free(dest->seed); + dest->seed = OPENSSL_malloc(src->seed_len); + if (dest->seed == NULL) + return 0; + if (!memcpy(dest->seed, src->seed, src->seed_len)) + return 0; + dest->seed_len = src->seed_len; + } + else + { + if (dest->seed) + OPENSSL_free(dest->seed); + dest->seed = NULL; + dest->seed_len = 0; + } + + + return dest->meth->group_copy(dest, src); + } + + +EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) + { + EC_GROUP *t = NULL; + int ok = 0; + + if (a == NULL) return NULL; + + if ((t = EC_GROUP_new(a->meth)) == NULL) return(NULL); + if (!EC_GROUP_copy(t, a)) goto err; + + ok = 1; + + err: + if (!ok) + { + if (t) EC_GROUP_free(t); + return NULL; + } + else return t; + } + + +const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group) + { + return group->meth; + } + + +int EC_METHOD_get_field_type(const EC_METHOD *meth) + { + return meth->field_type; + } + + +int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor) + { + if (generator == NULL) + { + ECerr(EC_F_EC_GROUP_SET_GENERATOR, ERR_R_PASSED_NULL_PARAMETER); + return 0 ; + } + + if (group->generator == NULL) + { + group->generator = EC_POINT_new(group); + if (group->generator == NULL) return 0; + } + if (!EC_POINT_copy(group->generator, generator)) return 0; + + if (order != NULL) + { if (!BN_copy(&group->order, order)) return 0; } + else + BN_zero(&group->order); + + if (cofactor != NULL) + { if (!BN_copy(&group->cofactor, cofactor)) return 0; } + else + BN_zero(&group->cofactor); + + return 1; + } + + +const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) + { + return group->generator; + } + + +int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) + { + if (!BN_copy(order, &group->order)) + return 0; + + return !BN_is_zero(order); + } + + +int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx) + { + if (!BN_copy(cofactor, &group->cofactor)) + return 0; + + return !BN_is_zero(&group->cofactor); + } + + +void EC_GROUP_set_curve_name(EC_GROUP *group, int nid) + { + group->curve_name = nid; + } + + +int EC_GROUP_get_curve_name(const EC_GROUP *group) + { + return group->curve_name; + } + + +void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) + { + group->asn1_flag = flag; + } + + +int EC_GROUP_get_asn1_flag(const EC_GROUP *group) + { + return group->asn1_flag; + } + + +void EC_GROUP_set_point_conversion_form(EC_GROUP *group, + point_conversion_form_t form) + { + group->asn1_form = form; + } + + +point_conversion_form_t EC_GROUP_get_point_conversion_form(const EC_GROUP *group) + { + return group->asn1_form; + } + + +size_t EC_GROUP_set_seed(EC_GROUP *group, const unsigned char *p, size_t len) + { + if (group->seed) + { + OPENSSL_free(group->seed); + group->seed = NULL; + group->seed_len = 0; + } + + if (!len || !p) + return 1; + + if ((group->seed = OPENSSL_malloc(len)) == NULL) + return 0; + memcpy(group->seed, p, len); + group->seed_len = len; + + return len; + } + + +unsigned char *EC_GROUP_get0_seed(const EC_GROUP *group) + { + return group->seed; + } + + +size_t EC_GROUP_get_seed_len(const EC_GROUP *group) + { + return group->seed_len; + } + + +int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + if (group->meth->group_set_curve == 0) + { + ECerr(EC_F_EC_GROUP_SET_CURVE_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_set_curve(group, p, a, b, ctx); + } + + +int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) + { + if (group->meth->group_get_curve == 0) + { + ECerr(EC_F_EC_GROUP_GET_CURVE_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_get_curve(group, p, a, b, ctx); + } + + +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) + { + ECerr(EC_F_EC_GROUP_SET_CURVE_GF2M, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_set_curve(group, p, a, b, ctx); + } + + +int EC_GROUP_get_curve_GF2m(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) + { + if (group->meth->group_get_curve == 0) + { + ECerr(EC_F_EC_GROUP_GET_CURVE_GF2M, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_get_curve(group, p, a, b, ctx); + } + + +int EC_GROUP_get_degree(const EC_GROUP *group) + { + if (group->meth->group_get_degree == 0) + { + ECerr(EC_F_EC_GROUP_GET_DEGREE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_get_degree(group); + } + + +int EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) + { + if (group->meth->group_check_discriminant == 0) + { + ECerr(EC_F_EC_GROUP_CHECK_DISCRIMINANT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_check_discriminant(group, ctx); + } + + +int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx) + { + int r = 0; + BIGNUM *a1, *a2, *a3, *b1, *b2, *b3; + BN_CTX *ctx_new = NULL; + + /* compare the field types*/ + if (EC_METHOD_get_field_type(EC_GROUP_method_of(a)) != + EC_METHOD_get_field_type(EC_GROUP_method_of(b))) + return 1; + /* compare the curve name (if present) */ + if (EC_GROUP_get_curve_name(a) && EC_GROUP_get_curve_name(b) && + EC_GROUP_get_curve_name(a) == EC_GROUP_get_curve_name(b)) + return 0; + + if (!ctx) + ctx_new = ctx = BN_CTX_new(); + if (!ctx) + return -1; + + BN_CTX_start(ctx); + a1 = BN_CTX_get(ctx); + a2 = BN_CTX_get(ctx); + a3 = BN_CTX_get(ctx); + b1 = BN_CTX_get(ctx); + b2 = BN_CTX_get(ctx); + b3 = BN_CTX_get(ctx); + if (!b3) + { + BN_CTX_end(ctx); + if (ctx_new) + BN_CTX_free(ctx); + return -1; + } + + /* XXX This approach assumes that the external representation + * of curves over the same field type is the same. + */ + if (!a->meth->group_get_curve(a, a1, a2, a3, ctx) || + !b->meth->group_get_curve(b, b1, b2, b3, ctx)) + r = 1; + + if (r || BN_cmp(a1, b1) || BN_cmp(a2, b2) || BN_cmp(a3, b3)) + r = 1; + + /* XXX EC_POINT_cmp() assumes that the methods are equal */ + if (r || EC_POINT_cmp(a, EC_GROUP_get0_generator(a), + EC_GROUP_get0_generator(b), ctx)) + r = 1; + + if (!r) + { + /* compare the order and cofactor */ + if (!EC_GROUP_get_order(a, a1, ctx) || + !EC_GROUP_get_order(b, b1, ctx) || + !EC_GROUP_get_cofactor(a, a2, ctx) || + !EC_GROUP_get_cofactor(b, b2, ctx)) + { + BN_CTX_end(ctx); + if (ctx_new) + BN_CTX_free(ctx); + return -1; + } + if (BN_cmp(a1, b1) || BN_cmp(a2, b2)) + r = 1; + } + + BN_CTX_end(ctx); + if (ctx_new) + BN_CTX_free(ctx); + + return r; + } + + +/* this has 'package' visibility */ +int EC_EX_DATA_set_data(EC_EXTRA_DATA **ex_data, void *data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) + { + EC_EXTRA_DATA *d; + + if (ex_data == NULL) + return 0; + + for (d = *ex_data; d != NULL; d = d->next) + { + if (d->dup_func == dup_func && d->free_func == free_func && d->clear_free_func == clear_free_func) + { + ECerr(EC_F_EC_EX_DATA_SET_DATA, EC_R_SLOT_FULL); + return 0; + } + } + + if (data == NULL) + /* no explicit entry needed */ + return 1; + + d = OPENSSL_malloc(sizeof *d); + if (d == NULL) + return 0; + + d->data = data; + d->dup_func = dup_func; + d->free_func = free_func; + d->clear_free_func = clear_free_func; + + d->next = *ex_data; + *ex_data = d; + + return 1; + } + +/* this has 'package' visibility */ +void *EC_EX_DATA_get_data(const EC_EXTRA_DATA *ex_data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) + { + const EC_EXTRA_DATA *d; + + for (d = ex_data; d != NULL; d = d->next) + { + if (d->dup_func == dup_func && d->free_func == free_func && d->clear_free_func == clear_free_func) + return d->data; + } + + return NULL; + } + +/* this has 'package' visibility */ +void EC_EX_DATA_free_data(EC_EXTRA_DATA **ex_data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) + { + EC_EXTRA_DATA **p; + + if (ex_data == NULL) + return; + + for (p = ex_data; *p != NULL; p = &((*p)->next)) + { + if ((*p)->dup_func == dup_func && (*p)->free_func == free_func && (*p)->clear_free_func == clear_free_func) + { + EC_EXTRA_DATA *next = (*p)->next; + + (*p)->free_func((*p)->data); + OPENSSL_free(*p); + + *p = next; + return; + } + } + } + +/* this has 'package' visibility */ +void EC_EX_DATA_clear_free_data(EC_EXTRA_DATA **ex_data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) + { + EC_EXTRA_DATA **p; + + if (ex_data == NULL) + return; + + for (p = ex_data; *p != NULL; p = &((*p)->next)) + { + if ((*p)->dup_func == dup_func && (*p)->free_func == free_func && (*p)->clear_free_func == clear_free_func) + { + EC_EXTRA_DATA *next = (*p)->next; + + (*p)->clear_free_func((*p)->data); + OPENSSL_free(*p); + + *p = next; + return; + } + } + } + +/* this has 'package' visibility */ +void EC_EX_DATA_free_all_data(EC_EXTRA_DATA **ex_data) + { + EC_EXTRA_DATA *d; + + if (ex_data == NULL) + return; + + d = *ex_data; + while (d) + { + EC_EXTRA_DATA *next = d->next; + + d->free_func(d->data); + OPENSSL_free(d); + + d = next; + } + *ex_data = NULL; + } + +/* this has 'package' visibility */ +void EC_EX_DATA_clear_free_all_data(EC_EXTRA_DATA **ex_data) + { + EC_EXTRA_DATA *d; + + if (ex_data == NULL) + return; + + d = *ex_data; + while (d) + { + EC_EXTRA_DATA *next = d->next; + + d->clear_free_func(d->data); + OPENSSL_free(d); + + d = next; + } + *ex_data = NULL; + } + + +/* functions for EC_POINT objects */ + +EC_POINT *EC_POINT_new(const EC_GROUP *group) + { + EC_POINT *ret; + + if (group == NULL) + { + ECerr(EC_F_EC_POINT_NEW, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (group->meth->point_init == 0) + { + ECerr(EC_F_EC_POINT_NEW, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return NULL; + } + + ret = OPENSSL_malloc(sizeof *ret); + if (ret == NULL) + { + ECerr(EC_F_EC_POINT_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->meth = group->meth; + + if (!ret->meth->point_init(ret)) + { + OPENSSL_free(ret); + return NULL; + } + + return ret; + } + + +void EC_POINT_free(EC_POINT *point) + { + if (!point) return; + + if (point->meth->point_finish != 0) + point->meth->point_finish(point); + OPENSSL_free(point); + } + + +void EC_POINT_clear_free(EC_POINT *point) + { + if (!point) return; + + if (point->meth->point_clear_finish != 0) + point->meth->point_clear_finish(point); + else if (point->meth != NULL && point->meth->point_finish != 0) + point->meth->point_finish(point); + OPENSSL_cleanse(point, sizeof *point); + OPENSSL_free(point); + } + + +int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src) + { + if (dest->meth->point_copy == 0) + { + ECerr(EC_F_EC_POINT_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (dest->meth != src->meth) + { + ECerr(EC_F_EC_POINT_COPY, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (dest == src) + return 1; + return dest->meth->point_copy(dest, src); + } + + +EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group) + { + EC_POINT *t; + int r; + + if (a == NULL) return NULL; + + t = EC_POINT_new(group); + if (t == NULL) return(NULL); + r = EC_POINT_copy(t, a); + if (!r) + { + EC_POINT_free(t); + return NULL; + } + else return t; + } + + +const EC_METHOD *EC_POINT_method_of(const EC_POINT *point) + { + return point->meth; + } + + +int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) + { + if (group->meth->point_set_to_infinity == 0) + { + ECerr(EC_F_EC_POINT_SET_TO_INFINITY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_SET_TO_INFINITY, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_to_infinity(group, point); + } + + +int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx) + { + if (group->meth->point_set_Jprojective_coordinates_GFp == 0) + { + ECerr(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_Jprojective_coordinates_GFp(group, point, x, y, z, ctx); + } + + +int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point, + BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx) + { + if (group->meth->point_get_Jprojective_coordinates_GFp == 0) + { + ECerr(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_get_Jprojective_coordinates_GFp(group, point, x, y, z, ctx); + } + + +int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx) + { + if (group->meth->point_set_affine_coordinates == 0) + { + ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_affine_coordinates(group, point, x, y, ctx); + } + + +int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx) + { + if (group->meth->point_set_affine_coordinates == 0) + { + ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_affine_coordinates(group, point, x, y, ctx); + } + + +int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point, + BIGNUM *x, BIGNUM *y, BN_CTX *ctx) + { + if (group->meth->point_get_affine_coordinates == 0) + { + ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_get_affine_coordinates(group, point, x, y, ctx); + } + + +int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *group, const EC_POINT *point, + BIGNUM *x, BIGNUM *y, BN_CTX *ctx) + { + if (group->meth->point_get_affine_coordinates == 0) + { + ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + 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); + } + + +int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) + { + if (group->meth->add == 0) + { + ECerr(EC_F_EC_POINT_ADD, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if ((group->meth != r->meth) || (r->meth != a->meth) || (a->meth != b->meth)) + { + ECerr(EC_F_EC_POINT_ADD, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->add(group, r, a, b, ctx); + } + + +int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) + { + if (group->meth->dbl == 0) + { + ECerr(EC_F_EC_POINT_DBL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if ((group->meth != r->meth) || (r->meth != a->meth)) + { + ECerr(EC_F_EC_POINT_DBL, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->dbl(group, r, a, ctx); + } + + +int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) + { + if (group->meth->dbl == 0) + { + ECerr(EC_F_EC_POINT_INVERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != a->meth) + { + ECerr(EC_F_EC_POINT_INVERT, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->invert(group, a, ctx); + } + + +int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) + { + if (group->meth->is_at_infinity == 0) + { + ECerr(EC_F_EC_POINT_IS_AT_INFINITY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_IS_AT_INFINITY, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->is_at_infinity(group, point); + } + + +int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) + { + if (group->meth->is_on_curve == 0) + { + ECerr(EC_F_EC_POINT_IS_ON_CURVE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_IS_ON_CURVE, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->is_on_curve(group, point, ctx); + } + + +int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) + { + if (group->meth->point_cmp == 0) + { + ECerr(EC_F_EC_POINT_CMP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if ((group->meth != a->meth) || (a->meth != b->meth)) + { + ECerr(EC_F_EC_POINT_CMP, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_cmp(group, a, b, ctx); + } + + +int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) + { + if (group->meth->make_affine == 0) + { + ECerr(EC_F_EC_POINT_MAKE_AFFINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) + { + ECerr(EC_F_EC_POINT_MAKE_AFFINE, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->make_affine(group, point, ctx); + } + + +int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx) + { + size_t i; + + if (group->meth->points_make_affine == 0) + { + ECerr(EC_F_EC_POINTS_MAKE_AFFINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + for (i = 0; i < num; i++) + { + if (group->meth != points[i]->meth) + { + ECerr(EC_F_EC_POINTS_MAKE_AFFINE, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + } + return group->meth->points_make_affine(group, num, points, ctx); + } + + +/* Functions for point multiplication. + * + * If group->meth->mul is 0, we use the wNAF-based implementations in ec_mult.c; + * otherwise we dispatch through methods. + */ + +int EC_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) + { + if (group->meth->mul == 0) + /* use default */ + return ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx); + + return group->meth->mul(group, r, scalar, num, points, scalars, ctx); + } + +int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, + const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx) + { + /* just a convenient interface to EC_POINTs_mul() */ + + const EC_POINT *points[1]; + const BIGNUM *scalars[1]; + + points[0] = point; + scalars[0] = p_scalar; + + return EC_POINTs_mul(group, r, g_scalar, (point != NULL && p_scalar != NULL), points, scalars, ctx); + } + +int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx) + { + if (group->meth->mul == 0) + /* use default */ + return ec_wNAF_precompute_mult(group, ctx); + + if (group->meth->precompute_mult != 0) + return group->meth->precompute_mult(group, ctx); + else + return 1; /* nothing to do, so report success */ + } + +int EC_GROUP_have_precompute_mult(const EC_GROUP *group) + { + if (group->meth->mul == 0) + /* use default */ + return ec_wNAF_have_precompute_mult(group); + + if (group->meth->have_precompute_mult != 0) + return group->meth->have_precompute_mult(group); + else + return 0; /* cannot tell whether precomputation has been performed */ + } diff --git a/openssl/crypto/ec/ec_mult.c b/openssl/crypto/ec/ec_mult.c new file mode 100644 index 000000000..2ba173ef3 --- /dev/null +++ b/openssl/crypto/ec/ec_mult.c @@ -0,0 +1,938 @@ +/* crypto/ec/ec_mult.c */ +/* + * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. + */ +/* ==================================================================== + * Copyright (c) 1998-2007 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 <string.h> + +#include <openssl/err.h> + +#include "ec_lcl.h" + + +/* + * This file implements the wNAF-based interleaving multi-exponentation method + * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#multiexp>); + * for multiplication with precomputation, we use wNAF splitting + * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#fastexp>). + */ + + + + +/* structure for precomputed multiples of the generator */ +typedef struct ec_pre_comp_st { + const EC_GROUP *group; /* parent EC_GROUP object */ + size_t blocksize; /* block size for wNAF splitting */ + size_t numblocks; /* max. number of blocks for which we have precomputation */ + size_t w; /* window size */ + EC_POINT **points; /* array with pre-calculated multiples of generator: + * 'num' pointers to EC_POINT objects followed by a NULL */ + size_t num; /* numblocks * 2^(w-1) */ + int references; +} EC_PRE_COMP; + +/* functions to manage EC_PRE_COMP within the EC_GROUP extra_data framework */ +static void *ec_pre_comp_dup(void *); +static void ec_pre_comp_free(void *); +static void ec_pre_comp_clear_free(void *); + +static EC_PRE_COMP *ec_pre_comp_new(const EC_GROUP *group) + { + EC_PRE_COMP *ret = NULL; + + if (!group) + return NULL; + + ret = (EC_PRE_COMP *)OPENSSL_malloc(sizeof(EC_PRE_COMP)); + if (!ret) + { + ECerr(EC_F_EC_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE); + return ret; + } + ret->group = group; + ret->blocksize = 8; /* default */ + ret->numblocks = 0; + ret->w = 4; /* default */ + ret->points = NULL; + ret->num = 0; + ret->references = 1; + return ret; + } + +static void *ec_pre_comp_dup(void *src_) + { + EC_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 ec_pre_comp_free(void *pre_) + { + int i; + EC_PRE_COMP *pre = pre_; + + if (!pre) + return; + + i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP); + if (i > 0) + return; + + if (pre->points) + { + EC_POINT **p; + + for (p = pre->points; *p != NULL; p++) + EC_POINT_free(*p); + OPENSSL_free(pre->points); + } + OPENSSL_free(pre); + } + +static void ec_pre_comp_clear_free(void *pre_) + { + int i; + EC_PRE_COMP *pre = pre_; + + if (!pre) + return; + + i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP); + if (i > 0) + return; + + if (pre->points) + { + EC_POINT **p; + + for (p = pre->points; *p != NULL; p++) + EC_POINT_clear_free(*p); + OPENSSL_cleanse(pre->points, sizeof pre->points); + OPENSSL_free(pre->points); + } + OPENSSL_cleanse(pre, sizeof pre); + OPENSSL_free(pre); + } + + + + +/* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. + * This is an array r[] of values that are either zero or odd with an + * absolute value less than 2^w satisfying + * scalar = \sum_j r[j]*2^j + * where at most one of any w+1 consecutive digits is non-zero + * with the exception that the most significant digit may be only + * w-1 zeros away from that next non-zero digit. + */ +static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) + { + int window_val; + int ok = 0; + signed char *r = NULL; + int sign = 1; + int bit, next_bit, mask; + size_t len = 0, j; + + if (BN_is_zero(scalar)) + { + r = OPENSSL_malloc(1); + if (!r) + { + ECerr(EC_F_COMPUTE_WNAF, ERR_R_MALLOC_FAILURE); + goto err; + } + r[0] = 0; + *ret_len = 1; + return r; + } + + if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute values less than 2^7 */ + { + ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); + goto err; + } + bit = 1 << w; /* at most 128 */ + next_bit = bit << 1; /* at most 256 */ + mask = next_bit - 1; /* at most 255 */ + + if (BN_is_negative(scalar)) + { + sign = -1; + } + + 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 + * BN_num_bits(scalar) + 1) */ + if (r == NULL) + { + 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 */ + { + int digit = 0; + + /* 0 <= window_val <= 2^(w+1) */ + + if (window_val & 1) + { + /* 0 < window_val < 2^(w+1) */ + + if (window_val & bit) + { + digit = window_val - next_bit; /* -2^w < digit < 0 */ + +#if 1 /* modified wNAF */ + if (j + w + 1 >= len) + { + /* special case for generating modified wNAFs: + * no new bits will be added into window_val, + * so using a positive digit here will decrease + * the total length of the representation */ + + digit = window_val & (mask >> 1); /* 0 < digit < 2^w */ + } +#endif + } + else + { + digit = window_val; /* 0 < digit < 2^w */ + } + + if (digit <= -bit || digit >= bit || !(digit & 1)) + { + ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); + goto err; + } + + window_val -= digit; + + /* now window_val is 0 or 2^(w+1) in standard wNAF generation; + * for modified window NAFs, it may also be 2^w + */ + if (window_val != 0 && window_val != next_bit && window_val != bit) + { + ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + r[j++] = sign * digit; + + window_val >>= 1; + window_val += bit * BN_is_bit_set(scalar, j + w); + + if (window_val > next_bit) + { + ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (j > len + 1) + { + ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); + goto err; + } + len = j; + ok = 1; + + err: + if (!ok) + { + OPENSSL_free(r); + r = NULL; + } + if (ok) + *ret_len = len; + return r; + } + + +/* TODO: table should be optimised for the wNAF-based implementation, + * sometimes smaller windows will give better performance + * (thus the boundaries should be increased) + */ +#define EC_window_bits_for_scalar_size(b) \ + ((size_t) \ + ((b) >= 2000 ? 6 : \ + (b) >= 800 ? 5 : \ + (b) >= 300 ? 4 : \ + (b) >= 70 ? 3 : \ + (b) >= 20 ? 2 : \ + 1)) + +/* Compute + * \sum scalars[i]*points[i], + * also including + * scalar*generator + * in the addition if scalar != NULL + */ +int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + const EC_POINT *generator = NULL; + EC_POINT *tmp = NULL; + size_t totalnum; + size_t blocksize = 0, numblocks = 0; /* for wNAF splitting */ + size_t pre_points_per_block = 0; + size_t i, j; + int k; + int r_is_inverted = 0; + int r_is_at_infinity = 1; + size_t *wsize = NULL; /* individual window sizes */ + signed char **wNAF = NULL; /* individual wNAFs */ + size_t *wNAF_len = NULL; + size_t max_len = 0; + size_t num_val; + EC_POINT **val = NULL; /* precomputation */ + EC_POINT **v; + EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' or 'pre_comp->points' */ + const EC_PRE_COMP *pre_comp = NULL; + int num_scalar = 0; /* flag: will be set to 1 if 'scalar' must be treated like other scalars, + * i.e. precomputation is not available */ + int ret = 0; + + if (group->meth != r->meth) + { + ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + + if ((scalar == NULL) && (num == 0)) + { + return EC_POINT_set_to_infinity(group, r); + } + + for (i = 0; i < num; i++) + { + if (group->meth != points[i]->meth) + { + ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + } + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; + } + + if (scalar != NULL) + { + generator = EC_GROUP_get0_generator(group); + if (generator == NULL) + { + ECerr(EC_F_EC_WNAF_MUL, EC_R_UNDEFINED_GENERATOR); + goto err; + } + + /* look if we can use precomputed multiples of generator */ + + pre_comp = EC_EX_DATA_get_data(group->extra_data, ec_pre_comp_dup, ec_pre_comp_free, ec_pre_comp_clear_free); + + if (pre_comp && pre_comp->numblocks && (EC_POINT_cmp(group, generator, pre_comp->points[0], ctx) == 0)) + { + blocksize = pre_comp->blocksize; + + /* determine maximum number of blocks that wNAF splitting may yield + * (NB: maximum wNAF length is bit length plus one) */ + numblocks = (BN_num_bits(scalar) / blocksize) + 1; + + /* we cannot use more blocks than we have precomputation for */ + if (numblocks > pre_comp->numblocks) + numblocks = pre_comp->numblocks; + + pre_points_per_block = 1u << (pre_comp->w - 1); + + /* check that pre_comp looks sane */ + if (pre_comp->num != (pre_comp->numblocks * pre_points_per_block)) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); + goto err; + } + } + else + { + /* can't use precomputation */ + pre_comp = NULL; + numblocks = 1; + num_scalar = 1; /* treat 'scalar' like 'num'-th element of 'scalars' */ + } + } + + totalnum = num + numblocks; + + wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]); + wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]); + wNAF = OPENSSL_malloc((totalnum + 1) * sizeof wNAF[0]); /* includes space for pivot */ + val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]); + + if (!wsize || !wNAF_len || !wNAF || !val_sub) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE); + goto err; + } + + wNAF[0] = NULL; /* preliminary pivot */ + + /* num_val will be the total number of temporarily precomputed points */ + num_val = 0; + + for (i = 0; i < num + num_scalar; i++) + { + size_t bits; + + 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); + 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) + goto err; + if (wNAF_len[i] > max_len) + max_len = wNAF_len[i]; + } + + if (numblocks) + { + /* we go here iff scalar != NULL */ + + if (pre_comp == NULL) + { + if (num_scalar != 1) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); + goto err; + } + /* we have already generated a wNAF for 'scalar' */ + } + else + { + signed char *tmp_wNAF = NULL; + size_t tmp_len = 0; + + if (num_scalar != 0) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* use the window size for which we have precomputation */ + wsize[num] = pre_comp->w; + tmp_wNAF = compute_wNAF(scalar, wsize[num], &tmp_len); + if (!tmp_wNAF) + goto err; + + if (tmp_len <= max_len) + { + /* One of the other wNAFs is at least as long + * as the wNAF belonging to the generator, + * so wNAF splitting will not buy us anything. */ + + numblocks = 1; + totalnum = num + 1; /* don't use wNAF splitting */ + wNAF[num] = tmp_wNAF; + wNAF[num + 1] = NULL; + wNAF_len[num] = tmp_len; + if (tmp_len > max_len) + max_len = tmp_len; + /* pre_comp->points starts with the points that we need here: */ + val_sub[num] = pre_comp->points; + } + else + { + /* don't include tmp_wNAF directly into wNAF array + * - use wNAF splitting and include the blocks */ + + signed char *pp; + EC_POINT **tmp_points; + + if (tmp_len < numblocks * blocksize) + { + /* possibly we can do with fewer blocks than estimated */ + numblocks = (tmp_len + blocksize - 1) / blocksize; + if (numblocks > pre_comp->numblocks) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); + goto err; + } + totalnum = num + numblocks; + } + + /* split wNAF in 'numblocks' parts */ + pp = tmp_wNAF; + tmp_points = pre_comp->points; + + for (i = num; i < totalnum; i++) + { + if (i < totalnum - 1) + { + wNAF_len[i] = blocksize; + if (tmp_len < blocksize) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); + goto err; + } + tmp_len -= blocksize; + } + else + /* last block gets whatever is left + * (this could be more or less than 'blocksize'!) */ + wNAF_len[i] = tmp_len; + + wNAF[i + 1] = NULL; + wNAF[i] = OPENSSL_malloc(wNAF_len[i]); + if (wNAF[i] == NULL) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE); + OPENSSL_free(tmp_wNAF); + goto err; + } + memcpy(wNAF[i], pp, wNAF_len[i]); + if (wNAF_len[i] > max_len) + max_len = wNAF_len[i]; + + if (*tmp_points == NULL) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); + OPENSSL_free(tmp_wNAF); + goto err; + } + val_sub[i] = tmp_points; + tmp_points += pre_points_per_block; + pp += blocksize; + } + OPENSSL_free(tmp_wNAF); + } + } + } + + /* All points we precompute now go into a single array 'val'. + * 'val_sub[i]' is a pointer to the subarray for the i-th point, + * or to a subarray of 'pre_comp->points' if we already have precomputation. */ + val = OPENSSL_malloc((num_val + 1) * sizeof val[0]); + if (val == NULL) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE); + goto err; + } + val[num_val] = NULL; /* pivot element */ + + /* allocate points for precomputation */ + v = val; + for (i = 0; i < num + num_scalar; i++) + { + val_sub[i] = v; + for (j = 0; j < (1u << (wsize[i] - 1)); j++) + { + *v = EC_POINT_new(group); + if (*v == NULL) goto err; + v++; + } + } + if (!(v == val + num_val)) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!(tmp = EC_POINT_new(group))) + goto err; + + /* prepare precomputed values: + * val_sub[i][0] := points[i] + * val_sub[i][1] := 3 * points[i] + * val_sub[i][2] := 5 * points[i] + * ... + */ + for (i = 0; i < num + num_scalar; i++) + { + if (i < num) + { + if (!EC_POINT_copy(val_sub[i][0], points[i])) goto err; + } + else + { + if (!EC_POINT_copy(val_sub[i][0], generator)) goto err; + } + + 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++) + { + if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) goto err; + } + } + } + +#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */ + if (!EC_POINTs_make_affine(group, num_val, val, ctx)) + goto err; +#endif + + r_is_at_infinity = 1; + + for (k = max_len - 1; k >= 0; k--) + { + if (!r_is_at_infinity) + { + if (!EC_POINT_dbl(group, r, r, ctx)) goto err; + } + + for (i = 0; i < totalnum; i++) + { + if (wNAF_len[i] > (size_t)k) + { + int digit = wNAF[i][k]; + int is_neg; + + if (digit) + { + is_neg = digit < 0; + + if (is_neg) + digit = -digit; + + if (is_neg != r_is_inverted) + { + if (!r_is_at_infinity) + { + if (!EC_POINT_invert(group, r, ctx)) goto err; + } + r_is_inverted = !r_is_inverted; + } + + /* digit > 0 */ + + if (r_is_at_infinity) + { + if (!EC_POINT_copy(r, val_sub[i][digit >> 1])) goto err; + r_is_at_infinity = 0; + } + else + { + if (!EC_POINT_add(group, r, r, val_sub[i][digit >> 1], ctx)) goto err; + } + } + } + } + } + + if (r_is_at_infinity) + { + if (!EC_POINT_set_to_infinity(group, r)) goto err; + } + else + { + if (r_is_inverted) + if (!EC_POINT_invert(group, r, ctx)) goto err; + } + + ret = 1; + + err: + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + if (tmp != NULL) + EC_POINT_free(tmp); + if (wsize != NULL) + OPENSSL_free(wsize); + if (wNAF_len != NULL) + OPENSSL_free(wNAF_len); + if (wNAF != NULL) + { + signed char **w; + + for (w = wNAF; *w != NULL; w++) + OPENSSL_free(*w); + + OPENSSL_free(wNAF); + } + if (val != NULL) + { + for (v = val; *v != NULL; v++) + EC_POINT_clear_free(*v); + + OPENSSL_free(val); + } + if (val_sub != NULL) + { + OPENSSL_free(val_sub); + } + return ret; + } + + +/* ec_wNAF_precompute_mult() + * creates an EC_PRE_COMP object with preprecomputed multiples of the generator + * for use with wNAF splitting as implemented in ec_wNAF_mul(). + * + * 'pre_comp->points' is an array of multiples of the generator + * of the following form: + * points[0] = generator; + * points[1] = 3 * generator; + * ... + * points[2^(w-1)-1] = (2^(w-1)-1) * generator; + * points[2^(w-1)] = 2^blocksize * generator; + * points[2^(w-1)+1] = 3 * 2^blocksize * generator; + * ... + * points[2^(w-1)*(numblocks-1)-1] = (2^(w-1)) * 2^(blocksize*(numblocks-2)) * generator + * points[2^(w-1)*(numblocks-1)] = 2^(blocksize*(numblocks-1)) * generator + * ... + * points[2^(w-1)*numblocks-1] = (2^(w-1)) * 2^(blocksize*(numblocks-1)) * generator + * points[2^(w-1)*numblocks] = NULL + */ +int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *ctx) + { + const EC_POINT *generator; + EC_POINT *tmp_point = NULL, *base = NULL, **var; + BN_CTX *new_ctx = NULL; + BIGNUM *order; + size_t i, bits, w, pre_points_per_block, blocksize, numblocks, num; + EC_POINT **points = NULL; + EC_PRE_COMP *pre_comp; + int ret = 0; + + /* if there is an old EC_PRE_COMP object, throw it away */ + EC_EX_DATA_free_data(&group->extra_data, ec_pre_comp_dup, ec_pre_comp_free, ec_pre_comp_clear_free); + + if ((pre_comp = ec_pre_comp_new(group)) == NULL) + return 0; + + generator = EC_GROUP_get0_generator(group); + if (generator == NULL) + { + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR); + goto err; + } + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; + } + + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + if (order == NULL) goto err; + + if (!EC_GROUP_get_order(group, order, ctx)) goto err; + if (BN_is_zero(order)) + { + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER); + goto err; + } + + bits = BN_num_bits(order); + /* The following parameters mean we precompute (approximately) + * one point per bit. + * + * TBD: The combination 8, 4 is perfect for 160 bits; for other + * bit lengths, other parameter combinations might provide better + * efficiency. + */ + blocksize = 8; + w = 4; + if (EC_window_bits_for_scalar_size(bits) > w) + { + /* let's not make the window too small ... */ + w = EC_window_bits_for_scalar_size(bits); + } + + numblocks = (bits + blocksize - 1) / blocksize; /* max. number of blocks to use for wNAF splitting */ + + pre_points_per_block = 1u << (w - 1); + num = pre_points_per_block * numblocks; /* number of points to compute and store */ + + points = OPENSSL_malloc(sizeof (EC_POINT*)*(num + 1)); + if (!points) + { + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE); + goto err; + } + + var = points; + var[num] = NULL; /* pivot */ + for (i = 0; i < num; i++) + { + if ((var[i] = EC_POINT_new(group)) == NULL) + { + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (!(tmp_point = EC_POINT_new(group)) || !(base = EC_POINT_new(group))) + { + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_POINT_copy(base, generator)) + goto err; + + /* do the precomputation */ + for (i = 0; i < numblocks; i++) + { + size_t j; + + if (!EC_POINT_dbl(group, tmp_point, base, ctx)) + goto err; + + if (!EC_POINT_copy(*var++, base)) + goto err; + + for (j = 1; j < pre_points_per_block; j++, var++) + { + /* calculate odd multiples of the current base point */ + if (!EC_POINT_add(group, *var, tmp_point, *(var - 1), ctx)) + goto err; + } + + if (i < numblocks - 1) + { + /* get the next base (multiply current one by 2^blocksize) */ + size_t k; + + if (blocksize <= 2) + { + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!EC_POINT_dbl(group, base, tmp_point, ctx)) + goto err; + for (k = 2; k < blocksize; k++) + { + if (!EC_POINT_dbl(group,base,base,ctx)) + goto err; + } + } + } + + if (!EC_POINTs_make_affine(group, num, points, ctx)) + goto err; + + pre_comp->group = group; + pre_comp->blocksize = blocksize; + pre_comp->numblocks = numblocks; + pre_comp->w = w; + pre_comp->points = points; + points = NULL; + pre_comp->num = num; + + if (!EC_EX_DATA_set_data(&group->extra_data, pre_comp, + ec_pre_comp_dup, ec_pre_comp_free, ec_pre_comp_clear_free)) + goto err; + pre_comp = NULL; + + ret = 1; + err: + if (ctx != NULL) + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + if (pre_comp) + ec_pre_comp_free(pre_comp); + if (points) + { + EC_POINT **p; + + for (p = points; *p != NULL; p++) + EC_POINT_free(*p); + OPENSSL_free(points); + } + if (tmp_point) + EC_POINT_free(tmp_point); + if (base) + EC_POINT_free(base); + return ret; + } + + +int ec_wNAF_have_precompute_mult(const EC_GROUP *group) + { + if (EC_EX_DATA_get_data(group->extra_data, ec_pre_comp_dup, ec_pre_comp_free, ec_pre_comp_clear_free) != NULL) + return 1; + else + return 0; + } diff --git a/openssl/crypto/ec/ec_print.c b/openssl/crypto/ec/ec_print.c new file mode 100644 index 000000000..f7c8a303a --- /dev/null +++ b/openssl/crypto/ec/ec_print.c @@ -0,0 +1,195 @@ +/* crypto/ec/ec_print.c */ +/* ==================================================================== + * 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). + * + */ + +#include <openssl/crypto.h> +#include "ec_lcl.h" + +BIGNUM *EC_POINT_point2bn(const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form, + BIGNUM *ret, + BN_CTX *ctx) + { + size_t buf_len=0; + unsigned char *buf; + + buf_len = EC_POINT_point2oct(group, point, form, + NULL, 0, ctx); + if (buf_len == 0) + return NULL; + + if ((buf = OPENSSL_malloc(buf_len)) == NULL) + return NULL; + + if (!EC_POINT_point2oct(group, point, form, buf, buf_len, ctx)) + { + OPENSSL_free(buf); + return NULL; + } + + ret = BN_bin2bn(buf, buf_len, ret); + + OPENSSL_free(buf); + + return ret; +} + +EC_POINT *EC_POINT_bn2point(const EC_GROUP *group, + const BIGNUM *bn, + EC_POINT *point, + BN_CTX *ctx) + { + size_t buf_len=0; + unsigned char *buf; + EC_POINT *ret; + + if ((buf_len = BN_num_bytes(bn)) == 0) return NULL; + buf = OPENSSL_malloc(buf_len); + if (buf == NULL) + return NULL; + + if (!BN_bn2bin(bn, buf)) + { + OPENSSL_free(buf); + return NULL; + } + + if (point == NULL) + { + if ((ret = EC_POINT_new(group)) == NULL) + { + OPENSSL_free(buf); + return NULL; + } + } + else + ret = point; + + if (!EC_POINT_oct2point(group, ret, buf, buf_len, ctx)) + { + if (point == NULL) + EC_POINT_clear_free(ret); + OPENSSL_free(buf); + return NULL; + } + + OPENSSL_free(buf); + return ret; + } + +static const char *HEX_DIGITS = "0123456789ABCDEF"; + +/* the return value must be freed (using OPENSSL_free()) */ +char *EC_POINT_point2hex(const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form, + BN_CTX *ctx) + { + char *ret, *p; + size_t buf_len=0,i; + unsigned char *buf, *pbuf; + + buf_len = EC_POINT_point2oct(group, point, form, + NULL, 0, ctx); + if (buf_len == 0) + return NULL; + + if ((buf = OPENSSL_malloc(buf_len)) == NULL) + return NULL; + + if (!EC_POINT_point2oct(group, point, form, buf, buf_len, ctx)) + { + OPENSSL_free(buf); + return NULL; + } + + ret = (char *)OPENSSL_malloc(buf_len*2+2); + if (ret == NULL) + { + OPENSSL_free(buf); + return NULL; + } + p = ret; + pbuf = buf; + for (i=buf_len; i > 0; i--) + { + int v = (int) *(pbuf++); + *(p++)=HEX_DIGITS[v>>4]; + *(p++)=HEX_DIGITS[v&0x0F]; + } + *p='\0'; + + OPENSSL_free(buf); + + return ret; + } + +EC_POINT *EC_POINT_hex2point(const EC_GROUP *group, + const char *buf, + EC_POINT *point, + BN_CTX *ctx) + { + EC_POINT *ret=NULL; + BIGNUM *tmp_bn=NULL; + + if (!BN_hex2bn(&tmp_bn, buf)) + return NULL; + + ret = EC_POINT_bn2point(group, tmp_bn, point, ctx); + + BN_clear_free(tmp_bn); + + return ret; + } diff --git a/openssl/crypto/ec/ecp_mont.c b/openssl/crypto/ec/ecp_mont.c new file mode 100644 index 000000000..9fc4a466a --- /dev/null +++ b/openssl/crypto/ec/ecp_mont.c @@ -0,0 +1,315 @@ +/* crypto/ec/ecp_mont.c */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ +/* ==================================================================== + * Copyright (c) 1998-2001 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 "ec_lcl.h" + + +const EC_METHOD *EC_GFp_mont_method(void) + { + static const EC_METHOD ret = { + NID_X9_62_prime_field, + ec_GFp_mont_group_init, + ec_GFp_mont_group_finish, + ec_GFp_mont_group_clear_finish, + ec_GFp_mont_group_copy, + ec_GFp_mont_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_simple_point_get_affine_coordinates, + ec_GFp_simple_set_compressed_coordinates, + ec_GFp_simple_point2oct, + ec_GFp_simple_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, + 0 /* mul */, + 0 /* precompute_mult */, + 0 /* have_precompute_mult */, + ec_GFp_mont_field_mul, + ec_GFp_mont_field_sqr, + 0 /* field_div */, + ec_GFp_mont_field_encode, + ec_GFp_mont_field_decode, + ec_GFp_mont_field_set_to_one }; + + return &ret; + } + + +int ec_GFp_mont_group_init(EC_GROUP *group) + { + int ok; + + ok = ec_GFp_simple_group_init(group); + group->field_data1 = NULL; + group->field_data2 = NULL; + return ok; + } + + +void ec_GFp_mont_group_finish(EC_GROUP *group) + { + if (group->field_data1 != NULL) + { + BN_MONT_CTX_free(group->field_data1); + group->field_data1 = NULL; + } + if (group->field_data2 != NULL) + { + BN_free(group->field_data2); + group->field_data2 = NULL; + } + ec_GFp_simple_group_finish(group); + } + + +void ec_GFp_mont_group_clear_finish(EC_GROUP *group) + { + if (group->field_data1 != NULL) + { + BN_MONT_CTX_free(group->field_data1); + group->field_data1 = NULL; + } + if (group->field_data2 != NULL) + { + BN_clear_free(group->field_data2); + group->field_data2 = NULL; + } + ec_GFp_simple_group_clear_finish(group); + } + + +int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) + { + if (dest->field_data1 != NULL) + { + BN_MONT_CTX_free(dest->field_data1); + dest->field_data1 = NULL; + } + if (dest->field_data2 != NULL) + { + BN_clear_free(dest->field_data2); + dest->field_data2 = NULL; + } + + if (!ec_GFp_simple_group_copy(dest, src)) return 0; + + if (src->field_data1 != NULL) + { + dest->field_data1 = BN_MONT_CTX_new(); + if (dest->field_data1 == NULL) return 0; + if (!BN_MONT_CTX_copy(dest->field_data1, src->field_data1)) goto err; + } + if (src->field_data2 != NULL) + { + dest->field_data2 = BN_dup(src->field_data2); + if (dest->field_data2 == NULL) goto err; + } + + return 1; + + err: + if (dest->field_data1 != NULL) + { + BN_MONT_CTX_free(dest->field_data1); + dest->field_data1 = NULL; + } + return 0; + } + + +int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + BN_MONT_CTX *mont = NULL; + BIGNUM *one = NULL; + int ret = 0; + + if (group->field_data1 != NULL) + { + BN_MONT_CTX_free(group->field_data1); + group->field_data1 = NULL; + } + if (group->field_data2 != NULL) + { + BN_free(group->field_data2); + group->field_data2 = NULL; + } + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + mont = BN_MONT_CTX_new(); + if (mont == NULL) goto err; + if (!BN_MONT_CTX_set(mont, p, ctx)) + { + ECerr(EC_F_EC_GFP_MONT_GROUP_SET_CURVE, ERR_R_BN_LIB); + goto err; + } + one = BN_new(); + if (one == NULL) goto err; + if (!BN_to_montgomery(one, BN_value_one(), mont, ctx)) goto err; + + group->field_data1 = mont; + mont = NULL; + group->field_data2 = one; + one = NULL; + + ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx); + + if (!ret) + { + BN_MONT_CTX_free(group->field_data1); + group->field_data1 = NULL; + BN_free(group->field_data2); + group->field_data2 = NULL; + } + + err: + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + if (mont != NULL) + BN_MONT_CTX_free(mont); + return ret; + } + + +int ec_GFp_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + if (group->field_data1 == NULL) + { + ECerr(EC_F_EC_GFP_MONT_FIELD_MUL, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_mod_mul_montgomery(r, a, b, group->field_data1, ctx); + } + + +int ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) + { + if (group->field_data1 == NULL) + { + ECerr(EC_F_EC_GFP_MONT_FIELD_SQR, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_mod_mul_montgomery(r, a, a, group->field_data1, ctx); + } + + +int ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) + { + if (group->field_data1 == NULL) + { + ECerr(EC_F_EC_GFP_MONT_FIELD_ENCODE, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_to_montgomery(r, a, (BN_MONT_CTX *)group->field_data1, ctx); + } + + +int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) + { + if (group->field_data1 == NULL) + { + ECerr(EC_F_EC_GFP_MONT_FIELD_DECODE, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_from_montgomery(r, a, group->field_data1, ctx); + } + + +int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r, BN_CTX *ctx) + { + if (group->field_data2 == NULL) + { + ECerr(EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE, EC_R_NOT_INITIALIZED); + return 0; + } + + if (!BN_copy(r, group->field_data2)) return 0; + return 1; + } diff --git a/openssl/crypto/ec/ecp_nist.c b/openssl/crypto/ec/ecp_nist.c new file mode 100644 index 000000000..71893d5ea --- /dev/null +++ b/openssl/crypto/ec/ecp_nist.c @@ -0,0 +1,236 @@ +/* crypto/ec/ecp_nist.c */ +/* + * Written by Nils Larsch 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. + * Portions of this software developed by SUN MICROSYSTEMS, INC., + * and contributed to the OpenSSL project. + */ + +#include <limits.h> + +#include <openssl/err.h> +#include <openssl/obj_mac.h> +#include "ec_lcl.h" + +const EC_METHOD *EC_GFp_nist_method(void) + { + static const EC_METHOD ret = { + NID_X9_62_prime_field, + ec_GFp_simple_group_init, + ec_GFp_simple_group_finish, + ec_GFp_simple_group_clear_finish, + ec_GFp_nist_group_copy, + ec_GFp_nist_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_simple_point_get_affine_coordinates, + ec_GFp_simple_set_compressed_coordinates, + ec_GFp_simple_point2oct, + ec_GFp_simple_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, + 0 /* mul */, + 0 /* precompute_mult */, + 0 /* 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; + } + +#if BN_BITS2 == 64 +#define NO_32_BIT_TYPE +#endif + +int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src) + { + dest->field_mod_func = src->field_mod_func; + + return ec_GFp_simple_group_copy(dest, src); + } + +int ec_GFp_nist_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 *tmp_bn; + + if (ctx == NULL) + if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0; + + BN_CTX_start(ctx); + if ((tmp_bn = BN_CTX_get(ctx)) == NULL) goto err; + + 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 + { + ECerr(EC_F_EC_GFP_NIST_GROUP_SET_CURVE, EC_R_NOT_A_NIST_PRIME); + goto err; + } + + 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; + } + + +int ec_GFp_nist_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) + { + int ret=0; + BN_CTX *ctx_new=NULL; + + if (!group || !r || !a || !b) + { + ECerr(EC_F_EC_GFP_NIST_FIELD_MUL, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + if (!ctx) + if ((ctx_new = ctx = BN_CTX_new()) == NULL) goto err; + + if (!BN_mul(r, a, b, ctx)) goto err; + if (!group->field_mod_func(r, r, &group->field, ctx)) + goto err; + + ret=1; +err: + if (ctx_new) + BN_CTX_free(ctx_new); + return ret; + } + + +int ec_GFp_nist_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) + { + int ret=0; + BN_CTX *ctx_new=NULL; + + if (!group || !r || !a) + { + ECerr(EC_F_EC_GFP_NIST_FIELD_SQR, EC_R_PASSED_NULL_PARAMETER); + goto err; + } + if (!ctx) + if ((ctx_new = ctx = BN_CTX_new()) == NULL) goto err; + + if (!BN_sqr(r, a, ctx)) goto err; + if (!group->field_mod_func(r, r, &group->field, ctx)) + goto err; + + ret=1; +err: + if (ctx_new) + BN_CTX_free(ctx_new); + return ret; + } diff --git a/openssl/crypto/ec/ecp_smpl.c b/openssl/crypto/ec/ecp_smpl.c new file mode 100644 index 000000000..4d26f8bdf --- /dev/null +++ b/openssl/crypto/ec/ecp_smpl.c @@ -0,0 +1,1716 @@ +/* crypto/ec/ecp_smpl.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" + +const EC_METHOD *EC_GFp_simple_method(void) + { + static const EC_METHOD ret = { + NID_X9_62_prime_field, + ec_GFp_simple_group_init, + ec_GFp_simple_group_finish, + ec_GFp_simple_group_clear_finish, + ec_GFp_simple_group_copy, + ec_GFp_simple_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_simple_point_get_affine_coordinates, + ec_GFp_simple_set_compressed_coordinates, + ec_GFp_simple_point2oct, + ec_GFp_simple_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, + 0 /* mul */, + 0 /* precompute_mult */, + 0 /* have_precompute_mult */, + ec_GFp_simple_field_mul, + ec_GFp_simple_field_sqr, + 0 /* field_div */, + 0 /* field_encode */, + 0 /* field_decode */, + 0 /* field_set_to_one */ }; + + return &ret; + } + + +/* Most method functions in this file are designed to work with + * non-trivial representations of field elements if necessary + * (see ecp_mont.c): while standard modular addition and subtraction + * are used, the field_mul and field_sqr methods will be used for + * multiplication, and field_encode and field_decode (if defined) + * will be used for converting between representations. + + * Functions ec_GFp_simple_points_make_affine() and + * ec_GFp_simple_point_get_affine_coordinates() specifically assume + * that if a non-trivial representation is used, it is a Montgomery + * representation (i.e. 'encoding' means multiplying by some factor R). + */ + + +int ec_GFp_simple_group_init(EC_GROUP *group) + { + BN_init(&group->field); + BN_init(&group->a); + BN_init(&group->b); + group->a_is_minus3 = 0; + return 1; + } + + +void ec_GFp_simple_group_finish(EC_GROUP *group) + { + BN_free(&group->field); + BN_free(&group->a); + BN_free(&group->b); + } + + +void ec_GFp_simple_group_clear_finish(EC_GROUP *group) + { + BN_clear_free(&group->field); + BN_clear_free(&group->a); + BN_clear_free(&group->b); + } + + +int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) + { + if (!BN_copy(&dest->field, &src->field)) return 0; + if (!BN_copy(&dest->a, &src->a)) return 0; + if (!BN_copy(&dest->b, &src->b)) return 0; + + dest->a_is_minus3 = src->a_is_minus3; + + return 1; + } + + +int ec_GFp_simple_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 *tmp_a; + + /* p must be a prime > 3 */ + if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) + { + ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, EC_R_INVALID_FIELD); + return 0; + } + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + BN_CTX_start(ctx); + tmp_a = BN_CTX_get(ctx); + if (tmp_a == NULL) goto err; + + /* group->field */ + if (!BN_copy(&group->field, p)) goto err; + BN_set_negative(&group->field, 0); + + /* group->a */ + if (!BN_nnmod(tmp_a, a, p, ctx)) goto err; + if (group->meth->field_encode) + { if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) goto err; } + else + if (!BN_copy(&group->a, tmp_a)) goto err; + + /* group->b */ + if (!BN_nnmod(&group->b, b, p, ctx)) goto err; + if (group->meth->field_encode) + if (!group->meth->field_encode(group, &group->b, &group->b, ctx)) goto err; + + /* group->a_is_minus3 */ + if (!BN_add_word(tmp_a, 3)) goto err; + group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field)); + + ret = 1; + + err: + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) + { + int ret = 0; + BN_CTX *new_ctx = NULL; + + if (p != NULL) + { + if (!BN_copy(p, &group->field)) return 0; + } + + if (a != NULL || b != NULL) + { + if (group->meth->field_decode) + { + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + if (a != NULL) + { + if (!group->meth->field_decode(group, a, &group->a, ctx)) goto err; + } + if (b != NULL) + { + if (!group->meth->field_decode(group, b, &group->b, ctx)) goto err; + } + } + else + { + if (a != NULL) + { + if (!BN_copy(a, &group->a)) goto err; + } + if (b != NULL) + { + if (!BN_copy(b, &group->b)) goto err; + } + } + } + + ret = 1; + + err: + if (new_ctx) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_group_get_degree(const EC_GROUP *group) + { + return BN_num_bits(&group->field); + } + + +int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) + { + int ret = 0; + BIGNUM *a,*b,*order,*tmp_1,*tmp_2; + const BIGNUM *p = &group->field; + BN_CTX *new_ctx = NULL; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + { + ECerr(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT, ERR_R_MALLOC_FAILURE); + goto err; + } + } + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + tmp_1 = BN_CTX_get(ctx); + tmp_2 = BN_CTX_get(ctx); + order = BN_CTX_get(ctx); + if (order == NULL) goto err; + + if (group->meth->field_decode) + { + if (!group->meth->field_decode(group, a, &group->a, ctx)) goto err; + if (!group->meth->field_decode(group, b, &group->b, ctx)) goto err; + } + else + { + if (!BN_copy(a, &group->a)) goto err; + if (!BN_copy(b, &group->b)) goto err; + } + + /* check the discriminant: + * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p) + * 0 =< a, b < p */ + if (BN_is_zero(a)) + { + if (BN_is_zero(b)) goto err; + } + else if (!BN_is_zero(b)) + { + if (!BN_mod_sqr(tmp_1, a, p, ctx)) goto err; + if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx)) goto err; + if (!BN_lshift(tmp_1, tmp_2, 2)) goto err; + /* tmp_1 = 4*a^3 */ + + if (!BN_mod_sqr(tmp_2, b, p, ctx)) goto err; + if (!BN_mul_word(tmp_2, 27)) goto err; + /* tmp_2 = 27*b^2 */ + + if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx)) goto err; + if (BN_is_zero(a)) goto err; + } + ret = 1; + +err: + if (ctx != NULL) + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_point_init(EC_POINT *point) + { + BN_init(&point->X); + BN_init(&point->Y); + BN_init(&point->Z); + point->Z_is_one = 0; + + return 1; + } + + +void ec_GFp_simple_point_finish(EC_POINT *point) + { + BN_free(&point->X); + BN_free(&point->Y); + BN_free(&point->Z); + } + + +void ec_GFp_simple_point_clear_finish(EC_POINT *point) + { + BN_clear_free(&point->X); + BN_clear_free(&point->Y); + BN_clear_free(&point->Z); + point->Z_is_one = 0; + } + + +int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) + { + if (!BN_copy(&dest->X, &src->X)) return 0; + if (!BN_copy(&dest->Y, &src->Y)) return 0; + if (!BN_copy(&dest->Z, &src->Z)) return 0; + dest->Z_is_one = src->Z_is_one; + + return 1; + } + + +int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point) + { + point->Z_is_one = 0; + BN_zero(&point->Z); + return 1; + } + + +int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + int ret = 0; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + if (x != NULL) + { + if (!BN_nnmod(&point->X, x, &group->field, ctx)) goto err; + if (group->meth->field_encode) + { + if (!group->meth->field_encode(group, &point->X, &point->X, ctx)) goto err; + } + } + + if (y != NULL) + { + if (!BN_nnmod(&point->Y, y, &group->field, ctx)) goto err; + if (group->meth->field_encode) + { + if (!group->meth->field_encode(group, &point->Y, &point->Y, ctx)) goto err; + } + } + + if (z != NULL) + { + int Z_is_one; + + if (!BN_nnmod(&point->Z, z, &group->field, ctx)) goto err; + Z_is_one = BN_is_one(&point->Z); + if (group->meth->field_encode) + { + if (Z_is_one && (group->meth->field_set_to_one != 0)) + { + if (!group->meth->field_set_to_one(group, &point->Z, ctx)) goto err; + } + else + { + if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx)) goto err; + } + } + point->Z_is_one = Z_is_one; + } + + ret = 1; + + err: + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point, + BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + int ret = 0; + + if (group->meth->field_decode != 0) + { + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + if (x != NULL) + { + if (!group->meth->field_decode(group, x, &point->X, ctx)) goto err; + } + if (y != NULL) + { + if (!group->meth->field_decode(group, y, &point->Y, ctx)) goto err; + } + if (z != NULL) + { + if (!group->meth->field_decode(group, z, &point->Z, ctx)) goto err; + } + } + else + { + if (x != NULL) + { + if (!BN_copy(x, &point->X)) goto err; + } + if (y != NULL) + { + if (!BN_copy(y, &point->Y)) goto err; + } + if (z != NULL) + { + if (!BN_copy(z, &point->Z)) goto err; + } + } + + ret = 1; + + err: + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx) + { + if (x == NULL || y == NULL) + { + /* unlike for projective coordinates, we do not tolerate this */ + ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y, BN_value_one(), ctx); + } + + +int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, + BIGNUM *x, BIGNUM *y, BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + BIGNUM *Z, *Z_1, *Z_2, *Z_3; + const BIGNUM *Z_; + int ret = 0; + + if (EC_POINT_is_at_infinity(group, point)) + { + ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, EC_R_POINT_AT_INFINITY); + return 0; + } + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + BN_CTX_start(ctx); + Z = BN_CTX_get(ctx); + Z_1 = BN_CTX_get(ctx); + Z_2 = BN_CTX_get(ctx); + Z_3 = BN_CTX_get(ctx); + if (Z_3 == NULL) goto err; + + /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ + + if (group->meth->field_decode) + { + if (!group->meth->field_decode(group, Z, &point->Z, ctx)) goto err; + Z_ = Z; + } + else + { + Z_ = &point->Z; + } + + if (BN_is_one(Z_)) + { + if (group->meth->field_decode) + { + if (x != NULL) + { + if (!group->meth->field_decode(group, x, &point->X, ctx)) goto err; + } + if (y != NULL) + { + if (!group->meth->field_decode(group, y, &point->Y, ctx)) goto err; + } + } + else + { + if (x != NULL) + { + if (!BN_copy(x, &point->X)) goto err; + } + if (y != NULL) + { + if (!BN_copy(y, &point->Y)) goto err; + } + } + } + else + { + if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) + { + ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, ERR_R_BN_LIB); + goto err; + } + + if (group->meth->field_encode == 0) + { + /* field_sqr works on standard representation */ + if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) goto err; + } + else + { + if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) goto err; + } + + if (x != NULL) + { + /* in the Montgomery case, field_mul will cancel out Montgomery factor in X: */ + if (!group->meth->field_mul(group, x, &point->X, Z_2, ctx)) goto err; + } + + if (y != NULL) + { + if (group->meth->field_encode == 0) + { + /* field_mul works on standard representation */ + if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) goto err; + } + else + { + if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) goto err; + } + + /* in the Montgomery case, field_mul will cancel out Montgomery factor in Y: */ + if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) goto err; + } + } + + ret = 1; + + err: + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + 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 *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; + int ret = 0; + + if (a == b) + return EC_POINT_dbl(group, r, a, ctx); + if (EC_POINT_is_at_infinity(group, a)) + return EC_POINT_copy(r, b); + if (EC_POINT_is_at_infinity(group, b)) + return EC_POINT_copy(r, a); + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + BN_CTX_start(ctx); + n0 = BN_CTX_get(ctx); + n1 = BN_CTX_get(ctx); + n2 = BN_CTX_get(ctx); + n3 = BN_CTX_get(ctx); + n4 = BN_CTX_get(ctx); + n5 = BN_CTX_get(ctx); + n6 = BN_CTX_get(ctx); + if (n6 == NULL) goto end; + + /* Note that in this function we must not read components of 'a' or 'b' + * once we have written the corresponding components of 'r'. + * ('r' might be one of 'a' or 'b'.) + */ + + /* n1, n2 */ + if (b->Z_is_one) + { + if (!BN_copy(n1, &a->X)) goto end; + if (!BN_copy(n2, &a->Y)) goto end; + /* n1 = X_a */ + /* n2 = Y_a */ + } + else + { + if (!field_sqr(group, n0, &b->Z, ctx)) goto end; + if (!field_mul(group, n1, &a->X, n0, ctx)) goto end; + /* n1 = X_a * Z_b^2 */ + + if (!field_mul(group, n0, n0, &b->Z, ctx)) goto end; + if (!field_mul(group, n2, &a->Y, n0, ctx)) goto end; + /* n2 = Y_a * Z_b^3 */ + } + + /* n3, n4 */ + if (a->Z_is_one) + { + if (!BN_copy(n3, &b->X)) goto end; + if (!BN_copy(n4, &b->Y)) goto end; + /* n3 = X_b */ + /* n4 = Y_b */ + } + else + { + if (!field_sqr(group, n0, &a->Z, ctx)) goto end; + if (!field_mul(group, n3, &b->X, n0, ctx)) goto end; + /* n3 = X_b * Z_a^2 */ + + if (!field_mul(group, n0, n0, &a->Z, ctx)) goto end; + if (!field_mul(group, n4, &b->Y, n0, ctx)) goto end; + /* n4 = Y_b * Z_a^3 */ + } + + /* n5, n6 */ + if (!BN_mod_sub_quick(n5, n1, n3, p)) goto end; + if (!BN_mod_sub_quick(n6, n2, n4, p)) goto end; + /* n5 = n1 - n3 */ + /* n6 = n2 - n4 */ + + if (BN_is_zero(n5)) + { + if (BN_is_zero(n6)) + { + /* a is the same point as b */ + BN_CTX_end(ctx); + ret = EC_POINT_dbl(group, r, a, ctx); + ctx = NULL; + goto end; + } + else + { + /* a is the inverse of b */ + BN_zero(&r->Z); + r->Z_is_one = 0; + ret = 1; + goto end; + } + } + + /* 'n7', 'n8' */ + if (!BN_mod_add_quick(n1, n1, n3, p)) goto end; + if (!BN_mod_add_quick(n2, n2, n4, p)) goto end; + /* 'n7' = n1 + n3 */ + /* 'n8' = n2 + n4 */ + + /* Z_r */ + if (a->Z_is_one && b->Z_is_one) + { + if (!BN_copy(&r->Z, n5)) goto end; + } + else + { + if (a->Z_is_one) + { if (!BN_copy(n0, &b->Z)) goto end; } + else if (b->Z_is_one) + { if (!BN_copy(n0, &a->Z)) goto end; } + else + { if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) goto end; } + if (!field_mul(group, &r->Z, n0, n5, ctx)) goto end; + } + r->Z_is_one = 0; + /* Z_r = Z_a * Z_b * n5 */ + + /* X_r */ + if (!field_sqr(group, n0, n6, ctx)) goto end; + if (!field_sqr(group, n4, n5, ctx)) goto end; + if (!field_mul(group, n3, n1, n4, ctx)) goto end; + if (!BN_mod_sub_quick(&r->X, n0, n3, p)) goto end; + /* X_r = n6^2 - n5^2 * 'n7' */ + + /* 'n9' */ + if (!BN_mod_lshift1_quick(n0, &r->X, p)) goto end; + if (!BN_mod_sub_quick(n0, n3, n0, p)) goto end; + /* n9 = n5^2 * 'n7' - 2 * X_r */ + + /* Y_r */ + if (!field_mul(group, n0, n0, n6, ctx)) goto end; + if (!field_mul(group, n5, n4, n5, ctx)) goto end; /* now n5 is n5^3 */ + if (!field_mul(group, n1, n2, n5, ctx)) goto end; + if (!BN_mod_sub_quick(n0, n0, n1, p)) goto end; + if (BN_is_odd(n0)) + if (!BN_add(n0, n0, p)) goto end; + /* now 0 <= n0 < 2*p, and n0 is even */ + if (!BN_rshift1(&r->Y, n0)) goto end; + /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ + + ret = 1; + + end: + if (ctx) /* otherwise we already called BN_CTX_end */ + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) + { + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *n0, *n1, *n2, *n3; + int ret = 0; + + if (EC_POINT_is_at_infinity(group, a)) + { + BN_zero(&r->Z); + r->Z_is_one = 0; + return 1; + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + BN_CTX_start(ctx); + n0 = BN_CTX_get(ctx); + n1 = BN_CTX_get(ctx); + n2 = BN_CTX_get(ctx); + n3 = BN_CTX_get(ctx); + if (n3 == NULL) goto err; + + /* Note that in this function we must not read components of 'a' + * once we have written the corresponding components of 'r'. + * ('r' might the same as 'a'.) + */ + + /* n1 */ + if (a->Z_is_one) + { + if (!field_sqr(group, n0, &a->X, ctx)) goto err; + if (!BN_mod_lshift1_quick(n1, n0, p)) goto err; + if (!BN_mod_add_quick(n0, n0, n1, p)) goto err; + if (!BN_mod_add_quick(n1, n0, &group->a, p)) goto err; + /* n1 = 3 * X_a^2 + a_curve */ + } + else if (group->a_is_minus3) + { + if (!field_sqr(group, n1, &a->Z, ctx)) goto err; + if (!BN_mod_add_quick(n0, &a->X, n1, p)) goto err; + if (!BN_mod_sub_quick(n2, &a->X, n1, p)) goto err; + if (!field_mul(group, n1, n0, n2, ctx)) goto err; + if (!BN_mod_lshift1_quick(n0, n1, p)) goto err; + if (!BN_mod_add_quick(n1, n0, n1, p)) goto err; + /* n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) + * = 3 * X_a^2 - 3 * Z_a^4 */ + } + else + { + if (!field_sqr(group, n0, &a->X, ctx)) goto err; + if (!BN_mod_lshift1_quick(n1, n0, p)) goto err; + if (!BN_mod_add_quick(n0, n0, n1, p)) goto err; + if (!field_sqr(group, n1, &a->Z, ctx)) goto err; + if (!field_sqr(group, n1, n1, ctx)) goto err; + if (!field_mul(group, n1, n1, &group->a, ctx)) goto err; + if (!BN_mod_add_quick(n1, n1, n0, p)) goto err; + /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */ + } + + /* Z_r */ + if (a->Z_is_one) + { + if (!BN_copy(n0, &a->Y)) goto err; + } + else + { + if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) goto err; + } + if (!BN_mod_lshift1_quick(&r->Z, n0, p)) goto err; + r->Z_is_one = 0; + /* Z_r = 2 * Y_a * Z_a */ + + /* n2 */ + if (!field_sqr(group, n3, &a->Y, ctx)) goto err; + if (!field_mul(group, n2, &a->X, n3, ctx)) goto err; + if (!BN_mod_lshift_quick(n2, n2, 2, p)) goto err; + /* n2 = 4 * X_a * Y_a^2 */ + + /* X_r */ + if (!BN_mod_lshift1_quick(n0, n2, p)) goto err; + if (!field_sqr(group, &r->X, n1, ctx)) goto err; + if (!BN_mod_sub_quick(&r->X, &r->X, n0, p)) goto err; + /* X_r = n1^2 - 2 * n2 */ + + /* n3 */ + if (!field_sqr(group, n0, n3, ctx)) goto err; + if (!BN_mod_lshift_quick(n3, n0, 3, p)) goto err; + /* n3 = 8 * Y_a^4 */ + + /* Y_r */ + if (!BN_mod_sub_quick(n0, n2, &r->X, p)) goto err; + if (!field_mul(group, n0, n1, n0, ctx)) goto err; + if (!BN_mod_sub_quick(&r->Y, n0, n3, p)) goto err; + /* Y_r = n1 * (n2 - X_r) - n3 */ + + ret = 1; + + err: + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) + { + if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y)) + /* point is its own inverse */ + return 1; + + return BN_usub(&point->Y, &group->field, &point->Y); + } + + +int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) + { + return BN_is_zero(&point->Z); + } + + +int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) + { + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *rh, *tmp, *Z4, *Z6; + int ret = -1; + + if (EC_POINT_is_at_infinity(group, point)) + return 1; + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return -1; + } + + BN_CTX_start(ctx); + rh = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + Z4 = BN_CTX_get(ctx); + Z6 = BN_CTX_get(ctx); + if (Z6 == NULL) goto err; + + /* We have a curve defined by a Weierstrass equation + * y^2 = x^3 + a*x + b. + * The point to consider is given in Jacobian projective coordinates + * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). + * Substituting this and multiplying by Z^6 transforms the above equation into + * Y^2 = X^3 + a*X*Z^4 + b*Z^6. + * To test this, we add up the right-hand side in 'rh'. + */ + + /* rh := X^2 */ + if (!field_sqr(group, rh, &point->X, ctx)) goto err; + + if (!point->Z_is_one) + { + if (!field_sqr(group, tmp, &point->Z, ctx)) goto err; + if (!field_sqr(group, Z4, tmp, ctx)) goto err; + if (!field_mul(group, Z6, Z4, tmp, ctx)) goto err; + + /* rh := (rh + a*Z^4)*X */ + if (group->a_is_minus3) + { + if (!BN_mod_lshift1_quick(tmp, Z4, p)) goto err; + if (!BN_mod_add_quick(tmp, tmp, Z4, p)) goto err; + if (!BN_mod_sub_quick(rh, rh, tmp, p)) goto err; + if (!field_mul(group, rh, rh, &point->X, ctx)) goto err; + } + else + { + if (!field_mul(group, tmp, Z4, &group->a, ctx)) goto err; + if (!BN_mod_add_quick(rh, rh, tmp, p)) goto err; + if (!field_mul(group, rh, rh, &point->X, ctx)) goto err; + } + + /* rh := rh + b*Z^6 */ + if (!field_mul(group, tmp, &group->b, Z6, ctx)) goto err; + if (!BN_mod_add_quick(rh, rh, tmp, p)) goto err; + } + else + { + /* point->Z_is_one */ + + /* rh := (rh + a)*X */ + if (!BN_mod_add_quick(rh, rh, &group->a, p)) goto err; + if (!field_mul(group, rh, rh, &point->X, ctx)) goto err; + /* rh := rh + b */ + if (!BN_mod_add_quick(rh, rh, &group->b, p)) goto err; + } + + /* 'lh' := Y^2 */ + if (!field_sqr(group, tmp, &point->Y, ctx)) goto err; + + ret = (0 == BN_ucmp(tmp, rh)); + + err: + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) + { + /* return values: + * -1 error + * 0 equal (in affine coordinates) + * 1 not equal + */ + + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + BN_CTX *new_ctx = NULL; + BIGNUM *tmp1, *tmp2, *Za23, *Zb23; + const BIGNUM *tmp1_, *tmp2_; + int ret = -1; + + if (EC_POINT_is_at_infinity(group, a)) + { + return EC_POINT_is_at_infinity(group, b) ? 0 : 1; + } + + if (a->Z_is_one && b->Z_is_one) + { + return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return -1; + } + + BN_CTX_start(ctx); + tmp1 = BN_CTX_get(ctx); + tmp2 = BN_CTX_get(ctx); + Za23 = BN_CTX_get(ctx); + Zb23 = BN_CTX_get(ctx); + if (Zb23 == NULL) goto end; + + /* We have to decide whether + * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), + * or equivalently, whether + * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). + */ + + if (!b->Z_is_one) + { + if (!field_sqr(group, Zb23, &b->Z, ctx)) goto end; + if (!field_mul(group, tmp1, &a->X, Zb23, ctx)) goto end; + tmp1_ = tmp1; + } + else + tmp1_ = &a->X; + if (!a->Z_is_one) + { + if (!field_sqr(group, Za23, &a->Z, ctx)) goto end; + if (!field_mul(group, tmp2, &b->X, Za23, ctx)) goto end; + tmp2_ = tmp2; + } + else + tmp2_ = &b->X; + + /* compare X_a*Z_b^2 with X_b*Z_a^2 */ + if (BN_cmp(tmp1_, tmp2_) != 0) + { + ret = 1; /* points differ */ + goto end; + } + + + if (!b->Z_is_one) + { + if (!field_mul(group, Zb23, Zb23, &b->Z, ctx)) goto end; + if (!field_mul(group, tmp1, &a->Y, Zb23, ctx)) goto end; + /* tmp1_ = tmp1 */ + } + else + tmp1_ = &a->Y; + if (!a->Z_is_one) + { + if (!field_mul(group, Za23, Za23, &a->Z, ctx)) goto end; + if (!field_mul(group, tmp2, &b->Y, Za23, ctx)) goto end; + /* tmp2_ = tmp2 */ + } + else + tmp2_ = &b->Y; + + /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */ + if (BN_cmp(tmp1_, tmp2_) != 0) + { + ret = 1; /* points differ */ + goto end; + } + + /* points are equal */ + ret = 0; + + end: + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + BIGNUM *x, *y; + int ret = 0; + + if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) + return 1; + + 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 (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; + if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; + if (!point->Z_is_one) + { + ECerr(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + + err: + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; + } + + +int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx) + { + BN_CTX *new_ctx = NULL; + BIGNUM *tmp0, *tmp1; + size_t pow2 = 0; + BIGNUM **heap = NULL; + size_t i; + int ret = 0; + + if (num == 0) + return 1; + + if (ctx == NULL) + { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) + return 0; + } + + BN_CTX_start(ctx); + tmp0 = BN_CTX_get(ctx); + tmp1 = BN_CTX_get(ctx); + if (tmp0 == NULL || tmp1 == NULL) goto err; + + /* Before converting the individual points, compute inverses of all Z values. + * Modular inversion is rather slow, but luckily we can do with a single + * explicit inversion, plus about 3 multiplications per input value. + */ + + pow2 = 1; + while (num > pow2) + pow2 <<= 1; + /* Now pow2 is the smallest power of 2 satifsying pow2 >= num. + * We need twice that. */ + pow2 <<= 1; + + heap = OPENSSL_malloc(pow2 * sizeof heap[0]); + if (heap == NULL) goto err; + + /* The array is used as a binary tree, exactly as in heapsort: + * + * heap[1] + * heap[2] heap[3] + * heap[4] heap[5] heap[6] heap[7] + * heap[8]heap[9] heap[10]heap[11] heap[12]heap[13] heap[14] heap[15] + * + * We put the Z's in the last line; + * then we set each other node to the product of its two child-nodes (where + * empty or 0 entries are treated as ones); + * then we invert heap[1]; + * then we invert each other node by replacing it by the product of its + * parent (after inversion) and its sibling (before inversion). + */ + heap[0] = NULL; + for (i = pow2/2 - 1; i > 0; i--) + heap[i] = NULL; + for (i = 0; i < num; i++) + heap[pow2/2 + i] = &points[i]->Z; + for (i = pow2/2 + num; i < pow2; i++) + heap[i] = NULL; + + /* set each node to the product of its children */ + for (i = pow2/2 - 1; i > 0; i--) + { + heap[i] = BN_new(); + if (heap[i] == NULL) goto err; + + if (heap[2*i] != NULL) + { + if ((heap[2*i + 1] == NULL) || BN_is_zero(heap[2*i + 1])) + { + if (!BN_copy(heap[i], heap[2*i])) goto err; + } + else + { + if (BN_is_zero(heap[2*i])) + { + if (!BN_copy(heap[i], heap[2*i + 1])) goto err; + } + else + { + if (!group->meth->field_mul(group, heap[i], + heap[2*i], heap[2*i + 1], ctx)) goto err; + } + } + } + } + + /* invert heap[1] */ + if (!BN_is_zero(heap[1])) + { + if (!BN_mod_inverse(heap[1], heap[1], &group->field, ctx)) + { + ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB); + goto err; + } + } + if (group->meth->field_encode != 0) + { + /* in the Montgomery case, we just turned R*H (representing H) + * into 1/(R*H), but we need R*(1/H) (representing 1/H); + * i.e. we have need to multiply by the Montgomery factor twice */ + if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err; + if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err; + } + + /* set other heap[i]'s to their inverses */ + for (i = 2; i < pow2/2 + num; i += 2) + { + /* i is even */ + if ((heap[i + 1] != NULL) && !BN_is_zero(heap[i + 1])) + { + if (!group->meth->field_mul(group, tmp0, heap[i/2], heap[i + 1], ctx)) goto err; + if (!group->meth->field_mul(group, tmp1, heap[i/2], heap[i], ctx)) goto err; + if (!BN_copy(heap[i], tmp0)) goto err; + if (!BN_copy(heap[i + 1], tmp1)) goto err; + } + else + { + if (!BN_copy(heap[i], heap[i/2])) goto err; + } + } + + /* we have replaced all non-zero Z's by their inverses, now fix up all the points */ + for (i = 0; i < num; i++) + { + EC_POINT *p = points[i]; + + if (!BN_is_zero(&p->Z)) + { + /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ + + if (!group->meth->field_sqr(group, tmp1, &p->Z, ctx)) goto err; + if (!group->meth->field_mul(group, &p->X, &p->X, tmp1, ctx)) goto err; + + if (!group->meth->field_mul(group, tmp1, tmp1, &p->Z, ctx)) goto err; + if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp1, ctx)) goto err; + + if (group->meth->field_set_to_one != 0) + { + if (!group->meth->field_set_to_one(group, &p->Z, ctx)) goto err; + } + else + { + if (!BN_one(&p->Z)) goto err; + } + p->Z_is_one = 1; + } + } + + ret = 1; + + err: + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + if (heap != NULL) + { + /* heap[pow2/2] .. heap[pow2-1] have not been allocated locally! */ + for (i = pow2/2 - 1; i > 0; i--) + { + if (heap[i] != NULL) + BN_clear_free(heap[i]); + } + OPENSSL_free(heap); + } + return ret; + } + + +int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) + { + return BN_mod_mul(r, a, b, &group->field, ctx); + } + + +int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) + { + return BN_mod_sqr(r, a, &group->field, ctx); + } diff --git a/openssl/crypto/ec/ectest.c b/openssl/crypto/ec/ectest.c new file mode 100644 index 000000000..6148d553f --- /dev/null +++ b/openssl/crypto/ec/ectest.c @@ -0,0 +1,1344 @@ +/* crypto/ec/ectest.c */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ +/* ==================================================================== + * Copyright (c) 1998-2001 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 the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#ifdef FLAT_INC +#include "e_os.h" +#else +#include "../e_os.h" +#endif +#include <string.h> +#include <time.h> + + +#ifdef OPENSSL_NO_EC +int main(int argc, char * argv[]) { puts("Elliptic curves are disabled."); return 0; } +#else + + +#include <openssl/ec.h> +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#endif +#include <openssl/err.h> +#include <openssl/obj_mac.h> +#include <openssl/objects.h> +#include <openssl/rand.h> +#include <openssl/bn.h> + +#if defined(_MSC_VER) && defined(_MIPS_) && (_MSC_VER/100==12) +/* suppress "too big too optimize" warning */ +#pragma warning(disable:4959) +#endif + +#define ABORT do { \ + fflush(stdout); \ + fprintf(stderr, "%s:%d: ABORT\n", __FILE__, __LINE__); \ + ERR_print_errors_fp(stderr); \ + 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 + +#if 0 +static void timings(EC_GROUP *group, int type, BN_CTX *ctx) + { + clock_t clck; + int i, j; + BIGNUM *s; + BIGNUM *r[10], *r0[10]; + EC_POINT *P; + + s = BN_new(); + if (s == NULL) ABORT; + + fprintf(stdout, "Timings for %d-bit field, ", EC_GROUP_get_degree(group)); + if (!EC_GROUP_get_order(group, s, ctx)) ABORT; + fprintf(stdout, "%d-bit scalars ", (int)BN_num_bits(s)); + fflush(stdout); + + P = EC_POINT_new(group); + if (P == NULL) ABORT; + EC_POINT_copy(P, EC_GROUP_get0_generator(group)); + + for (i = 0; i < 10; i++) + { + if ((r[i] = BN_new()) == NULL) ABORT; + if (!BN_pseudo_rand(r[i], BN_num_bits(s), 0, 0)) ABORT; + if (type != TIMING_BASE_PT) + { + if ((r0[i] = BN_new()) == NULL) ABORT; + if (!BN_pseudo_rand(r0[i], BN_num_bits(s), 0, 0)) ABORT; + } + } + + clck = clock(); + for (i = 0; i < 10; i++) + { + for (j = 0; j < 10; j++) + { + if (!EC_POINT_mul(group, P, (type != TIMING_RAND_PT) ? r[i] : NULL, + (type != TIMING_BASE_PT) ? P : NULL, (type != TIMING_BASE_PT) ? r0[i] : NULL, ctx)) ABORT; + } + } + clck = clock() - clck; + + fprintf(stdout, "\n"); + +#ifdef CLOCKS_PER_SEC + /* "To determine the time in seconds, the value returned + * by the clock function should be divided by the value + * of the macro CLOCKS_PER_SEC." + * -- ISO/IEC 9899 */ +# define UNIT "s" +#else + /* "`CLOCKS_PER_SEC' undeclared (first use this function)" + * -- cc on NeXTstep/OpenStep */ +# define UNIT "units" +# define CLOCKS_PER_SEC 1 +#endif + + if (type == TIMING_BASE_PT) { + fprintf(stdout, "%i %s in %.2f " UNIT "\n", i*j, + "base point multiplications", (double)clck/CLOCKS_PER_SEC); + } else if (type == TIMING_RAND_PT) { + fprintf(stdout, "%i %s in %.2f " UNIT "\n", i*j, + "random point multiplications", (double)clck/CLOCKS_PER_SEC); + } else if (type == TIMING_SIMUL) { + fprintf(stdout, "%i %s in %.2f " UNIT "\n", i*j, + "s*P+t*Q operations", (double)clck/CLOCKS_PER_SEC); + } + fprintf(stdout, "average: %.4f " UNIT "\n", (double)clck/(CLOCKS_PER_SEC*i*j)); + + EC_POINT_free(P); + BN_free(s); + for (i = 0; i < 10; i++) + { + BN_free(r[i]); + if (type != TIMING_BASE_PT) BN_free(r0[i]); + } + } +#endif + +void prime_field_tests() + { + BN_CTX *ctx = NULL; + BIGNUM *p, *a, *b; + EC_GROUP *group; + EC_GROUP *P_160 = NULL, *P_192 = NULL, *P_224 = NULL, *P_256 = NULL, *P_384 = NULL, *P_521 = NULL; + EC_POINT *P, *Q, *R; + BIGNUM *x, *y, *z; + unsigned char buf[100]; + size_t i, len; + int k; + +#if 1 /* optional */ + ctx = BN_CTX_new(); + if (!ctx) ABORT; +#endif + + p = BN_new(); + a = BN_new(); + b = BN_new(); + if (!p || !a || !b) ABORT; + + if (!BN_hex2bn(&p, "17")) ABORT; + if (!BN_hex2bn(&a, "1")) ABORT; + if (!BN_hex2bn(&b, "1")) ABORT; + + group = EC_GROUP_new(EC_GFp_mont_method()); /* applications should use EC_GROUP_new_curve_GFp + * so that the library gets to choose the EC_METHOD */ + if (!group) ABORT; + + if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT; + + { + EC_GROUP *tmp; + tmp = EC_GROUP_new(EC_GROUP_method_of(group)); + if (!tmp) ABORT; + if (!EC_GROUP_copy(tmp, group)) ABORT; + EC_GROUP_free(group); + group = tmp; + } + + if (!EC_GROUP_get_curve_GFp(group, p, a, b, ctx)) ABORT; + + fprintf(stdout, "Curve defined by Weierstrass equation\n y^2 = x^3 + a*x + b (mod 0x"); + BN_print_fp(stdout, p); + fprintf(stdout, ")\n a = 0x"); + BN_print_fp(stdout, a); + fprintf(stdout, "\n b = 0x"); + BN_print_fp(stdout, b); + fprintf(stdout, "\n"); + + P = EC_POINT_new(group); + Q = EC_POINT_new(group); + R = EC_POINT_new(group); + if (!P || !Q || !R) ABORT; + + if (!EC_POINT_set_to_infinity(group, P)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + buf[0] = 0; + if (!EC_POINT_oct2point(group, Q, buf, 1, ctx)) ABORT; + + if (!EC_POINT_add(group, P, P, Q, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + x = BN_new(); + y = BN_new(); + z = BN_new(); + if (!x || !y || !z) ABORT; + + if (!BN_hex2bn(&x, "D")) ABORT; + if (!EC_POINT_set_compressed_coordinates_GFp(group, Q, x, 1, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, Q, ctx)) + { + if (!EC_POINT_get_affine_coordinates_GFp(group, Q, x, y, ctx)) ABORT; + fprintf(stderr, "Point is not on curve: x = 0x"); + BN_print_fp(stderr, x); + fprintf(stderr, ", y = 0x"); + BN_print_fp(stderr, y); + fprintf(stderr, "\n"); + ABORT; + } + + fprintf(stdout, "A cyclic subgroup:\n"); + k = 100; + do + { + if (k-- == 0) ABORT; + + if (EC_POINT_is_at_infinity(group, P)) + fprintf(stdout, " point at infinity\n"); + else + { + if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT; + + fprintf(stdout, " x = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, ", y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, "\n"); + } + + if (!EC_POINT_copy(R, P)) ABORT; + if (!EC_POINT_add(group, P, P, Q, ctx)) ABORT; + +#if 0 /* optional */ + { + EC_POINT *points[3]; + + points[0] = R; + points[1] = Q; + points[2] = P; + if (!EC_POINTs_make_affine(group, 2, points, ctx)) ABORT; + } +#endif + + } + while (!EC_POINT_is_at_infinity(group, P)); + + if (!EC_POINT_add(group, P, Q, R, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + len = EC_POINT_point2oct(group, Q, POINT_CONVERSION_COMPRESSED, 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, "Generator as octect 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 "); + 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 "); + 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; + fprintf(stdout, "\nA representation of the inverse of that generator in\nJacobian projective coordinates:\n X = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, ", Y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, ", Z = 0x"); + BN_print_fp(stdout, z); + fprintf(stdout, "\n"); + + if (!EC_POINT_invert(group, P, ctx)) ABORT; + if (0 != EC_POINT_cmp(group, P, R, ctx)) ABORT; + + + /* Curve secp160r1 (Certicom Research SEC 2 Version 1.0, section 2.4.2, 2000) + * -- not a NIST curve, but commonly used */ + + if (!BN_hex2bn(&p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF")) ABORT; + if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT; + if (!BN_hex2bn(&a, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC")) ABORT; + if (!BN_hex2bn(&b, "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45")) ABORT; + if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT; + + if (!BN_hex2bn(&x, "4A96B5688EF573284664698968C38BB913CBFC82")) ABORT; + if (!BN_hex2bn(&y, "23a628553168947d59dcc912042351377ac5fb32")) ABORT; + if (!EC_POINT_set_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; + if (!BN_hex2bn(&z, "0100000000000000000001F4C8F927AED3CA752257")) ABORT; + if (!EC_GROUP_set_generator(group, P, z, BN_value_one())) ABORT; + + if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT; + fprintf(stdout, "\nSEC2 curve secp160r1 -- Generator:\n x = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, "\n y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, "\n"); + /* G_y value taken from the standard: */ + if (!BN_hex2bn(&z, "23a628553168947d59dcc912042351377ac5fb32")) ABORT; + if (0 != BN_cmp(y, z)) ABORT; + + fprintf(stdout, "verify degree ..."); + 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"); + + if (!(P_160 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT; + if (!EC_GROUP_copy(P_160, group)) ABORT; + + + /* Curve P-192 (FIPS PUB 186-2, App. 6) */ + + if (!BN_hex2bn(&p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF")) ABORT; + if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT; + if (!BN_hex2bn(&a, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC")) ABORT; + if (!BN_hex2bn(&b, "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1")) ABORT; + if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT; + + if (!BN_hex2bn(&x, "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012")) ABORT; + if (!EC_POINT_set_compressed_coordinates_GFp(group, P, x, 1, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; + if (!BN_hex2bn(&z, "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831")) ABORT; + if (!EC_GROUP_set_generator(group, P, z, BN_value_one())) ABORT; + + if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT; + fprintf(stdout, "\nNIST curve P-192 -- Generator:\n x = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, "\n y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, "\n"); + /* G_y value taken from the standard: */ + if (!BN_hex2bn(&z, "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")) ABORT; + if (0 != BN_cmp(y, z)) ABORT; + + fprintf(stdout, "verify degree ..."); + 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"); + + if (!(P_192 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT; + if (!EC_GROUP_copy(P_192, group)) ABORT; + + + /* Curve P-224 (FIPS PUB 186-2, App. 6) */ + + if (!BN_hex2bn(&p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001")) ABORT; + if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT; + if (!BN_hex2bn(&a, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE")) ABORT; + if (!BN_hex2bn(&b, "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4")) ABORT; + if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT; + + if (!BN_hex2bn(&x, "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21")) ABORT; + if (!EC_POINT_set_compressed_coordinates_GFp(group, P, x, 0, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; + if (!BN_hex2bn(&z, "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D")) ABORT; + if (!EC_GROUP_set_generator(group, P, z, BN_value_one())) ABORT; + + if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT; + fprintf(stdout, "\nNIST curve P-224 -- Generator:\n x = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, "\n y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, "\n"); + /* G_y value taken from the standard: */ + if (!BN_hex2bn(&z, "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")) ABORT; + if (0 != BN_cmp(y, z)) ABORT; + + fprintf(stdout, "verify degree ..."); + 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"); + + if (!(P_224 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT; + if (!EC_GROUP_copy(P_224, group)) ABORT; + + + /* Curve P-256 (FIPS PUB 186-2, App. 6) */ + + if (!BN_hex2bn(&p, "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")) ABORT; + if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT; + if (!BN_hex2bn(&a, "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")) ABORT; + if (!BN_hex2bn(&b, "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")) ABORT; + if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT; + + if (!BN_hex2bn(&x, "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")) ABORT; + if (!EC_POINT_set_compressed_coordinates_GFp(group, P, x, 1, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; + if (!BN_hex2bn(&z, "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E" + "84F3B9CAC2FC632551")) ABORT; + if (!EC_GROUP_set_generator(group, P, z, BN_value_one())) ABORT; + + if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT; + fprintf(stdout, "\nNIST curve P-256 -- Generator:\n x = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, "\n y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, "\n"); + /* G_y value taken from the standard: */ + if (!BN_hex2bn(&z, "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")) ABORT; + if (0 != BN_cmp(y, z)) ABORT; + + fprintf(stdout, "verify degree ..."); + 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"); + + if (!(P_256 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT; + if (!EC_GROUP_copy(P_256, group)) ABORT; + + + /* Curve P-384 (FIPS PUB 186-2, App. 6) */ + + if (!BN_hex2bn(&p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF")) ABORT; + if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT; + if (!BN_hex2bn(&a, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC")) ABORT; + if (!BN_hex2bn(&b, "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141" + "120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF")) ABORT; + if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT; + + if (!BN_hex2bn(&x, "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B" + "9859F741E082542A385502F25DBF55296C3A545E3872760AB7")) ABORT; + if (!EC_POINT_set_compressed_coordinates_GFp(group, P, x, 1, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; + if (!BN_hex2bn(&z, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973")) ABORT; + if (!EC_GROUP_set_generator(group, P, z, BN_value_one())) ABORT; + + if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT; + fprintf(stdout, "\nNIST curve P-384 -- Generator:\n x = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, "\n y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, "\n"); + /* G_y value taken from the standard: */ + if (!BN_hex2bn(&z, "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A14" + "7CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")) ABORT; + if (0 != BN_cmp(y, z)) ABORT; + + 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"); + + if (!(P_384 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT; + if (!EC_GROUP_copy(P_384, group)) ABORT; + + + /* Curve P-521 (FIPS PUB 186-2, App. 6) */ + + if (!BN_hex2bn(&p, "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFF")) ABORT; + if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT; + if (!BN_hex2bn(&a, "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFC")) ABORT; + if (!BN_hex2bn(&b, "051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B" + "315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573" + "DF883D2C34F1EF451FD46B503F00")) ABORT; + if (!EC_GROUP_set_curve_GFp(group, p, a, b, ctx)) ABORT; + + if (!BN_hex2bn(&x, "C6858E06B70404E9CD9E3ECB662395B4429C648139053F" + "B521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B" + "3C1856A429BF97E7E31C2E5BD66")) ABORT; + if (!EC_POINT_set_compressed_coordinates_GFp(group, P, x, 0, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; + if (!BN_hex2bn(&z, "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5" + "C9B8899C47AEBB6FB71E91386409")) ABORT; + if (!EC_GROUP_set_generator(group, P, z, BN_value_one())) ABORT; + + if (!EC_POINT_get_affine_coordinates_GFp(group, P, x, y, ctx)) ABORT; + fprintf(stdout, "\nNIST curve P-521 -- Generator:\n x = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, "\n y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, "\n"); + /* G_y value taken from the standard: */ + if (!BN_hex2bn(&z, "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579" + "B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C" + "7086A272C24088BE94769FD16650")) ABORT; + if (0 != BN_cmp(y, z)) ABORT; + + 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"); + + if (!(P_521 = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT; + if (!EC_GROUP_copy(P_521, group)) ABORT; + + + /* more tests using the last curve */ + + if (!EC_POINT_copy(Q, P)) ABORT; + if (EC_POINT_is_at_infinity(group, Q)) ABORT; + if (!EC_POINT_dbl(group, P, P, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; + if (!EC_POINT_invert(group, Q, ctx)) ABORT; /* P = -2Q */ + + if (!EC_POINT_add(group, R, P, Q, ctx)) ABORT; + if (!EC_POINT_add(group, R, R, Q, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, R)) ABORT; /* R = P + 2Q */ + + { + const EC_POINT *points[4]; + const BIGNUM *scalars[4]; + BIGNUM scalar3; + + if (EC_POINT_is_at_infinity(group, Q)) ABORT; + points[0] = Q; + points[1] = Q; + points[2] = Q; + points[3] = Q; + + if (!BN_add(y, z, BN_value_one())) ABORT; + if (BN_is_odd(y)) ABORT; + if (!BN_rshift1(y, y)) ABORT; + scalars[0] = y; /* (group order + 1)/2, so y*Q + y*Q = Q */ + scalars[1] = y; + + fprintf(stdout, "combined multiplication ..."); + fflush(stdout); + + /* z is still the group order */ + if (!EC_POINTs_mul(group, P, NULL, 2, points, scalars, ctx)) ABORT; + if (!EC_POINTs_mul(group, R, z, 2, points, scalars, ctx)) ABORT; + if (0 != EC_POINT_cmp(group, P, R, ctx)) ABORT; + if (0 != EC_POINT_cmp(group, R, Q, ctx)) ABORT; + + fprintf(stdout, "."); + fflush(stdout); + + if (!BN_pseudo_rand(y, BN_num_bits(y), 0, 0)) ABORT; + if (!BN_add(z, z, y)) ABORT; + BN_set_negative(z, 1); + scalars[0] = y; + scalars[1] = z; /* z = -(order + y) */ + + if (!EC_POINTs_mul(group, P, NULL, 2, points, scalars, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + fprintf(stdout, "."); + fflush(stdout); + + if (!BN_pseudo_rand(x, BN_num_bits(y) - 1, 0, 0)) ABORT; + if (!BN_add(z, x, y)) ABORT; + BN_set_negative(z, 1); + scalars[0] = x; + scalars[1] = y; + scalars[2] = z; /* z = -(x+y) */ + + BN_init(&scalar3); + BN_zero(&scalar3); + scalars[3] = &scalar3; + + if (!EC_POINTs_mul(group, P, NULL, 4, points, scalars, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + fprintf(stdout, " ok\n\n"); + + BN_free(&scalar3); + } + + +#if 0 + timings(P_160, TIMING_BASE_PT, ctx); + timings(P_160, TIMING_RAND_PT, ctx); + timings(P_160, TIMING_SIMUL, ctx); + timings(P_192, TIMING_BASE_PT, ctx); + timings(P_192, TIMING_RAND_PT, ctx); + timings(P_192, TIMING_SIMUL, ctx); + timings(P_224, TIMING_BASE_PT, ctx); + timings(P_224, TIMING_RAND_PT, ctx); + timings(P_224, TIMING_SIMUL, ctx); + timings(P_256, TIMING_BASE_PT, ctx); + timings(P_256, TIMING_RAND_PT, ctx); + timings(P_256, TIMING_SIMUL, ctx); + timings(P_384, TIMING_BASE_PT, ctx); + timings(P_384, TIMING_RAND_PT, ctx); + timings(P_384, TIMING_SIMUL, ctx); + timings(P_521, TIMING_BASE_PT, ctx); + timings(P_521, TIMING_RAND_PT, ctx); + timings(P_521, TIMING_SIMUL, ctx); +#endif + + + if (ctx) + BN_CTX_free(ctx); + BN_free(p); BN_free(a); BN_free(b); + EC_GROUP_free(group); + EC_POINT_free(P); + EC_POINT_free(Q); + EC_POINT_free(R); + BN_free(x); BN_free(y); BN_free(z); + + if (P_160) EC_GROUP_free(P_160); + if (P_192) EC_GROUP_free(P_192); + if (P_224) EC_GROUP_free(P_224); + if (P_256) EC_GROUP_free(P_256); + if (P_384) EC_GROUP_free(P_384); + if (P_521) EC_GROUP_free(P_521); + + } + +/* Change test based on whether binary point compression is enabled or not. */ +#ifdef OPENSSL_EC_BIN_PT_COMP +#define CHAR2_CURVE_TEST_INTERNAL(_name, _p, _a, _b, _x, _y, _y_bit, _order, _cof, _degree, _variable) \ + if (!BN_hex2bn(&x, _x)) ABORT; \ + if (!EC_POINT_set_compressed_coordinates_GF2m(group, P, x, _y_bit, ctx)) ABORT; \ + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; \ + if (!BN_hex2bn(&z, _order)) ABORT; \ + if (!BN_hex2bn(&cof, _cof)) ABORT; \ + if (!EC_GROUP_set_generator(group, P, z, cof)) ABORT; \ + if (!EC_POINT_get_affine_coordinates_GF2m(group, P, x, y, ctx)) ABORT; \ + fprintf(stdout, "\n%s -- Generator:\n x = 0x", _name); \ + BN_print_fp(stdout, x); \ + fprintf(stdout, "\n y = 0x"); \ + BN_print_fp(stdout, y); \ + fprintf(stdout, "\n"); \ + /* G_y value taken from the standard: */ \ + if (!BN_hex2bn(&z, _y)) ABORT; \ + if (0 != BN_cmp(y, z)) ABORT; +#else +#define CHAR2_CURVE_TEST_INTERNAL(_name, _p, _a, _b, _x, _y, _y_bit, _order, _cof, _degree, _variable) \ + if (!BN_hex2bn(&x, _x)) ABORT; \ + if (!BN_hex2bn(&y, _y)) ABORT; \ + if (!EC_POINT_set_affine_coordinates_GF2m(group, P, x, y, ctx)) ABORT; \ + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; \ + if (!BN_hex2bn(&z, _order)) ABORT; \ + if (!BN_hex2bn(&cof, _cof)) ABORT; \ + if (!EC_GROUP_set_generator(group, P, z, cof)) ABORT; \ + fprintf(stdout, "\n%s -- Generator:\n x = 0x", _name); \ + BN_print_fp(stdout, x); \ + fprintf(stdout, "\n y = 0x"); \ + BN_print_fp(stdout, y); \ + fprintf(stdout, "\n"); +#endif + +#define CHAR2_CURVE_TEST(_name, _p, _a, _b, _x, _y, _y_bit, _order, _cof, _degree, _variable) \ + if (!BN_hex2bn(&p, _p)) ABORT; \ + if (!BN_hex2bn(&a, _a)) ABORT; \ + if (!BN_hex2bn(&b, _b)) ABORT; \ + if (!EC_GROUP_set_curve_GF2m(group, p, a, b, ctx)) ABORT; \ + CHAR2_CURVE_TEST_INTERNAL(_name, _p, _a, _b, _x, _y, _y_bit, _order, _cof, _degree, _variable) \ + 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"); \ + if (!(_variable = EC_GROUP_new(EC_GROUP_method_of(group)))) ABORT; \ + if (!EC_GROUP_copy(_variable, group)) ABORT; + +void char2_field_tests() + { + BN_CTX *ctx = NULL; + BIGNUM *p, *a, *b; + EC_GROUP *group; + EC_GROUP *C2_K163 = NULL, *C2_K233 = NULL, *C2_K283 = NULL, *C2_K409 = NULL, *C2_K571 = NULL; + EC_GROUP *C2_B163 = NULL, *C2_B233 = NULL, *C2_B283 = NULL, *C2_B409 = NULL, *C2_B571 = NULL; + EC_POINT *P, *Q, *R; + BIGNUM *x, *y, *z, *cof; + unsigned char buf[100]; + size_t i, len; + int k; + +#if 1 /* optional */ + ctx = BN_CTX_new(); + if (!ctx) ABORT; +#endif + + p = BN_new(); + a = BN_new(); + b = BN_new(); + if (!p || !a || !b) ABORT; + + if (!BN_hex2bn(&p, "13")) ABORT; + if (!BN_hex2bn(&a, "3")) ABORT; + if (!BN_hex2bn(&b, "1")) ABORT; + + group = EC_GROUP_new(EC_GF2m_simple_method()); /* applications should use EC_GROUP_new_curve_GF2m + * so that the library gets to choose the EC_METHOD */ + if (!group) ABORT; + if (!EC_GROUP_set_curve_GF2m(group, p, a, b, ctx)) ABORT; + + { + EC_GROUP *tmp; + tmp = EC_GROUP_new(EC_GROUP_method_of(group)); + if (!tmp) ABORT; + if (!EC_GROUP_copy(tmp, group)) ABORT; + EC_GROUP_free(group); + group = tmp; + } + + if (!EC_GROUP_get_curve_GF2m(group, p, a, b, ctx)) ABORT; + + fprintf(stdout, "Curve defined by Weierstrass equation\n y^2 + x*y = x^3 + a*x^2 + b (mod 0x"); + BN_print_fp(stdout, p); + fprintf(stdout, ")\n a = 0x"); + BN_print_fp(stdout, a); + fprintf(stdout, "\n b = 0x"); + BN_print_fp(stdout, b); + fprintf(stdout, "\n(0x... means binary polynomial)\n"); + + P = EC_POINT_new(group); + Q = EC_POINT_new(group); + R = EC_POINT_new(group); + if (!P || !Q || !R) ABORT; + + if (!EC_POINT_set_to_infinity(group, P)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + buf[0] = 0; + if (!EC_POINT_oct2point(group, Q, buf, 1, ctx)) ABORT; + + if (!EC_POINT_add(group, P, P, Q, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + x = BN_new(); + y = BN_new(); + z = BN_new(); + cof = BN_new(); + if (!x || !y || !z || !cof) ABORT; + + if (!BN_hex2bn(&x, "6")) ABORT; +/* Change test based on whether binary point compression is enabled or not. */ +#ifdef OPENSSL_EC_BIN_PT_COMP + if (!EC_POINT_set_compressed_coordinates_GF2m(group, Q, x, 1, ctx)) ABORT; +#else + if (!BN_hex2bn(&y, "8")) ABORT; + if (!EC_POINT_set_affine_coordinates_GF2m(group, Q, x, y, ctx)) ABORT; +#endif + if (!EC_POINT_is_on_curve(group, Q, ctx)) + { +/* Change test based on whether binary point compression is enabled or not. */ +#ifdef OPENSSL_EC_BIN_PT_COMP + if (!EC_POINT_get_affine_coordinates_GF2m(group, Q, x, y, ctx)) ABORT; +#endif + fprintf(stderr, "Point is not on curve: x = 0x"); + BN_print_fp(stderr, x); + fprintf(stderr, ", y = 0x"); + BN_print_fp(stderr, y); + fprintf(stderr, "\n"); + ABORT; + } + + fprintf(stdout, "A cyclic subgroup:\n"); + k = 100; + do + { + if (k-- == 0) ABORT; + + if (EC_POINT_is_at_infinity(group, P)) + fprintf(stdout, " point at infinity\n"); + else + { + if (!EC_POINT_get_affine_coordinates_GF2m(group, P, x, y, ctx)) ABORT; + + fprintf(stdout, " x = 0x"); + BN_print_fp(stdout, x); + fprintf(stdout, ", y = 0x"); + BN_print_fp(stdout, y); + fprintf(stdout, "\n"); + } + + if (!EC_POINT_copy(R, P)) ABORT; + if (!EC_POINT_add(group, P, P, Q, ctx)) ABORT; + } + while (!EC_POINT_is_at_infinity(group, P)); + + if (!EC_POINT_add(group, P, Q, R, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + +/* Change test based on whether binary point compression is enabled or not. */ +#ifdef OPENSSL_EC_BIN_PT_COMP + len = EC_POINT_point2oct(group, Q, POINT_CONVERSION_COMPRESSED, 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, "Generator as octet string, compressed form:\n "); + for (i = 0; i < len; i++) fprintf(stdout, "%02X", buf[i]); +#endif + + 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 octet string, uncompressed form:\n "); + for (i = 0; i < len; i++) fprintf(stdout, "%02X", buf[i]); + +/* Change test based on whether binary point compression is enabled or not. */ +#ifdef OPENSSL_EC_BIN_PT_COMP + 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 octet string, hybrid form:\n "); + for (i = 0; i < len; i++) fprintf(stdout, "%02X", buf[i]); +#endif + + fprintf(stdout, "\n"); + + if (!EC_POINT_invert(group, P, ctx)) ABORT; + if (0 != EC_POINT_cmp(group, P, R, ctx)) ABORT; + + + /* Curve K-163 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve K-163", + "0800000000000000000000000000000000000000C9", + "1", + "1", + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8", + "0289070FB05D38FF58321F2E800536D538CCDAA3D9", + 1, + "04000000000000000000020108A2E0CC0D99F8A5EF", + "2", + 163, + C2_K163 + ); + + /* Curve B-163 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve B-163", + "0800000000000000000000000000000000000000C9", + "1", + "020A601907B8C953CA1481EB10512F78744A3205FD", + "03F0EBA16286A2D57EA0991168D4994637E8343E36", + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1", + 1, + "040000000000000000000292FE77E70C12A4234C33", + "2", + 163, + C2_B163 + ); + + /* Curve K-233 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve K-233", + "020000000000000000000000000000000000000004000000000000000001", + "0", + "1", + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126", + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3", + 0, + "008000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", + "4", + 233, + C2_K233 + ); + + /* Curve B-233 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve B-233", + "020000000000000000000000000000000000000004000000000000000001", + "000000000000000000000000000000000000000000000000000000000001", + "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD", + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B", + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052", + 1, + "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", + "2", + 233, + C2_B233 + ); + + /* Curve K-283 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve K-283", + "0800000000000000000000000000000000000000000000000000000000000000000010A1", + "0", + "1", + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836", + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259", + 0, + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61", + "4", + 283, + C2_K283 + ); + + /* Curve B-283 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve B-283", + "0800000000000000000000000000000000000000000000000000000000000000000010A1", + "000000000000000000000000000000000000000000000000000000000000000000000001", + "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053", + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", + 1, + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", + "2", + 283, + C2_B283 + ); + + /* Curve K-409 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve K-409", + "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", + "0", + "1", + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746", + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B", + 1, + "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", + "4", + 409, + C2_K409 + ); + + /* Curve B-409 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve B-409", + "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F", + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7", + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706", + 1, + "010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173", + "2", + 409, + C2_B409 + ); + + /* Curve K-571 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve K-571", + "80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", + "0", + "1", + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972", + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3", + 0, + "020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001", + "4", + 571, + C2_K571 + ); + + /* Curve B-571 (FIPS PUB 186-2, App. 6) */ + CHAR2_CURVE_TEST + ( + "NIST curve B-571", + "80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A", + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19", + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B", + 1, + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47", + "2", + 571, + C2_B571 + ); + + /* more tests using the last curve */ + + if (!EC_POINT_copy(Q, P)) ABORT; + if (EC_POINT_is_at_infinity(group, Q)) ABORT; + if (!EC_POINT_dbl(group, P, P, ctx)) ABORT; + if (!EC_POINT_is_on_curve(group, P, ctx)) ABORT; + if (!EC_POINT_invert(group, Q, ctx)) ABORT; /* P = -2Q */ + + if (!EC_POINT_add(group, R, P, Q, ctx)) ABORT; + if (!EC_POINT_add(group, R, R, Q, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, R)) ABORT; /* R = P + 2Q */ + + { + const EC_POINT *points[3]; + const BIGNUM *scalars[3]; + + if (EC_POINT_is_at_infinity(group, Q)) ABORT; + points[0] = Q; + points[1] = Q; + points[2] = Q; + + if (!BN_add(y, z, BN_value_one())) ABORT; + if (BN_is_odd(y)) ABORT; + if (!BN_rshift1(y, y)) ABORT; + scalars[0] = y; /* (group order + 1)/2, so y*Q + y*Q = Q */ + scalars[1] = y; + + fprintf(stdout, "combined multiplication ..."); + fflush(stdout); + + /* z is still the group order */ + if (!EC_POINTs_mul(group, P, NULL, 2, points, scalars, ctx)) ABORT; + if (!EC_POINTs_mul(group, R, z, 2, points, scalars, ctx)) ABORT; + if (0 != EC_POINT_cmp(group, P, R, ctx)) ABORT; + if (0 != EC_POINT_cmp(group, R, Q, ctx)) ABORT; + + fprintf(stdout, "."); + fflush(stdout); + + if (!BN_pseudo_rand(y, BN_num_bits(y), 0, 0)) ABORT; + if (!BN_add(z, z, y)) ABORT; + BN_set_negative(z, 1); + scalars[0] = y; + scalars[1] = z; /* z = -(order + y) */ + + if (!EC_POINTs_mul(group, P, NULL, 2, points, scalars, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + fprintf(stdout, "."); + fflush(stdout); + + if (!BN_pseudo_rand(x, BN_num_bits(y) - 1, 0, 0)) ABORT; + if (!BN_add(z, x, y)) ABORT; + BN_set_negative(z, 1); + scalars[0] = x; + scalars[1] = y; + scalars[2] = z; /* z = -(x+y) */ + + if (!EC_POINTs_mul(group, P, NULL, 3, points, scalars, ctx)) ABORT; + if (!EC_POINT_is_at_infinity(group, P)) ABORT; + + fprintf(stdout, " ok\n\n"); + } + + +#if 0 + timings(C2_K163, TIMING_BASE_PT, ctx); + timings(C2_K163, TIMING_RAND_PT, ctx); + timings(C2_K163, TIMING_SIMUL, ctx); + timings(C2_B163, TIMING_BASE_PT, ctx); + timings(C2_B163, TIMING_RAND_PT, ctx); + timings(C2_B163, TIMING_SIMUL, ctx); + timings(C2_K233, TIMING_BASE_PT, ctx); + timings(C2_K233, TIMING_RAND_PT, ctx); + timings(C2_K233, TIMING_SIMUL, ctx); + timings(C2_B233, TIMING_BASE_PT, ctx); + timings(C2_B233, TIMING_RAND_PT, ctx); + timings(C2_B233, TIMING_SIMUL, ctx); + timings(C2_K283, TIMING_BASE_PT, ctx); + timings(C2_K283, TIMING_RAND_PT, ctx); + timings(C2_K283, TIMING_SIMUL, ctx); + timings(C2_B283, TIMING_BASE_PT, ctx); + timings(C2_B283, TIMING_RAND_PT, ctx); + timings(C2_B283, TIMING_SIMUL, ctx); + timings(C2_K409, TIMING_BASE_PT, ctx); + timings(C2_K409, TIMING_RAND_PT, ctx); + timings(C2_K409, TIMING_SIMUL, ctx); + timings(C2_B409, TIMING_BASE_PT, ctx); + timings(C2_B409, TIMING_RAND_PT, ctx); + timings(C2_B409, TIMING_SIMUL, ctx); + timings(C2_K571, TIMING_BASE_PT, ctx); + timings(C2_K571, TIMING_RAND_PT, ctx); + timings(C2_K571, TIMING_SIMUL, ctx); + timings(C2_B571, TIMING_BASE_PT, ctx); + timings(C2_B571, TIMING_RAND_PT, ctx); + timings(C2_B571, TIMING_SIMUL, ctx); +#endif + + + if (ctx) + BN_CTX_free(ctx); + BN_free(p); BN_free(a); BN_free(b); + EC_GROUP_free(group); + EC_POINT_free(P); + EC_POINT_free(Q); + EC_POINT_free(R); + BN_free(x); BN_free(y); BN_free(z); BN_free(cof); + + if (C2_K163) EC_GROUP_free(C2_K163); + if (C2_B163) EC_GROUP_free(C2_B163); + if (C2_K233) EC_GROUP_free(C2_K233); + if (C2_B233) EC_GROUP_free(C2_B233); + if (C2_K283) EC_GROUP_free(C2_K283); + if (C2_B283) EC_GROUP_free(C2_B283); + if (C2_K409) EC_GROUP_free(C2_K409); + if (C2_B409) EC_GROUP_free(C2_B409); + if (C2_K571) EC_GROUP_free(C2_K571); + if (C2_B571) EC_GROUP_free(C2_B571); + + } + +void internal_curve_test(void) + { + EC_builtin_curve *curves = NULL; + size_t crv_len = 0, n = 0; + int ok = 1; + + crv_len = EC_get_builtin_curves(NULL, 0); + + curves = OPENSSL_malloc(sizeof(EC_builtin_curve) * crv_len); + + if (curves == NULL) + return; + + if (!EC_get_builtin_curves(curves, crv_len)) + { + OPENSSL_free(curves); + return; + } + + fprintf(stdout, "testing internal curves: "); + + for (n = 0; n < crv_len; n++) + { + EC_GROUP *group = NULL; + int nid = curves[n].nid; + if ((group = EC_GROUP_new_by_curve_name(nid)) == NULL) + { + ok = 0; + fprintf(stdout, "\nEC_GROUP_new_curve_name() failed with" + " curve %s\n", OBJ_nid2sn(nid)); + /* try next curve */ + continue; + } + if (!EC_GROUP_check(group, NULL)) + { + ok = 0; + fprintf(stdout, "\nEC_GROUP_check() failed with" + " curve %s\n", OBJ_nid2sn(nid)); + EC_GROUP_free(group); + /* try the next curve */ + continue; + } + fprintf(stdout, "."); + fflush(stdout); + EC_GROUP_free(group); + } + if (ok) + fprintf(stdout, " ok\n"); + else + fprintf(stdout, " failed\n"); + OPENSSL_free(curves); + return; + } + +static const char rnd_seed[] = "string to make the random number generator think it has entropy"; + +int main(int argc, char *argv[]) + { + + /* enable memory leak checking unless explicitly disabled */ + if (!((getenv("OPENSSL_DEBUG_MEMORY") != NULL) && (0 == strcmp(getenv("OPENSSL_DEBUG_MEMORY"), "off")))) + { + CRYPTO_malloc_debug_init(); + CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL); + } + else + { + /* OPENSSL_DEBUG_MEMORY=off */ + CRYPTO_set_mem_debug_functions(0, 0, 0, 0, 0); + } + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + ERR_load_crypto_strings(); + + RAND_seed(rnd_seed, sizeof rnd_seed); /* or BN_generate_prime may fail */ + + prime_field_tests(); + puts(""); + char2_field_tests(); + /* test the internal curves */ + internal_curve_test(); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + ERR_remove_state(0); + CRYPTO_mem_leaks_fp(stderr); + + return 0; + } +#endif |