EC_KEY * EC_KEY_new_method(ENGINE *engine) { EC_KEY *ret; if ((ret = calloc(1, sizeof(EC_KEY))) == NULL) { ECerror(ERR_R_MALLOC_FAILURE); return NULL; } ret->meth = EC_KEY_get_default_method(); #ifndef OPENSSL_NO_ENGINE if (engine != NULL) { if (!ENGINE_init(engine)) { ECerror(ERR_R_ENGINE_LIB); goto err; } ret->engine = engine; } else ret->engine = ENGINE_get_default_EC(); if (ret->engine) { ret->meth = ENGINE_get_EC(ret->engine); if (ret->meth == NULL) { ECerror(ERR_R_ENGINE_LIB); goto err; } } #endif ret->version = 1; ret->flags = 0; ret->group = NULL; ret->pub_key = NULL; ret->priv_key = NULL; ret->enc_flag = 0; ret->conv_form = POINT_CONVERSION_UNCOMPRESSED; ret->references = 1; ret->method_data = NULL; if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, ret, &ret->ex_data)) goto err; if (ret->meth->init != NULL && ret->meth->init(ret) == 0) goto err; return ret; err: EC_KEY_free(ret); return NULL; }
int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { if (group->field_data1 == NULL) { ECerror(EC_R_NOT_INITIALIZED); return 0; } return BN_from_montgomery(r, a, group->field_data1, ctx); }
int ec_GFp_simple_group_set_curve(EC_GROUP * group, const BIGNUM * p, const BIGNUM * a, const BIGNUM * b, BN_CTX * ctx) { int ret = 0; BN_CTX *new_ctx = NULL; BIGNUM *tmp_a; /* p must be a prime > 3 */ if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) { ECerror(EC_R_INVALID_FIELD); return 0; } if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); if ((tmp_a = BN_CTX_get(ctx)) == NULL) goto err; /* group->field */ if (!BN_copy(&group->field, p)) goto err; BN_set_negative(&group->field, 0); /* group->a */ if (!BN_nnmod(tmp_a, a, p, ctx)) goto err; if (group->meth->field_encode) { if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) goto err; } else if (!BN_copy(&group->a, tmp_a)) goto err; /* group->b */ if (!BN_nnmod(&group->b, b, p, ctx)) goto err; if (group->meth->field_encode) if (!group->meth->field_encode(group, &group->b, &group->b, ctx)) goto err; /* group->a_is_minus3 */ if (!BN_add_word(tmp_a, 3)) goto err; group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field)); ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r, BN_CTX *ctx) { if (group->field_data2 == NULL) { ECerror(EC_R_NOT_INITIALIZED); return 0; } if (!BN_copy(r, group->field_data2)) return 0; return 1; }
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 */ ECerror(ERR_R_PASSED_NULL_PARAMETER); return 0; } return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y, BN_value_one(), ctx); }
int ec_GFp_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; BN_MONT_CTX_free(group->field_data1); group->field_data1 = 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)) { ECerror(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: BN_CTX_free(new_ctx); BN_MONT_CTX_free(mont); BN_free(one); return ret; }
int EC_GROUP_check(const EC_GROUP * group, BN_CTX * ctx) { int ret = 0; BIGNUM *order; BN_CTX *new_ctx = NULL; EC_POINT *point = NULL; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { ECerror(ERR_R_MALLOC_FAILURE); goto err; } } BN_CTX_start(ctx); if ((order = BN_CTX_get(ctx)) == NULL) goto err; /* check the discriminant */ if (!EC_GROUP_check_discriminant(group, ctx)) { ECerror(EC_R_DISCRIMINANT_IS_ZERO); goto err; } /* check the generator */ if (group->generator == NULL) { ECerror(EC_R_UNDEFINED_GENERATOR); goto err; } if (EC_POINT_is_on_curve(group, group->generator, ctx) <= 0) { ECerror(EC_R_POINT_IS_NOT_ON_CURVE); goto err; } /* check the order of the generator */ if ((point = EC_POINT_new(group)) == NULL) goto err; if (!EC_GROUP_get_order(group, order, ctx)) goto err; if (BN_is_zero(order)) { ECerror(EC_R_UNDEFINED_ORDER); goto err; } if (!EC_POINT_mul(group, point, order, NULL, NULL, ctx)) goto err; if (EC_POINT_is_at_infinity(group, point) <= 0) { ECerror(EC_R_INVALID_GROUP_ORDER); goto err; } ret = 1; err: if (ctx != NULL) BN_CTX_end(ctx); BN_CTX_free(new_ctx); EC_POINT_free(point); return ret; }
int EC_KEY_print_fp(FILE * fp, const EC_KEY * x, int off) { BIO *b; int ret; if ((b = BIO_new(BIO_s_file())) == NULL) { ECerror(ERR_R_BIO_LIB); return (0); } BIO_set_fp(b, fp, BIO_NOCLOSE); ret = EC_KEY_print(b, x, off); BIO_free(b); return (ret); }
int EC_GROUP_get_trinomial_basis(const EC_GROUP * group, unsigned int *k) { if (group == NULL) return 0; if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != NID_X9_62_characteristic_two_field || !((group->poly[0] != 0) && (group->poly[1] != 0) && (group->poly[2] == 0))) { ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } if (k) *k = group->poly[1]; return 1; }
static EC_PRE_COMP * ec_pre_comp_new(const EC_GROUP * group) { EC_PRE_COMP *ret = NULL; if (!group) return NULL; ret = malloc(sizeof(EC_PRE_COMP)); if (!ret) { ECerror(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; }
int ec_GFp_simple_make_affine(const EC_GROUP * group, EC_POINT * point, BN_CTX * ctx) { BN_CTX *new_ctx = NULL; BIGNUM *x, *y; int ret = 0; if (point->Z_is_one || EC_POINT_is_at_infinity(group, point) > 0) return 1; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); if ((x = BN_CTX_get(ctx)) == NULL) goto err; if ((y = BN_CTX_get(ctx)) == NULL) goto err; if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; if (!point->Z_is_one) { ECerror(ERR_R_INTERNAL_ERROR); goto err; } ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ECPKParameters_print(BIO * bp, const EC_GROUP * x, int off) { unsigned char *buffer = NULL; size_t buf_len = 0, i; int ret = 0, reason = ERR_R_BIO_LIB; BN_CTX *ctx = NULL; const EC_POINT *point = NULL; BIGNUM *p = NULL, *a = NULL, *b = NULL, *gen = NULL, *order = NULL, *cofactor = NULL; const unsigned char *seed; size_t seed_len = 0; const char *nname; static const char *gen_compressed = "Generator (compressed):"; static const char *gen_uncompressed = "Generator (uncompressed):"; static const char *gen_hybrid = "Generator (hybrid):"; if (!x) { reason = ERR_R_PASSED_NULL_PARAMETER; goto err; } ctx = BN_CTX_new(); if (ctx == NULL) { reason = ERR_R_MALLOC_FAILURE; goto err; } if (EC_GROUP_get_asn1_flag(x)) { /* the curve parameter are given by an asn1 OID */ int nid; if (!BIO_indent(bp, off, 128)) goto err; nid = EC_GROUP_get_curve_name(x); if (nid == 0) goto err; if (BIO_printf(bp, "ASN1 OID: %s", OBJ_nid2sn(nid)) <= 0) goto err; if (BIO_printf(bp, "\n") <= 0) goto err; nname = EC_curve_nid2nist(nid); if (nname) { if (!BIO_indent(bp, off, 128)) goto err; if (BIO_printf(bp, "NIST CURVE: %s\n", nname) <= 0) goto err; } } else { /* explicit parameters */ int is_char_two = 0; point_conversion_form_t form; int tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(x)); if (tmp_nid == NID_X9_62_characteristic_two_field) is_char_two = 1; if ((p = BN_new()) == NULL || (a = BN_new()) == NULL || (b = BN_new()) == NULL || (order = BN_new()) == NULL || (cofactor = BN_new()) == NULL) { reason = ERR_R_MALLOC_FAILURE; goto err; } #ifndef OPENSSL_NO_EC2M if (is_char_two) { if (!EC_GROUP_get_curve_GF2m(x, p, a, b, ctx)) { reason = ERR_R_EC_LIB; goto err; } } else /* prime field */ #endif { if (!EC_GROUP_get_curve_GFp(x, p, a, b, ctx)) { reason = ERR_R_EC_LIB; goto err; } } if ((point = EC_GROUP_get0_generator(x)) == NULL) { reason = ERR_R_EC_LIB; goto err; } if (!EC_GROUP_get_order(x, order, NULL) || !EC_GROUP_get_cofactor(x, cofactor, NULL)) { reason = ERR_R_EC_LIB; goto err; } form = EC_GROUP_get_point_conversion_form(x); if ((gen = EC_POINT_point2bn(x, point, form, NULL, ctx)) == NULL) { reason = ERR_R_EC_LIB; goto err; } buf_len = (size_t) BN_num_bytes(p); if (buf_len < (i = (size_t) BN_num_bytes(a))) buf_len = i; if (buf_len < (i = (size_t) BN_num_bytes(b))) buf_len = i; if (buf_len < (i = (size_t) BN_num_bytes(gen))) buf_len = i; if (buf_len < (i = (size_t) BN_num_bytes(order))) buf_len = i; if (buf_len < (i = (size_t) BN_num_bytes(cofactor))) buf_len = i; if ((seed = EC_GROUP_get0_seed(x)) != NULL) seed_len = EC_GROUP_get_seed_len(x); buf_len += 10; if ((buffer = malloc(buf_len)) == NULL) { reason = ERR_R_MALLOC_FAILURE; goto err; } if (!BIO_indent(bp, off, 128)) goto err; /* print the 'short name' of the field type */ if (BIO_printf(bp, "Field Type: %s\n", OBJ_nid2sn(tmp_nid)) <= 0) goto err; if (is_char_two) { /* print the 'short name' of the base type OID */ int basis_type = EC_GROUP_get_basis_type(x); if (basis_type == 0) goto err; if (!BIO_indent(bp, off, 128)) goto err; if (BIO_printf(bp, "Basis Type: %s\n", OBJ_nid2sn(basis_type)) <= 0) goto err; /* print the polynomial */ if ((p != NULL) && !ASN1_bn_print(bp, "Polynomial:", p, buffer, off)) goto err; } else { if ((p != NULL) && !ASN1_bn_print(bp, "Prime:", p, buffer, off)) goto err; } if ((a != NULL) && !ASN1_bn_print(bp, "A: ", a, buffer, off)) goto err; if ((b != NULL) && !ASN1_bn_print(bp, "B: ", b, buffer, off)) goto err; if (form == POINT_CONVERSION_COMPRESSED) { if ((gen != NULL) && !ASN1_bn_print(bp, gen_compressed, gen, buffer, off)) goto err; } else if (form == POINT_CONVERSION_UNCOMPRESSED) { if ((gen != NULL) && !ASN1_bn_print(bp, gen_uncompressed, gen, buffer, off)) goto err; } else { /* form == POINT_CONVERSION_HYBRID */ if ((gen != NULL) && !ASN1_bn_print(bp, gen_hybrid, gen, buffer, off)) goto err; } if ((order != NULL) && !ASN1_bn_print(bp, "Order: ", order, buffer, off)) goto err; if ((cofactor != NULL) && !ASN1_bn_print(bp, "Cofactor: ", cofactor, buffer, off)) goto err; if (seed && !print_bin(bp, "Seed:", seed, seed_len, off)) goto err; } ret = 1; err: if (!ret) ECerror(reason); BN_free(p); BN_free(a); BN_free(b); BN_free(gen); BN_free(order); BN_free(cofactor); BN_CTX_free(ctx); free(buffer); return (ret); }
/* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. * This is an array r[] of values that are either zero or odd with an * absolute value less than 2^w satisfying * scalar = \sum_j r[j]*2^j * where at most one of any w+1 consecutive digits is non-zero * with the exception that the most significant digit may be only * w-1 zeros away from that next non-zero digit. */ static signed char * compute_wNAF(const BIGNUM * scalar, int w, size_t * ret_len) { int window_val; int ok = 0; signed char *r = NULL; int sign = 1; int bit, next_bit, mask; size_t len = 0, j; if (BN_is_zero(scalar)) { r = malloc(1); if (!r) { ECerror(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 */ ECerror(ERR_R_INTERNAL_ERROR); goto err; } bit = 1 << w; /* at most 128 */ next_bit = bit << 1; /* at most 256 */ mask = next_bit - 1; /* at most 255 */ if (BN_is_negative(scalar)) { sign = -1; } if (scalar->d == NULL || scalar->top == 0) { ECerror(ERR_R_INTERNAL_ERROR); goto err; } len = BN_num_bits(scalar); r = 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) { ECerror(ERR_R_MALLOC_FAILURE); goto err; } window_val = scalar->d[0] & mask; j = 0; while ((window_val != 0) || (j + w + 1 < len)) { /* if j+w+1 >= len, window_val will not increase */ int digit = 0; /* 0 <= window_val <= 2^(w+1) */ if (window_val & 1) { /* 0 < window_val < 2^(w+1) */ if (window_val & bit) { digit = window_val - next_bit; /* -2^w < digit < 0 */ #if 1 /* modified wNAF */ if (j + w + 1 >= len) { /* * special case for generating * modified wNAFs: no new bits will * be added into window_val, so using * a positive digit here will * decrease the total length of the * representation */ digit = window_val & (mask >> 1); /* 0 < digit < 2^w */ } #endif } else {
int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP * group, const EC_POINT * point, BIGNUM * x, BIGNUM * y, BN_CTX * ctx) { BN_CTX *new_ctx = NULL; BIGNUM *Z, *Z_1, *Z_2, *Z_3; const BIGNUM *Z_; int ret = 0; if (EC_POINT_is_at_infinity(group, point) > 0) { ECerror(EC_R_POINT_AT_INFINITY); return 0; } if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); if ((Z = BN_CTX_get(ctx)) == NULL) goto err; if ((Z_1 = BN_CTX_get(ctx)) == NULL) goto err; if ((Z_2 = BN_CTX_get(ctx)) == NULL) goto err; if ((Z_3 = BN_CTX_get(ctx)) == NULL) goto err; /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ if (group->meth->field_decode) { if (!group->meth->field_decode(group, Z, &point->Z, ctx)) goto err; Z_ = Z; } else { Z_ = &point->Z; } if (BN_is_one(Z_)) { if (group->meth->field_decode) { if (x != NULL) { if (!group->meth->field_decode(group, x, &point->X, ctx)) goto err; } if (y != NULL) { if (!group->meth->field_decode(group, y, &point->Y, ctx)) goto err; } } else { if (x != NULL) { if (!BN_copy(x, &point->X)) goto err; } if (y != NULL) { if (!BN_copy(y, &point->Y)) goto err; } } } else { if (!BN_mod_inverse_ct(Z_1, Z_, &group->field, ctx)) { ECerror(ERR_R_BN_LIB); goto err; } if (group->meth->field_encode == 0) { /* field_sqr works on standard representation */ if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) goto err; } else { if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) goto err; } if (x != NULL) { /* * in the Montgomery case, field_mul will cancel out * Montgomery factor in X: */ if (!group->meth->field_mul(group, x, &point->X, Z_2, ctx)) goto err; } if (y != NULL) { if (group->meth->field_encode == 0) { /* field_mul works on standard representation */ if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) goto err; } else { if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) goto err; } /* * in the Montgomery case, field_mul will cancel out * Montgomery factor in Y: */ if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) goto err; } } ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_group_check_discriminant(const EC_GROUP * group, BN_CTX * ctx) { int ret = 0; BIGNUM *a, *b, *order, *tmp_1, *tmp_2; const BIGNUM *p = &group->field; BN_CTX *new_ctx = NULL; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { ECerror(ERR_R_MALLOC_FAILURE); goto err; } } BN_CTX_start(ctx); if ((a = BN_CTX_get(ctx)) == NULL) goto err; if ((b = BN_CTX_get(ctx)) == NULL) goto err; if ((tmp_1 = BN_CTX_get(ctx)) == NULL) goto err; if ((tmp_2 = BN_CTX_get(ctx)) == NULL) goto err; if ((order = BN_CTX_get(ctx)) == NULL) goto err; if (group->meth->field_decode) { if (!group->meth->field_decode(group, a, &group->a, ctx)) goto err; if (!group->meth->field_decode(group, b, &group->b, ctx)) goto err; } else { if (!BN_copy(a, &group->a)) goto err; if (!BN_copy(b, &group->b)) goto err; } /* * check the discriminant: y^2 = x^3 + a*x + b is an elliptic curve * <=> 4*a^3 + 27*b^2 != 0 (mod p) 0 =< a, b < p */ if (BN_is_zero(a)) { if (BN_is_zero(b)) goto err; } else if (!BN_is_zero(b)) { if (!BN_mod_sqr(tmp_1, a, p, ctx)) goto err; if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx)) goto err; if (!BN_lshift(tmp_1, tmp_2, 2)) goto err; /* tmp_1 = 4*a^3 */ if (!BN_mod_sqr(tmp_2, b, p, ctx)) goto err; if (!BN_mul_word(tmp_2, 27)) goto err; /* tmp_2 = 27*b^2 */ if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx)) goto err; if (BN_is_zero(a)) goto err; } ret = 1; err: if (ctx != NULL) BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_points_make_affine(const EC_GROUP * group, size_t num, EC_POINT * points[], BN_CTX * ctx) { BN_CTX *new_ctx = NULL; BIGNUM *tmp0, *tmp1; size_t pow2 = 0; BIGNUM **heap = NULL; size_t i; int ret = 0; if (num == 0) return 1; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); if ((tmp0 = BN_CTX_get(ctx)) == NULL) goto err; if ((tmp1 = BN_CTX_get(ctx)) == NULL) goto err; /* * Before converting the individual points, compute inverses of all Z * values. Modular inversion is rather slow, but luckily we can do * with a single explicit inversion, plus about 3 multiplications per * input value. */ pow2 = 1; while (num > pow2) pow2 <<= 1; /* * Now pow2 is the smallest power of 2 satifsying pow2 >= num. We * need twice that. */ pow2 <<= 1; heap = reallocarray(NULL, pow2, sizeof heap[0]); if (heap == NULL) goto err; /* * The array is used as a binary tree, exactly as in heapsort: * * heap[1] heap[2] heap[3] heap[4] heap[5] * heap[6] heap[7] heap[8]heap[9] heap[10]heap[11] * heap[12]heap[13] heap[14] heap[15] * * We put the Z's in the last line; then we set each other node to the * product of its two child-nodes (where empty or 0 entries are * treated as ones); then we invert heap[1]; then we invert each * other node by replacing it by the product of its parent (after * inversion) and its sibling (before inversion). */ heap[0] = NULL; for (i = pow2 / 2 - 1; i > 0; i--) heap[i] = NULL; for (i = 0; i < num; i++) heap[pow2 / 2 + i] = &points[i]->Z; for (i = pow2 / 2 + num; i < pow2; i++) heap[i] = NULL; /* set each node to the product of its children */ for (i = pow2 / 2 - 1; i > 0; i--) { heap[i] = BN_new(); if (heap[i] == NULL) goto err; if (heap[2 * i] != NULL) { if ((heap[2 * i + 1] == NULL) || BN_is_zero(heap[2 * i + 1])) { if (!BN_copy(heap[i], heap[2 * i])) goto err; } else { if (BN_is_zero(heap[2 * i])) { if (!BN_copy(heap[i], heap[2 * i + 1])) goto err; } else { if (!group->meth->field_mul(group, heap[i], heap[2 * i], heap[2 * i + 1], ctx)) goto err; } } } } /* invert heap[1] */ if (!BN_is_zero(heap[1])) { if (!BN_mod_inverse_ct(heap[1], heap[1], &group->field, ctx)) { ECerror(ERR_R_BN_LIB); goto err; } } if (group->meth->field_encode != 0) { /* * in the Montgomery case, we just turned R*H (representing * H) into 1/(R*H), but we need R*(1/H) (representing * 1/H); i.e. we have need to multiply by the Montgomery * factor twice */ if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err; if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err; } /* set other heap[i]'s to their inverses */ for (i = 2; i < pow2 / 2 + num; i += 2) { /* i is even */ if ((heap[i + 1] != NULL) && !BN_is_zero(heap[i + 1])) { if (!group->meth->field_mul(group, tmp0, heap[i / 2], heap[i + 1], ctx)) goto err; if (!group->meth->field_mul(group, tmp1, heap[i / 2], heap[i], ctx)) goto err; if (!BN_copy(heap[i], tmp0)) goto err; if (!BN_copy(heap[i + 1], tmp1)) goto err; } else { if (!BN_copy(heap[i], heap[i / 2])) goto err; } } /* * we have replaced all non-zero Z's by their inverses, now fix up * all the points */ for (i = 0; i < num; i++) { EC_POINT *p = points[i]; if (!BN_is_zero(&p->Z)) { /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ if (!group->meth->field_sqr(group, tmp1, &p->Z, ctx)) goto err; if (!group->meth->field_mul(group, &p->X, &p->X, tmp1, ctx)) goto err; if (!group->meth->field_mul(group, tmp1, tmp1, &p->Z, ctx)) goto err; if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp1, ctx)) goto err; if (group->meth->field_set_to_one != 0) { if (!group->meth->field_set_to_one(group, &p->Z, ctx)) goto err; } else { if (!BN_one(&p->Z)) goto err; } p->Z_is_one = 1; } } ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); if (heap != NULL) { /* * heap[pow2/2] .. heap[pow2-1] have not been allocated * locally! */ for (i = pow2 / 2 - 1; i > 0; i--) { BN_clear_free(heap[i]); } free(heap); } return ret; }