diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2008-09-06 12:17:55 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2008-09-06 12:17:55 +0000 |
commit | 96de7a4399a8c71cbb70d6252fa77acfd76b3f09 (patch) | |
tree | e6f6e4aad1952944ccd27e9eb47ea48b9a78dde7 /lib/libcrypto/ec | |
parent | ec7710fe8f10fb624fbc33c0bbad2474e0c26979 (diff) |
resolve conflicts
Diffstat (limited to 'lib/libcrypto/ec')
-rw-r--r-- | lib/libcrypto/ec/ec.h | 319 | ||||
-rw-r--r-- | lib/libcrypto/ec/ec_cvt.c | 76 | ||||
-rw-r--r-- | lib/libcrypto/ec/ec_err.c | 114 | ||||
-rw-r--r-- | lib/libcrypto/ec/ec_lcl.h | 241 | ||||
-rw-r--r-- | lib/libcrypto/ec/ec_lib.c | 678 | ||||
-rw-r--r-- | lib/libcrypto/ec/ec_mult.c | 673 | ||||
-rw-r--r-- | lib/libcrypto/ec/ecp_mont.c | 151 | ||||
-rw-r--r-- | lib/libcrypto/ec/ecp_nist.c | 180 | ||||
-rw-r--r-- | lib/libcrypto/ec/ecp_smpl.c | 335 | ||||
-rw-r--r-- | lib/libcrypto/ec/ectest.c | 813 |
10 files changed, 2950 insertions, 630 deletions
diff --git a/lib/libcrypto/ec/ec.h b/lib/libcrypto/ec/ec.h index 6d6a9b71273..8bc2a235b1a 100644 --- a/lib/libcrypto/ec/ec.h +++ b/lib/libcrypto/ec/ec.h @@ -1,6 +1,9 @@ /* crypto/ec/ec.h */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * 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 @@ -52,22 +55,48 @@ * 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/bn.h> +#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, @@ -84,7 +113,8 @@ typedef struct ec_group_st -- field definition -- curve coefficients -- optional generator with associated information (order, cofactor) - -- optional extra data (TODO: precomputed table for fast computation of multiples of generator) + -- optional extra data (precomputed table for fast computation of multiples of generator) + -- ASN1 stuff */ EC_GROUP; @@ -96,40 +126,84 @@ typedef struct ec_point_st EC_POINT; */ const EC_METHOD *EC_GFp_simple_method(void); const EC_METHOD *EC_GFp_mont_method(void); -#if 0 -const EC_METHOD *EC_GFp_recp_method(void); /* TODO */ -const EC_METHOD *EC_GFp_nist_method(void); /* TODO */ -#endif +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); -/* We don't have types for field specifications and field elements in general. - * Otherwise we could declare - * int EC_GROUP_set_curve(EC_GROUP *, .....); - */ 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_new_GFp() calls EC_GROUP_new() and EC_GROUP_set_GFp() +/* 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 *); -int EC_GROUP_set_generator(EC_GROUP *, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor); -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 *); +/* 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 *); @@ -145,11 +219,28 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *, const EC_POINT *, 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 *); @@ -164,9 +255,112 @@ 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 @@ -178,51 +372,124 @@ void ERR_load_EC_strings(void); /* 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_GFP_MONT_GROUP_SET_CURVE_GFP 135 +#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 @@ -230,12 +497,28 @@ void ERR_load_EC_strings(void); #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 } diff --git a/lib/libcrypto/ec/ec_cvt.c b/lib/libcrypto/ec/ec_cvt.c index 45b0ec33a0b..d45640bab90 100644 --- a/lib/libcrypto/ec/ec_cvt.c +++ b/lib/libcrypto/ec/ec_cvt.c @@ -1,6 +1,9 @@ /* crypto/ec/ec_cvt.c */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * 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 @@ -52,7 +55,21 @@ * 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" @@ -60,11 +77,8 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM { const EC_METHOD *meth; EC_GROUP *ret; - - /* Finally, this will use EC_GFp_nist_method if 'p' is a special - * prime with optimized modular arithmetics (for NIST curves) - */ - meth = EC_GFp_mont_method(); + + meth = EC_GFp_nist_method(); ret = EC_GROUP_new(meth); if (ret == NULL) @@ -72,6 +86,56 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM 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; } diff --git a/lib/libcrypto/ec/ec_err.c b/lib/libcrypto/ec/ec_err.c index 5b70f943822..d04c8955604 100644 --- a/lib/libcrypto/ec/ec_err.c +++ b/lib/libcrypto/ec/ec_err.c @@ -1,6 +1,6 @@ /* crypto/ec/ec_err.c */ /* ==================================================================== - * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * 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 @@ -71,54 +71,127 @@ 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_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_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_GFP), "ec_GFp_simple_point_get_affine_coordinates_GFp"}, -{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_GFP), "ec_GFp_simple_set_compressed_coordinates_GFp"}, +{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_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_GFP_MONT_GROUP_SET_CURVE_GFP), "GFP_MONT_GROUP_SET_CURVE_GFP"}, +{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"}, @@ -126,12 +199,28 @@ static ERR_STRING_DATA EC_str_reasons[]= {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} }; @@ -139,15 +228,12 @@ static ERR_STRING_DATA EC_str_reasons[]= void ERR_load_EC_strings(void) { - static int init=1; +#ifndef OPENSSL_NO_ERR - if (init) + if (ERR_func_error_string(EC_str_functs[0].error) == NULL) { - init=0; -#ifndef OPENSSL_NO_ERR ERR_load_strings(0,EC_str_functs); ERR_load_strings(0,EC_str_reasons); -#endif - } +#endif } diff --git a/lib/libcrypto/ec/ec_lcl.h b/lib/libcrypto/ec/ec_lcl.h index cc4cf277550..fdd7aa27556 100644 --- a/lib/libcrypto/ec/ec_lcl.h +++ b/lib/libcrypto/ec/ec_lcl.h @@ -1,6 +1,9 @@ /* crypto/ec/ec_lcl.h */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * 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 @@ -52,35 +55,56 @@ * 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 and EC_GROUP_get_curve_GFp: */ - int (*group_set_curve_GFp)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); - int (*group_get_curve_GFp)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *); + /* 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_set_generator, EC_GROUP_get0_generator, - * EC_GROUP_get_order, EC_GROUP_get_cofactor: - */ - int (*group_set_generator)(EC_GROUP *, const EC_POINT *generator, - const BIGNUM *order, const BIGNUM *cofactor); - EC_POINT *(*group_get0_generator)(const EC_GROUP *); - int (*group_get_order)(const EC_GROUP *, BIGNUM *order, BN_CTX *); - int (*group_get_cofactor)(const EC_GROUP *, BIGNUM *cofactor, 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 *); @@ -89,20 +113,22 @@ struct ec_method_st { 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, EC_POINT_get_affine_coordinates_GFp, - * EC_POINT_set_compressed_coordinates_GFp: + * 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_GFp)(const EC_GROUP *, EC_POINT *, + int (*point_set_affine_coordinates)(const EC_GROUP *, EC_POINT *, const BIGNUM *x, const BIGNUM *y, BN_CTX *); - int (*point_get_affine_coordinates_GFp)(const EC_GROUP *, const EC_POINT *, + int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *, BIGNUM *x, BIGNUM *y, BN_CTX *); - int (*point_set_compressed_coordinates_GFp)(const EC_GROUP *, EC_POINT *, + 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: */ @@ -125,34 +151,65 @@ struct ec_method_st { 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' and 'field_sqr' can be used by 'add' and 'dbl' so that + /* '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; - void *extra_data; - void *(*extra_data_dup_func)(void *); - void (*extra_data_free_func)(void *); - void (*extra_data_clear_free_func)(void *); + 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; - /* All members except 'meth' and 'extra_data...' are handled by - * the method functions, even if they appear generic */ + 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(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 @@ -160,29 +217,49 @@ struct ec_group_st { * 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 */ - EC_POINT *generator; /* optional */ - BIGNUM order, cofactor; + 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; -/* Basically a 'mixin' for extra data, but available for EC_GROUPs only + 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. - * (Currently, we have one slot only, but is is possible to extend this - * if necessary.) */ -int EC_GROUP_set_extra_data(EC_GROUP *, void *extra_data, void *(*extra_data_dup_func)(void *), - void (*extra_data_free_func)(void *), void (*extra_data_clear_free_func)(void *)); -void *EC_GROUP_get_extra_data(const EC_GROUP *, void *(*extra_data_dup_func)(void *), - void (*extra_data_free_func)(void *), void (*extra_data_clear_free_func)(void *)); -void EC_GROUP_free_extra_data(EC_GROUP *); -void EC_GROUP_clear_free_extra_data(EC_GROUP *); + */ +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 **); @@ -201,18 +278,23 @@ struct ec_point_st { +/* 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_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); -int ec_GFp_simple_group_get_curve_GFp(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *); -int ec_GFp_simple_group_set_generator(EC_GROUP *, const EC_POINT *generator, - const BIGNUM *order, const BIGNUM *cofactor); -EC_POINT *ec_GFp_simple_group_get0_generator(const EC_GROUP *); -int ec_GFp_simple_group_get_order(const EC_GROUP *, BIGNUM *order, BN_CTX *); -int ec_GFp_simple_group_get_cofactor(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *); +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 *); @@ -222,11 +304,11 @@ 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_GFp(const EC_GROUP *, EC_POINT *, +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_GFp(const EC_GROUP *, const EC_POINT *, +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_GFp(const EC_GROUP *, EC_POINT *, +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 *); @@ -246,7 +328,7 @@ 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_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +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 *); @@ -257,21 +339,52 @@ int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CT int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *); -/* method functions in ecp_recp.c */ -int ec_GFp_recp_group_init(EC_GROUP *); -int ec_GFp_recp_group_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); -void ec_GFp_recp_group_finish(EC_GROUP *); -void ec_GFp_recp_group_clear_finish(EC_GROUP *); -int ec_GFp_recp_group_copy(EC_GROUP *, const EC_GROUP *); -int ec_GFp_recp_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); -int ec_GFp_recp_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); - - /* method functions in ecp_nist.c */ -int ec_GFp_nist_group_init(EC_GROUP *); -int ec_GFp_nist_group_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); -void ec_GFp_nist_group_finish(EC_GROUP *); -void ec_GFp_nist_group_clear_finish(EC_GROUP *); -int ec_GFp_nist_group_copy(EC_GROUP *, const EC_GROUP *); +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/lib/libcrypto/ec/ec_lib.c b/lib/libcrypto/ec/ec_lib.c index deb522060f2..5af84376c60 100644 --- a/lib/libcrypto/ec/ec_lib.c +++ b/lib/libcrypto/ec/ec_lib.c @@ -1,6 +1,9 @@ /* crypto/ec/ec_lib.c */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * 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 @@ -52,6 +55,11 @@ * 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> @@ -90,10 +98,18 @@ EC_GROUP *EC_GROUP_new(const EC_METHOD *meth) ret->meth = meth; ret->extra_data = NULL; - ret->extra_data_dup_func = 0; - ret->extra_data_free_func = 0; - ret->extra_data_clear_free_func = 0; - + + 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); @@ -111,7 +127,15 @@ void EC_GROUP_free(EC_GROUP *group) if (group->meth->group_finish != 0) group->meth->group_finish(group); - EC_GROUP_free_extra_data(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); } @@ -123,10 +147,21 @@ void EC_GROUP_clear_free(EC_GROUP *group) if (group->meth->group_clear_finish != 0) group->meth->group_clear_finish(group); - else if (group->meth != NULL && group->meth->group_finish != 0) + else if (group->meth->group_finish != 0) group->meth->group_finish(group); - EC_GROUP_clear_free_extra_data(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); @@ -135,6 +170,8 @@ void EC_GROUP_clear_free(EC_GROUP *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); @@ -148,161 +185,507 @@ int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src) if (dest == src) return 1; - EC_GROUP_clear_free_extra_data(dest); - if (src->extra_data_dup_func) + EC_EX_DATA_free_all_data(&dest->extra_data); + + for (d = src->extra_data; d != NULL; d = d->next) { - if (src->extra_data != NULL) + 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) { - dest->extra_data = src->extra_data_dup_func(src->extra_data); - if (dest->extra_data == NULL) - return 0; + 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->extra_data_dup_func = src->extra_data_dup_func; - dest->extra_data_free_func = src->extra_data_free_func; - dest->extra_data_clear_free_func = src->extra_data_clear_free_func; + 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_GFp == 0) + 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_GFp(group, p, a, b, ctx); + 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_GFp == 0) + 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_GFp(group, p, a, b, ctx); + return group->meth->group_get_curve(group, p, a, b, ctx); } -int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor) +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_generator == 0) + if (group->meth->group_set_curve == 0) { - ECerr(EC_F_EC_GROUP_SET_GENERATOR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ECerr(EC_F_EC_GROUP_SET_CURVE_GF2M, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } - return group->meth->group_set_generator(group, generator, order, cofactor); + return group->meth->group_set_curve(group, p, a, b, ctx); } -EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) +int EC_GROUP_get_curve_GF2m(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) { - if (group->meth->group_get0_generator == 0) + if (group->meth->group_get_curve == 0) { - ECerr(EC_F_EC_GROUP_GET0_GENERATOR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ECerr(EC_F_EC_GROUP_GET_CURVE_GF2M, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } - return group->meth->group_get0_generator(group); + return group->meth->group_get_curve(group, p, a, b, ctx); } -int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) +int EC_GROUP_get_degree(const EC_GROUP *group) { - if (group->meth->group_get_order == 0) + if (group->meth->group_get_degree == 0) { - ECerr(EC_F_EC_GROUP_GET_ORDER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ECerr(EC_F_EC_GROUP_GET_DEGREE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } - return group->meth->group_get_order(group, order, ctx); + return group->meth->group_get_degree(group); } -int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx) +int EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) { - if (group->meth->group_get_cofactor == 0) + if (group->meth->group_check_discriminant == 0) { - ECerr(EC_F_EC_GROUP_GET_COFACTOR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ECerr(EC_F_EC_GROUP_CHECK_DISCRIMINANT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } - return group->meth->group_get_cofactor(group, cofactor, ctx); + return group->meth->group_check_discriminant(group, ctx); } -/* this has 'package' visibility */ -int EC_GROUP_set_extra_data(EC_GROUP *group, void *extra_data, void *(*extra_data_dup_func)(void *), - void (*extra_data_free_func)(void *), void (*extra_data_clear_free_func)(void *)) +int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx) { - if ((group->extra_data != NULL) - || (group->extra_data_dup_func != 0) - || (group->extra_data_free_func != 0) - || (group->extra_data_clear_free_func != 0)) - { - ECerr(EC_F_EC_GROUP_SET_EXTRA_DATA, EC_R_SLOT_FULL); + 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; } - group->extra_data = extra_data; - group->extra_data_dup_func = extra_data_dup_func; - group->extra_data_free_func = extra_data_free_func; - group->extra_data_clear_free_func = extra_data_clear_free_func; - 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 */ -void *EC_GROUP_get_extra_data(const EC_GROUP *group, void *(*extra_data_dup_func)(void *), - void (*extra_data_free_func)(void *), void (*extra_data_clear_free_func)(void *)) +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 *)) { - if ((group->extra_data_dup_func != extra_data_dup_func) - || (group->extra_data_free_func != extra_data_free_func) - || (group->extra_data_clear_free_func != extra_data_clear_free_func)) + EC_EXTRA_DATA *d; + + if (ex_data == NULL) + return 0; + + for (d = *ex_data; d != NULL; d = d->next) { -#if 0 /* this was an error in 0.9.7, but that does not make a lot of sense */ - ECerr(..._F_EC_GROUP_GET_EXTRA_DATA, ..._R_NO_SUCH_EXTRA_DATA); -#endif - return NULL; + 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; + } } - return group->extra_data; + 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_GROUP_free_extra_data(EC_GROUP *group) +void EC_EX_DATA_free_data(EC_EXTRA_DATA **ex_data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) { - if (group->extra_data_free_func) - group->extra_data_free_func(group->extra_data); - group->extra_data = NULL; - group->extra_data_dup_func = 0; - group->extra_data_free_func = 0; - group->extra_data_clear_free_func = 0; + 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_GROUP_clear_free_extra_data(EC_GROUP *group) +void EC_EX_DATA_free_all_data(EC_EXTRA_DATA **ex_data) { - if (group->extra_data_clear_free_func) - group->extra_data_clear_free_func(group->extra_data); - else if (group->extra_data_free_func) - group->extra_data_free_func(group->extra_data); - group->extra_data = NULL; - group->extra_data_dup_func = 0; - group->extra_data_free_func = 0; - group->extra_data_clear_free_func = 0; + 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 */ @@ -382,6 +765,25 @@ int EC_POINT_copy(EC_POINT *dest, const EC_POINT *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; @@ -441,7 +843,7 @@ int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group, const EC_POI 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_GFp == 0) + 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; @@ -451,14 +853,31 @@ int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS); return 0; } - return group->meth->point_set_affine_coordinates_GFp(group, point, x, y, ctx); + 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_GFp == 0) + 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; @@ -468,14 +887,31 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *p ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS); return 0; } - return group->meth->point_get_affine_coordinates_GFp(group, point, x, y, ctx); + 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_GFp == 0) + 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; @@ -485,7 +921,24 @@ int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *poi ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS); return 0; } - return group->meth->point_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx); + 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); } @@ -559,12 +1012,12 @@ int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) { if (group->meth->dbl == 0) { - ECerr(EC_F_EC_POINT_DBL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + 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_DBL, EC_R_INCOMPATIBLE_OBJECTS); + ECerr(EC_F_EC_POINT_INVERT, EC_R_INCOMPATIBLE_OBJECTS); return 0; } return group->meth->invert(group, a, ctx); @@ -654,3 +1107,58 @@ int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], } 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/lib/libcrypto/ec/ec_mult.c b/lib/libcrypto/ec/ec_mult.c index 16822a73cf5..2ba173ef364 100644 --- a/lib/libcrypto/ec/ec_mult.c +++ b/lib/libcrypto/ec/ec_mult.c @@ -1,6 +1,9 @@ /* crypto/ec/ec_mult.c */ +/* + * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. + */ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * 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 @@ -52,41 +55,161 @@ * 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" -/* TODO: optional precomputation of multiples of the generator */ +/* + * 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>). + */ -/* - * wNAF-based interleaving multi-exponentation method - * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#multiexp>) - */ + +/* 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 width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. + +/* 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. + * 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, BN_CTX *ctx) +static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { - BIGNUM *c; + int window_val; int ok = 0; signed char *r = NULL; int sign = 1; int bit, next_bit, mask; size_t len = 0, j; - BN_CTX_start(ctx); - c = BN_CTX_get(ctx); - if (c == NULL) goto err; - + 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); @@ -96,60 +219,90 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len, B next_bit = bit << 1; /* at most 256 */ mask = next_bit - 1; /* at most 255 */ - if (!BN_copy(c, scalar)) goto err; - if (c->neg) + if (BN_is_negative(scalar)) { sign = -1; - c->neg = 0; } - len = BN_num_bits(c) + 1; /* wNAF may be one digit longer than binary representation */ - r = OPENSSL_malloc(len); - if (r == NULL) goto err; + len = BN_num_bits(scalar); + r = OPENSSL_malloc(len + 1); /* modified wNAF may be one digit longer than binary representation + * (*ret_len will be set to the actual length, i.e. at most + * 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 (!BN_is_zero(c)) + while ((window_val != 0) || (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */ { - int u = 0; + int digit = 0; - if (BN_is_odd(c)) + /* 0 <= window_val <= 2^(w+1) */ + + if (window_val & 1) { - if (c->d == NULL || c->top == 0) + /* 0 < window_val < 2^(w+1) */ + + if (window_val & bit) { - ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); - goto err; + 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 } - u = c->d[0] & mask; - if (u & bit) + else { - u -= next_bit; - /* u < 0 */ - if (!BN_add_word(c, -u)) goto err; + digit = window_val; /* 0 < digit < 2^w */ } - else + + if (digit <= -bit || digit >= bit || !(digit & 1)) { - /* u > 0 */ - if (!BN_sub_word(c, u)) goto err; + ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); + goto err; } - if (u <= -bit || u >= bit || !(u & 1) || c->neg) + 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 * u; - - if (BN_is_odd(c)) + 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 (!BN_rshift1(c, c)) goto err; } - if (j > len) + if (j > len + 1) { ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); goto err; @@ -158,7 +311,6 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len, B ok = 1; err: - BN_CTX_end(ctx); if (!ok) { OPENSSL_free(r); @@ -181,7 +333,7 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len, B (b) >= 300 ? 4 : \ (b) >= 70 ? 3 : \ (b) >= 20 ? 2 : \ - 1)) + 1)) /* Compute * \sum scalars[i]*points[i], @@ -189,13 +341,15 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len, B * scalar*generator * in the addition if scalar != NULL */ -int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, +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; - EC_POINT *generator = 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; @@ -207,12 +361,15 @@ int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, size_t num_val; EC_POINT **val = NULL; /* precomputation */ EC_POINT **v; - EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */ + 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_POINTS_MUL, EC_R_INCOMPATIBLE_OBJECTS); + ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -221,59 +378,226 @@ int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, return EC_POINT_set_to_infinity(group, r); } - if (scalar != NULL) + for (i = 0; i < num; i++) { - generator = EC_GROUP_get0_generator(group); - if (generator == NULL) + if (group->meth != points[i]->meth) { - ECerr(EC_F_EC_POINTS_MUL, EC_R_UNDEFINED_GENERATOR); + ECerr(EC_F_EC_WNAF_MUL, EC_R_INCOMPATIBLE_OBJECTS); return 0; } } - - for (i = 0; i < num; i++) + + if (ctx == NULL) { - if (group->meth != points[i]->meth) + 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_POINTS_MUL, EC_R_INCOMPATIBLE_OBJECTS); - return 0; + 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; - totalnum = num + (scalar != NULL); + /* 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; - wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]); + /* 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]); - if (wNAF != NULL) + 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) { - wNAF[0] = NULL; /* preliminary pivot */ + ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE); + goto err; } - if (wsize == NULL || wNAF_len == NULL || wNAF == NULL) goto err; - /* num_val := total number of points to precompute */ + wNAF[0] = NULL; /* preliminary pivot */ + + /* num_val will be the total number of temporarily precomputed points */ num_val = 0; - for (i = 0; i < totalnum; i++) + + 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 precomputed points go into a single array 'val', - * 'val_sub[i]' is a pointer to the subarray for the i-th point */ + /* 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) goto err; + if (val == NULL) + { + ECerr(EC_F_EC_WNAF_MUL, ERR_R_MALLOC_FAILURE); + goto err; + } val[num_val] = NULL; /* pivot element */ - val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]); - if (val_sub == NULL) goto err; - /* allocate points for precomputation */ v = val; - for (i = 0; i < totalnum; i++) + for (i = 0; i < num + num_scalar; i++) { val_sub[i] = v; for (j = 0; j < (1u << (wsize[i] - 1)); j++) @@ -285,19 +609,12 @@ int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, } if (!(v == val + num_val)) { - ECerr(EC_F_EC_POINTS_MUL, ERR_R_INTERNAL_ERROR); + ECerr(EC_F_EC_WNAF_MUL, ERR_R_INTERNAL_ERROR); goto err; } - if (ctx == NULL) - { - ctx = new_ctx = BN_CTX_new(); - if (ctx == NULL) - goto err; - } - - tmp = EC_POINT_new(group); - if (tmp == NULL) goto err; + if (!(tmp = EC_POINT_new(group))) + goto err; /* prepare precomputed values: * val_sub[i][0] := points[i] @@ -305,7 +622,7 @@ int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, * val_sub[i][2] := 5 * points[i] * ... */ - for (i = 0; i < totalnum; i++) + for (i = 0; i < num + num_scalar; i++) { if (i < num) { @@ -324,16 +641,11 @@ int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) goto err; } } - - 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], ctx); - if (wNAF[i] == NULL) goto err; - if (wNAF_len[i] > max_len) - max_len = wNAF_len[i]; } #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; + if (!EC_POINTs_make_affine(group, num_val, val, ctx)) + goto err; #endif r_is_at_infinity = 1; @@ -429,57 +741,198 @@ int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, } -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) - { - 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) +/* 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_GROUP_PRECOMPUTE_MULT, EC_R_UNDEFINED_GENERATOR); - return 0; + 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) - return 0; + goto err; } BN_CTX_start(ctx); order = BN_CTX_get(ctx); if (order == NULL) goto err; - if (!EC_GROUP_get_order(group, order, ctx)) return 0; + if (!EC_GROUP_get_order(group, order, ctx)) goto err; if (BN_is_zero(order)) { - ECerr(EC_F_EC_GROUP_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER); + ECerr(EC_F_EC_WNAF_PRECOMPUTE_MULT, EC_R_UNKNOWN_ORDER); goto err; } - /* TODO */ + 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 */ - ret = 1; + 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: - BN_CTX_end(ctx); + 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/lib/libcrypto/ec/ecp_mont.c b/lib/libcrypto/ec/ecp_mont.c index 7b30d4c38a7..9fc4a466a59 100644 --- a/lib/libcrypto/ec/ecp_mont.c +++ b/lib/libcrypto/ec/ecp_mont.c @@ -1,4 +1,7 @@ /* crypto/ec/ecp_mont.c */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ /* ==================================================================== * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * @@ -52,6 +55,11 @@ * 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> @@ -61,16 +69,15 @@ 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_GFp, - ec_GFp_simple_group_get_curve_GFp, - ec_GFp_simple_group_set_generator, - ec_GFp_simple_group_get0_generator, - ec_GFp_simple_group_get_order, - ec_GFp_simple_group_get_cofactor, + 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, @@ -78,9 +85,9 @@ const EC_METHOD *EC_GFp_mont_method(void) 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_GFp, - ec_GFp_simple_point_get_affine_coordinates_GFp, - ec_GFp_simple_set_compressed_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, @@ -91,8 +98,12 @@ const EC_METHOD *EC_GFp_mont_method(void) 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 }; @@ -112,66 +123,6 @@ int ec_GFp_mont_group_init(EC_GROUP *group) } -int ec_GFp_mont_group_set_curve_GFp(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_GFP_MONT_GROUP_SET_CURVE_GFP, 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_GFp(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; - } - - void ec_GFp_mont_group_finish(EC_GROUP *group) { if (group->field_data1 != NULL) @@ -243,6 +194,66 @@ int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) } +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) @@ -295,7 +306,7 @@ 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_DECODE, EC_R_NOT_INITIALIZED); + ECerr(EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE, EC_R_NOT_INITIALIZED); return 0; } diff --git a/lib/libcrypto/ec/ecp_nist.c b/lib/libcrypto/ec/ecp_nist.c index ed077486754..71893d5eaba 100644 --- a/lib/libcrypto/ec/ecp_nist.c +++ b/lib/libcrypto/ec/ecp_nist.c @@ -1,6 +1,9 @@ /* crypto/ec/ecp_nist.c */ +/* + * Written by Nils Larsch for the OpenSSL project. + */ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * 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 @@ -52,23 +55,30 @@ * 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" -#if 0 const EC_METHOD *EC_GFp_nist_method(void) { static const EC_METHOD ret = { - ec_GFp_nist_group_init, - ec_GFp_nist_group_finish, - ec_GFp_nist_group_clear_finish, + 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_GFp, - ec_GFp_simple_group_get_curve_GFp, - ec_GFp_simple_group_set_generator, - ec_GFp_simple_group_get0_generator, - ec_GFp_simple_group_get_order, - ec_GFp_simple_group_get_cofactor, + 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, @@ -76,9 +86,9 @@ const EC_METHOD *EC_GFp_nist_method(void) 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_GFp, - ec_GFp_simple_point_get_affine_coordinates_GFp, - ec_GFp_simple_set_compressed_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, @@ -89,46 +99,138 @@ const EC_METHOD *EC_GFp_nist_method(void) 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; } -#endif +#if BN_BITS2 == 64 +#define NO_32_BIT_TYPE +#endif -int ec_GFp_nist_group_init(EC_GROUP *group) +int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src) { - int ok; + dest->field_mod_func = src->field_mod_func; - ok = ec_GFp_simple_group_init(group); - group->field_data1 = NULL; - return ok; + return ec_GFp_simple_group_copy(dest, src); } - -int ec_GFp_nist_group_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); -/* TODO */ - - -void ec_GFp_nist_group_finish(EC_GROUP *group); -/* TODO */ - - -void ec_GFp_nist_group_clear_finish(EC_GROUP *group); -/* TODO */ - - -int ec_GFp_nist_group_copy(EC_GROUP *dest, const EC_GROUP *src); -/* TODO */ +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); -/* TODO */ +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); -/* TODO */ +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/lib/libcrypto/ec/ecp_smpl.c b/lib/libcrypto/ec/ecp_smpl.c index e9a51fb87a1..4d26f8bdf69 100644 --- a/lib/libcrypto/ec/ecp_smpl.c +++ b/lib/libcrypto/ec/ecp_smpl.c @@ -1,8 +1,10 @@ /* crypto/ec/ecp_smpl.c */ /* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de> - * for the OpenSSL project. */ + * for the OpenSSL project. + * Includes code written by Bodo Moeller for the OpenSSL project. +*/ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * 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 @@ -54,25 +56,29 @@ * 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_GFp, - ec_GFp_simple_group_get_curve_GFp, - ec_GFp_simple_group_set_generator, - ec_GFp_simple_group_get0_generator, - ec_GFp_simple_group_get_order, - ec_GFp_simple_group_get_cofactor, + 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, @@ -80,9 +86,9 @@ const EC_METHOD *EC_GFp_simple_method(void) 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_GFp, - ec_GFp_simple_point_get_affine_coordinates_GFp, - ec_GFp_simple_set_compressed_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, @@ -93,8 +99,12 @@ const EC_METHOD *EC_GFp_simple_method(void) 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 */ }; @@ -103,15 +113,26 @@ const EC_METHOD *EC_GFp_simple_method(void) } +/* 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; - group->generator = NULL; - BN_init(&group->order); - BN_init(&group->cofactor); return 1; } @@ -121,10 +142,6 @@ void ec_GFp_simple_group_finish(EC_GROUP *group) BN_free(&group->field); BN_free(&group->a); BN_free(&group->b); - if (group->generator != NULL) - EC_POINT_free(group->generator); - BN_free(&group->order); - BN_free(&group->cofactor); } @@ -133,13 +150,6 @@ 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); - if (group->generator != NULL) - { - EC_POINT_clear_free(group->generator); - group->generator = NULL; - } - BN_clear_free(&group->order); - BN_clear_free(&group->cofactor); } @@ -151,33 +161,11 @@ int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) dest->a_is_minus3 = src->a_is_minus3; - 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; - return 1; } -int ec_GFp_simple_group_set_curve_GFp(EC_GROUP *group, +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; @@ -187,7 +175,7 @@ int ec_GFp_simple_group_set_curve_GFp(EC_GROUP *group, /* 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_GFP, EC_R_INVALID_FIELD); + ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, EC_R_INVALID_FIELD); return 0; } @@ -204,7 +192,7 @@ int ec_GFp_simple_group_set_curve_GFp(EC_GROUP *group, /* group->field */ if (!BN_copy(&group->field, p)) goto err; - group->field.neg = 0; + BN_set_negative(&group->field, 0); /* group->a */ if (!BN_nnmod(tmp_a, a, p, ctx)) goto err; @@ -232,7 +220,7 @@ int ec_GFp_simple_group_set_curve_GFp(EC_GROUP *group, } -int ec_GFp_simple_group_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) +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; @@ -283,58 +271,76 @@ int ec_GFp_simple_group_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM * } +int ec_GFp_simple_group_get_degree(const EC_GROUP *group) + { + return BN_num_bits(&group->field); + } + -int ec_GFp_simple_group_set_generator(EC_GROUP *group, const EC_POINT *generator, - const BIGNUM *order, const BIGNUM *cofactor) +int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) { - if (generator == NULL) + int ret = 0; + BIGNUM *a,*b,*order,*tmp_1,*tmp_2; + const BIGNUM *p = &group->field; + BN_CTX *new_ctx = NULL; + + if (ctx == NULL) { - ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR, ERR_R_PASSED_NULL_PARAMETER); - return 0 ; + 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->generator == NULL) + if (group->meth->field_decode) { - group->generator = EC_POINT_new(group); - if (group->generator == NULL) return 0; + if (!group->meth->field_decode(group, a, &group->a, ctx)) goto err; + if (!group->meth->field_decode(group, b, &group->b, ctx)) goto err; } - if (!EC_POINT_copy(group->generator, generator)) return 0; - - if (order != NULL) - { if (!BN_copy(&group->order, order)) return 0; } - else - { if (!BN_zero(&group->order)) return 0; } - - if (cofactor != NULL) - { if (!BN_copy(&group->cofactor, cofactor)) return 0; } else - { if (!BN_zero(&group->cofactor)) return 0; } - - return 1; - } - - -EC_POINT *ec_GFp_simple_group_get0_generator(const EC_GROUP *group) - { - return group->generator; - } - - -int ec_GFp_simple_group_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) - { - if (!BN_copy(order, &group->order)) - return 0; - - return !BN_is_zero(&group->order); - } + { + 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 */ -int ec_GFp_simple_group_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx) - { - if (!BN_copy(cofactor, &group->cofactor)) - return 0; + if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx)) goto err; + if (BN_is_zero(a)) goto err; + } + ret = 1; - return !BN_is_zero(&group->cofactor); +err: + if (ctx != NULL) + BN_CTX_end(ctx); + if (new_ctx != NULL) + BN_CTX_free(new_ctx); + return ret; } @@ -380,7 +386,8 @@ int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point) { point->Z_is_one = 0; - return (BN_zero(&point->Z)); + BN_zero(&point->Z); + return 1; } @@ -497,13 +504,13 @@ int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, const E } -int ec_GFp_simple_point_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, +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_GFP, ERR_R_PASSED_NULL_PARAMETER); + ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES, ERR_R_PASSED_NULL_PARAMETER); return 0; } @@ -511,17 +518,17 @@ int ec_GFp_simple_point_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POI } -int ec_GFp_simple_point_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point, +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 *X, *Y, *Z, *Z_1, *Z_2, *Z_3; - const BIGNUM *X_, *Y_, *Z_; + 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_GFP, EC_R_POINT_AT_INFINITY); + ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, EC_R_POINT_AT_INFINITY); return 0; } @@ -533,8 +540,6 @@ int ec_GFp_simple_point_get_affine_coordinates_GFp(const EC_GROUP *group, const } BN_CTX_start(ctx); - X = BN_CTX_get(ctx); - Y = BN_CTX_get(ctx); Z = BN_CTX_get(ctx); Z_1 = BN_CTX_get(ctx); Z_2 = BN_CTX_get(ctx); @@ -545,34 +550,44 @@ int ec_GFp_simple_point_get_affine_coordinates_GFp(const EC_GROUP *group, const if (group->meth->field_decode) { - if (!group->meth->field_decode(group, X, &point->X, ctx)) goto err; - if (!group->meth->field_decode(group, Y, &point->Y, ctx)) goto err; if (!group->meth->field_decode(group, Z, &point->Z, ctx)) goto err; - X_ = X; Y_ = Y; Z_ = Z; + Z_ = Z; } else { - X_ = &point->X; - Y_ = &point->Y; Z_ = &point->Z; } if (BN_is_one(Z_)) { - if (x != NULL) + if (group->meth->field_decode) { - if (!BN_copy(x, X_)) goto err; + 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 (y != NULL) + else { - if (!BN_copy(y, Y_)) goto err; + 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_GFP, ERR_R_BN_LIB); + ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, ERR_R_BN_LIB); goto err; } @@ -588,15 +603,8 @@ int ec_GFp_simple_point_get_affine_coordinates_GFp(const EC_GROUP *group, const if (x != NULL) { - if (group->meth->field_encode == 0) - { - /* field_mul works on standard representation */ - if (!group->meth->field_mul(group, x, X_, Z_2, ctx)) goto err; - } - else - { - if (!BN_mod_mul(x, X_, Z_2, &group->field, ctx)) goto err; - } + /* 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) @@ -605,14 +613,14 @@ int ec_GFp_simple_point_get_affine_coordinates_GFp(const EC_GROUP *group, const { /* field_mul works on standard representation */ if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) goto err; - if (!group->meth->field_mul(group, y, Y_, Z_3, ctx)) goto err; - } else { if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) goto err; - if (!BN_mod_mul(y, Y_, Z_3, &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; } } @@ -626,13 +634,16 @@ int ec_GFp_simple_point_get_affine_coordinates_GFp(const EC_GROUP *group, const } -int ec_GFp_simple_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, +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(); @@ -704,19 +715,17 @@ int ec_GFp_simple_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) { - unsigned long err = ERR_peek_error(); + unsigned long err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) { - (void)ERR_get_error(); - ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP, EC_R_INVALID_COMPRESSED_POINT); + 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_GFP, ERR_R_BN_LIB); + ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB); goto err; } - /* If tmp1 is not a square (i.e. there is no point on the curve with - * our x), then y now is a nonsense value too */ if (y_bit != BN_is_odd(y)) { @@ -728,16 +737,17 @@ int ec_GFp_simple_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT if (kron == -2) goto err; if (kron == 1) - ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP, EC_R_INVALID_COMPRESSION_BIT); + ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSION_BIT); else - ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP, EC_R_INVALID_COMPRESSED_POINT); + /* 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_GFP, ERR_R_INTERNAL_ERROR); + ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_INTERNAL_ERROR); goto err; } @@ -1088,7 +1098,7 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, con else { /* a is the inverse of b */ - if (!BN_zero(&r->Z)) goto end; + BN_zero(&r->Z); r->Z_is_one = 0; ret = 1; goto end; @@ -1164,7 +1174,7 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_ if (EC_POINT_is_at_infinity(group, a)) { - if (!BN_zero(&r->Z)) return 0; + BN_zero(&r->Z); r->Z_is_one = 0; return 1; } @@ -1292,7 +1302,7 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_C int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; - BIGNUM *rh, *tmp1, *tmp2, *Z4, *Z6; + BIGNUM *rh, *tmp, *Z4, *Z6; int ret = -1; if (EC_POINT_is_at_infinity(group, point)) @@ -1311,8 +1321,7 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_C BN_CTX_start(ctx); rh = BN_CTX_get(ctx); - tmp1 = BN_CTX_get(ctx); - tmp2 = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); Z4 = BN_CTX_get(ctx); Z6 = BN_CTX_get(ctx); if (Z6 == NULL) goto err; @@ -1326,59 +1335,49 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_C * To test this, we add up the right-hand side in 'rh'. */ - /* rh := X^3 */ + /* rh := X^2 */ if (!field_sqr(group, rh, &point->X, ctx)) goto err; - if (!field_mul(group, rh, rh, &point->X, ctx)) goto err; if (!point->Z_is_one) { - if (!field_sqr(group, tmp1, &point->Z, ctx)) goto err; - if (!field_sqr(group, Z4, tmp1, ctx)) goto err; - if (!field_mul(group, Z6, Z4, tmp1, ctx)) goto err; + 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*X*Z^4 */ - if (!field_mul(group, tmp1, &point->X, Z4, ctx)) goto err; + /* rh := (rh + a*Z^4)*X */ if (group->a_is_minus3) { - if (!BN_mod_lshift1_quick(tmp2, tmp1, p)) goto err; - if (!BN_mod_add_quick(tmp2, tmp2, tmp1, p)) goto err; - if (!BN_mod_sub_quick(rh, rh, tmp2, p)) goto err; + 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, tmp2, tmp1, &group->a, ctx)) goto err; - if (!BN_mod_add_quick(rh, rh, tmp2, p)) goto err; + 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, tmp1, &group->b, Z6, ctx)) goto err; - if (!BN_mod_add_quick(rh, rh, tmp1, p)) goto err; + 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 (group->a_is_minus3) - { - if (!BN_mod_lshift1_quick(tmp2, &point->X, p)) goto err; - if (!BN_mod_add_quick(tmp2, tmp2, &point->X, p)) goto err; - if (!BN_mod_sub_quick(rh, rh, tmp2, p)) goto err; - } - else - { - if (!field_mul(group, tmp2, &point->X, &group->a, ctx)) goto err; - if (!BN_mod_add_quick(rh, rh, tmp2, p)) goto err; - } - + /* 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, tmp1, &point->Y, ctx)) goto err; + if (!field_sqr(group, tmp, &point->Y, ctx)) goto err; - ret = (0 == BN_cmp(tmp1, rh)); + ret = (0 == BN_ucmp(tmp, rh)); err: BN_CTX_end(ctx); diff --git a/lib/libcrypto/ec/ectest.c b/lib/libcrypto/ec/ectest.c index fcf969f3cf0..6148d553f9d 100644 --- a/lib/libcrypto/ec/ectest.c +++ b/lib/libcrypto/ec/ectest.c @@ -1,4 +1,7 @@ /* crypto/ec/ectest.c */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ /* ==================================================================== * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * @@ -52,6 +55,19 @@ * 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> @@ -74,6 +90,15 @@ int main(int argc, char * argv[]) { puts("Elliptic curves are disabled."); retur #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); \ @@ -82,47 +107,59 @@ int main(int argc, char * argv[]) { puts("Elliptic curves are disabled."); retur EXIT(1); \ } while (0) +void prime_field_tests(void); +void char2_field_tests(void); +void internal_curve_test(void); + +#define TIMING_BASE_PT 0 +#define TIMING_RAND_PT 1 +#define TIMING_SIMUL 2 + #if 0 -static void timings(EC_GROUP *group, int multi, BN_CTX *ctx) +static void timings(EC_GROUP *group, int type, BN_CTX *ctx) { clock_t clck; int i, j; - BIGNUM *s, *s0; + BIGNUM *s; + BIGNUM *r[10], *r0[10]; EC_POINT *P; s = BN_new(); - s0 = BN_new(); - if (s == NULL || s0 == NULL) ABORT; + if (s == NULL) ABORT; - if (!EC_GROUP_get_curve_GFp(group, s, NULL, NULL, ctx)) ABORT; - fprintf(stdout, "Timings for %d bit prime, ", (int)BN_num_bits(s)); + 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)); + 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)); - clck = clock(); for (i = 0; i < 10; i++) { - if (!BN_pseudo_rand(s, BN_num_bits(s), 0, 0)) ABORT; - if (multi) + 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 (!BN_pseudo_rand(s0, BN_num_bits(s), 0, 0)) ABORT; + 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, s, multi ? P : NULL, multi ? s0 : NULL, ctx)) ABORT; + 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; } - fprintf(stdout, "."); - fflush(stdout); } - fprintf(stdout, "\n"); - 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 @@ -136,43 +173,40 @@ static void timings(EC_GROUP *group, int multi, BN_CTX *ctx) # define CLOCKS_PER_SEC 1 #endif - fprintf(stdout, "%i %s in %.2f " UNIT "\n", i*j, - multi ? "s*P+t*Q operations" : "point multiplications", - (double)clck/CLOCKS_PER_SEC); + 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); - BN_free(s0); + for (i = 0; i < 10; i++) + { + BN_free(r[i]); + if (type != TIMING_BASE_PT) BN_free(r0[i]); + } } #endif -int main(int argc, char *argv[]) +void prime_field_tests() { BN_CTX *ctx = NULL; BIGNUM *p, *a, *b; EC_GROUP *group; - EC_GROUP *P_192 = NULL, *P_224 = NULL, *P_256 = NULL, *P_384 = NULL, *P_521 = NULL; + 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; - /* 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(); - #if 1 /* optional */ ctx = BN_CTX_new(); if (!ctx) ABORT; @@ -317,10 +351,56 @@ int main(int argc, char *argv[]) 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(p, BN_prime_checks, 0, ctx, NULL)) 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; @@ -340,6 +420,10 @@ int main(int argc, char *argv[]) /* 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); @@ -348,7 +432,9 @@ int main(int argc, char *argv[]) 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"); @@ -360,7 +446,7 @@ int main(int argc, char *argv[]) /* Curve P-224 (FIPS PUB 186-2, App. 6) */ if (!BN_hex2bn(&p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001")) ABORT; - if (1 != BN_is_prime(p, BN_prime_checks, 0, ctx, NULL)) 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; @@ -381,6 +467,10 @@ int main(int argc, char *argv[]) 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; @@ -388,7 +478,9 @@ int main(int argc, char *argv[]) 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"); @@ -400,7 +492,7 @@ int main(int argc, char *argv[]) /* Curve P-256 (FIPS PUB 186-2, App. 6) */ if (!BN_hex2bn(&p, "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")) ABORT; - if (1 != BN_is_prime(p, BN_prime_checks, 0, ctx, NULL)) 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; @@ -422,6 +514,10 @@ int main(int argc, char *argv[]) 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; @@ -429,7 +525,9 @@ int main(int argc, char *argv[]) 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"); @@ -442,7 +540,7 @@ int main(int argc, char *argv[]) if (!BN_hex2bn(&p, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF")) ABORT; - if (1 != BN_is_prime(p, BN_prime_checks, 0, ctx, NULL)) 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" @@ -468,6 +566,10 @@ int main(int argc, char *argv[]) "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; @@ -475,7 +577,9 @@ int main(int argc, char *argv[]) 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"); @@ -489,7 +593,7 @@ int main(int argc, char *argv[]) if (!BN_hex2bn(&p, "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFF")) ABORT; - if (1 != BN_is_prime(p, BN_prime_checks, 0, ctx, NULL)) ABORT; + if (1 != BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) ABORT; if (!BN_hex2bn(&a, "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFC")) ABORT; @@ -520,6 +624,10 @@ int main(int argc, char *argv[]) "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; @@ -527,7 +635,9 @@ int main(int argc, char *argv[]) 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"); @@ -549,13 +659,15 @@ int main(int argc, char *argv[]) if (!EC_POINT_is_at_infinity(group, R)) ABORT; /* R = P + 2Q */ { - const EC_POINT *points[3]; - const BIGNUM *scalars[3]; + 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; @@ -577,7 +689,7 @@ int main(int argc, char *argv[]) if (!BN_pseudo_rand(y, BN_num_bits(y), 0, 0)) ABORT; if (!BN_add(z, z, y)) ABORT; - z->neg = 1; + BN_set_negative(z, 1); scalars[0] = y; scalars[1] = z; /* z = -(order + y) */ @@ -589,29 +701,43 @@ int main(int argc, char *argv[]) if (!BN_pseudo_rand(x, BN_num_bits(y) - 1, 0, 0)) ABORT; if (!BN_add(z, x, y)) ABORT; - z->neg = 1; + 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; + 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_192, 0, ctx); - timings(P_192, 1, ctx); - timings(P_224, 0, ctx); - timings(P_224, 1, ctx); - timings(P_256, 0, ctx); - timings(P_256, 1, ctx); - timings(P_384, 0, ctx); - timings(P_384, 1, ctx); - timings(P_521, 0, ctx); - timings(P_521, 1, ctx); + 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 @@ -624,12 +750,587 @@ int main(int argc, char *argv[]) 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 |