// Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
// Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_EC_INTERNAL_H
#define OPENSSL_HEADER_CRYPTO_FIPSMODULE_EC_INTERNAL_H

#include <openssl/base.h>

#include <assert.h>

#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ex_data.h>

#include "../../mem_internal.h"
#include "../bn/internal.h"


DECLARE_OPAQUE_STRUCT(ec_key_st, ECKey)

BSSL_NAMESPACE_BEGIN

// EC internals.


// Cap the size of all field elements and scalars, including custom curves, to
// 66 bytes, large enough to fit secp521r1 and brainpoolP512r1, which appear to
// be the largest fields anyone plausibly uses.
#define EC_MAX_BYTES 66
#define EC_MAX_WORDS ((EC_MAX_BYTES + BN_BYTES - 1) / BN_BYTES)
#define EC_MAX_COMPRESSED (EC_MAX_BYTES + 1)
#define EC_MAX_UNCOMPRESSED (2 * EC_MAX_BYTES + 1)

static_assert(EC_MAX_WORDS <= BN_SMALL_MAX_WORDS,
              "bn_*_small functions not usable");


// Scalars.

// An EC_SCALAR is an integer fully reduced modulo the order. Only the first
// `order->width` words are used. An `EC_SCALAR` is specific to an `EC_GROUP`
// and must not be mixed between groups.
typedef struct {
  BN_ULONG words[EC_MAX_WORDS];
} EC_SCALAR;

// ec_bignum_to_scalar converts `in` to an `EC_SCALAR` and writes it to
// `*out`. It returns one on success and zero if `in` is out of range.
int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
                        const BIGNUM *in);

// ec_scalar_to_bytes serializes `in` as a big-endian bytestring to `out` and
// sets `*out_len` to the number of bytes written. The number of bytes written
// is `BN_num_bytes(&group->order)`, which is at most `EC_MAX_BYTES`.
void ec_scalar_to_bytes(const EC_GROUP *group, uint8_t *out, size_t *out_len,
                        const EC_SCALAR *in);

// ec_scalar_from_bytes deserializes `in` and stores the resulting scalar over
// group `group` to `out`. It returns one on success and zero if `in` is
// invalid.
int ec_scalar_from_bytes(const EC_GROUP *group, EC_SCALAR *out,
                         const uint8_t *in, size_t len);

// ec_scalar_reduce sets `out` to `words`, reduced modulo the group order.
// `words` must be less than order^2. `num` must be at most twice the width of
// group order. This function treats `words` as secret.
void ec_scalar_reduce(const EC_GROUP *group, EC_SCALAR *out,
                      const BN_ULONG *words, size_t num);

// ec_random_nonzero_scalar sets `out` to a uniformly selected random value from
// zero to `group->order` - 1. It returns one on success and zero on error.
int ec_random_scalar(const EC_GROUP *group, EC_SCALAR *out,
                     const uint8_t additional_data[32]);

// ec_random_nonzero_scalar sets `out` to a uniformly selected random value from
// 1 to `group->order` - 1. It returns one on success and zero on error.
int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
                             const uint8_t additional_data[32]);

// ec_scalar_equal_vartime returns one if `a` and `b` are equal and zero
// otherwise. Both values are treated as public.
int ec_scalar_equal_vartime(const EC_GROUP *group, const EC_SCALAR *a,
                            const EC_SCALAR *b);

// ec_scalar_is_zero returns one if `a` is zero and zero otherwise.
int ec_scalar_is_zero(const EC_GROUP *group, const EC_SCALAR *a);

// ec_scalar_add sets `r` to `a` + `b`.
void ec_scalar_add(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a,
                   const EC_SCALAR *b);

// ec_scalar_sub sets `r` to `a` - `b`.
void ec_scalar_sub(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a,
                   const EC_SCALAR *b);

// ec_scalar_neg sets `r` to -`a`.
void ec_scalar_neg(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a);

// ec_scalar_to_montgomery sets `r` to `a` in Montgomery form.
void ec_scalar_to_montgomery(const EC_GROUP *group, EC_SCALAR *r,
                             const EC_SCALAR *a);

// ec_scalar_to_montgomery sets `r` to `a` converted from Montgomery form.
void ec_scalar_from_montgomery(const EC_GROUP *group, EC_SCALAR *r,
                               const EC_SCALAR *a);

// ec_scalar_mul_montgomery sets `r` to `a` * `b` where inputs and outputs are
// in Montgomery form.
void ec_scalar_mul_montgomery(const EC_GROUP *group, EC_SCALAR *r,
                              const EC_SCALAR *a, const EC_SCALAR *b);

// ec_scalar_inv0_montgomery sets `r` to `a`^-1 where inputs and outputs are in
// Montgomery form. If `a` is zero, `r` is set to zero.
void ec_scalar_inv0_montgomery(const EC_GROUP *group, EC_SCALAR *r,
                               const EC_SCALAR *a);

// ec_scalar_to_montgomery_inv_vartime sets `r` to `a`^-1 R. That is, it takes
// in `a` not in Montgomery form and computes the inverse in Montgomery form. It
// returns one on success and zero if `a` has no inverse. This function assumes
// `a` is public and may leak information about it via timing.
//
// Note this is not the same operation as `ec_scalar_inv0_montgomery`.
int ec_scalar_to_montgomery_inv_vartime(const EC_GROUP *group, EC_SCALAR *r,
                                        const EC_SCALAR *a);

// ec_scalar_select, in constant time, sets `out` to `a` if `mask` is all ones
// and `b` if `mask` is all zeros.
void ec_scalar_select(const EC_GROUP *group, EC_SCALAR *out, BN_ULONG mask,
                      const EC_SCALAR *a, const EC_SCALAR *b);


// Field elements.

// An EC_FELEM represents a field element. Only the first `field->width` words
// are used. An `EC_FELEM` is specific to an `EC_GROUP` and must not be mixed
// between groups. Unless otherwise stated, all inputs and outputs are in
// Montgomery form.
typedef struct {
  BN_ULONG words[EC_MAX_WORDS];
} EC_FELEM;

// ec_felem_one returns one in `group`'s field.
const EC_FELEM *ec_felem_one(const EC_GROUP *group);

// ec_bignum_to_felem converts `in` to an `EC_FELEM`. It returns one on success
// and zero if `in` is out of range.
int ec_bignum_to_felem(const EC_GROUP *group, EC_FELEM *out, const BIGNUM *in);

// ec_felem_to_bignum converts `in` to a `BIGNUM`. It returns one on success and
// zero on allocation failure.
int ec_felem_to_bignum(const EC_GROUP *group, BIGNUM *out, const EC_FELEM *in);

// ec_felem_to_bytes serializes `in` as a big-endian bytestring to `out` and
// sets `*out_len` to the number of bytes written. The number of bytes written
// is `BN_num_bytes(&group->order)`, which is at most `EC_MAX_BYTES`.
void ec_felem_to_bytes(const EC_GROUP *group, uint8_t *out, size_t *out_len,
                       const EC_FELEM *in);

// ec_felem_from_bytes deserializes `in` and stores the resulting field element
// to `out`. It returns one on success and zero if `in` is invalid.
int ec_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out, const uint8_t *in,
                        size_t len);

// ec_felem_neg sets `out` to -`a`.
void ec_felem_neg(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a);

// ec_felem_add sets `out` to `a` + `b`.
void ec_felem_add(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
                  const EC_FELEM *b);

// ec_felem_add sets `out` to `a` - `b`.
void ec_felem_sub(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
                  const EC_FELEM *b);

// ec_felem_non_zero_mask returns all ones if `a` is non-zero and all zeros
// otherwise.
BN_ULONG ec_felem_non_zero_mask(const EC_GROUP *group, const EC_FELEM *a);

// ec_felem_select, in constant time, sets `out` to `a` if `mask` is all ones
// and `b` if `mask` is all zeros.
void ec_felem_select(const EC_GROUP *group, EC_FELEM *out, BN_ULONG mask,
                     const EC_FELEM *a, const EC_FELEM *b);

// ec_felem_equal returns one if `a` and `b` are equal and zero otherwise.
int ec_felem_equal(const EC_GROUP *group, const EC_FELEM *a, const EC_FELEM *b);

// ec_felem_mul sets `out` to `a` * `b`.
void ec_felem_mul(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
                  const EC_FELEM *b);

// ec_felem_sqr sets `out` to `a`^2.
void ec_felem_sqr(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a);

// ec_felem_to_montgomery sets `out` to `a` converted to Montgomery form.
void ec_felem_to_montgomery(const EC_GROUP *group, EC_FELEM *out,
                            const EC_FELEM *a);

// ec_felem_from_montgomery sets `out` to `a` converted from Montgomery form.
void ec_felem_from_montgomery(const EC_GROUP *group, EC_FELEM *out,
                              const EC_FELEM *a);

// ec_felem_reduce sets `out` to `words`, reduced modulo the field size, p.
// `words` must be less than p^2. `num` must be at most twice the width of p.
// This function treats `words` as secret.
void ec_felem_reduce(const EC_GROUP *group, EC_FELEM *out,
                     const BN_ULONG *words, size_t num);

// ec_felem_exp sets `out` to `a`^`exp`. It treats `a` is secret but `exp` as
// public.
//
// TODO(crbug.com/42290435): hash-to-curve uses this as part of computing a
// square root, which is what compressed coordinates ultimately needs to avoid
// `BIGNUM`. Can we unify this a bit? By generalizing to arbitrary
// exponentiation, we also miss an opportunity to use a specialized addition
// chain. We also miss our specialized field arithmetic for P-256.
void ec_felem_exp(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
                  const BN_ULONG *exp, size_t num_exp);


// Points.
//
// Points may represented in affine coordinates as `EC_AFFINE` or Jacobian
// coordinates as `EC_JACOBIAN`. Affine coordinates directly represent a
// point on the curve, but point addition over affine coordinates requires
// costly field inversions, so arithmetic is done in Jacobian coordinates.
// Converting from affine to Jacobian is cheap, while converting from Jacobian
// to affine costs a field inversion. (Jacobian coordinates amortize the field
// inversions needed in a sequence of point operations.)

// An EC_JACOBIAN represents an elliptic curve point in Jacobian coordinates.
// Unlike `EC_POINT`, it is a plain struct which can be stack-allocated and
// needs no cleanup. It is specific to an `EC_GROUP` and must not be mixed
// between groups.
typedef struct {
  // X, Y, and Z are Jacobian projective coordinates. They represent
  // (X/Z^2, Y/Z^3) if Z != 0 and the point at infinity otherwise.
  EC_FELEM X, Y, Z;
} EC_JACOBIAN;

// An EC_AFFINE represents an elliptic curve point in affine coordinates.
// coordinates. Note the point at infinity cannot be represented in affine
// coordinates.
typedef struct {
  EC_FELEM X, Y;
} EC_AFFINE;

// ec_affine_to_jacobian converts `p` to Jacobian form and writes the result to
// `*out`. This operation is very cheap and only costs a few copies.
void ec_affine_to_jacobian(const EC_GROUP *group, EC_JACOBIAN *out,
                           const EC_AFFINE *p);

// ec_jacobian_to_affine converts `p` to affine form and writes the result to
// `*out`. It returns one on success and zero if `p` was the point at infinity.
// This operation performs a field inversion and should only be done once per
// point.
//
// If only extracting the x-coordinate, use `ec_get_x_coordinate_*` which is
// slightly faster.
int ec_jacobian_to_affine(const EC_GROUP *group, EC_AFFINE *out,
                          const EC_JACOBIAN *p);

// ec_jacobian_to_affine_batch converts `num` points in `in` from Jacobian
// coordinates to affine coordinates and writes the results to `out`. It returns
// one on success and zero if any of the input points were infinity.
//
// This function is not implemented for all curves. Add implementations as
// needed.
int ec_jacobian_to_affine_batch(const EC_GROUP *group, EC_AFFINE *out,
                                const EC_JACOBIAN *in, size_t num);

// ec_point_set_affine_coordinates sets `out`'s to a point with affine
// coordinates `x` and `y`. It returns one if the point is on the curve and
// zero otherwise. If the point is not on the curve, the value of `out` is
// undefined.
int ec_point_set_affine_coordinates(const EC_GROUP *group, EC_AFFINE *out,
                                    const EC_FELEM *x, const EC_FELEM *y);

// ec_point_mul_no_self_test does the same as `EC_POINT_mul`, but doesn't try to
// run the self-test first. This is for use in the self tests themselves, to
// prevent an infinite loop.
int ec_point_mul_no_self_test(const EC_GROUP *group, EC_POINT *r,
                              const BIGNUM *g_scalar, const EC_POINT *p,
                              const BIGNUM *p_scalar, BN_CTX *ctx);

// ec_point_mul_scalar sets `r` to `p` * `scalar`. Both inputs are considered
// secret.
int ec_point_mul_scalar(const EC_GROUP *group, EC_JACOBIAN *r,
                        const EC_JACOBIAN *p, const EC_SCALAR *scalar);

// ec_point_mul_scalar_base sets `r` to generator * `scalar`. `scalar` is
// treated as secret.
int ec_point_mul_scalar_base(const EC_GROUP *group, EC_JACOBIAN *r,
                             const EC_SCALAR *scalar);

// ec_point_mul_scalar_batch sets `r` to `p0` * `scalar0` + `p1` * `scalar1` +
// `p2` * `scalar2`. `p2` may be NULL to skip that term.
//
// The inputs are treated as secret, however, this function leaks information
// about whether intermediate computations add a point to itself. Callers must
// ensure that discrete logs between `p0`, `p1`, and `p2` are uniformly
// distributed and independent of the scalars, which should be uniformly
// selected and not under the attackers control. This ensures the doubling case
// will occur with negligible probability.
//
// This function is not implemented for all curves. Add implementations as
// needed.
//
// TODO(davidben): This function does not use base point tables. For now, it is
// only used with the generic `EC_GFp_mont_method` implementation which has
// none. If generalizing to tuned curves, this may be useful. However, we still
// must double up to the least efficient input, so precomputed tables can only
// save table setup and allow a wider window size.
int ec_point_mul_scalar_batch(const EC_GROUP *group, EC_JACOBIAN *r,
                              const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
                              const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
                              const EC_JACOBIAN *p2, const EC_SCALAR *scalar2);

#define EC_MONT_PRECOMP_COMB_SIZE 5

// An `EC_PRECOMP` stores precomputed information about a point, to optimize
// repeated multiplications involving it. It is a union so different
// `EC_METHOD`s can store different information in it.
typedef union {
  EC_AFFINE comb[(1 << EC_MONT_PRECOMP_COMB_SIZE) - 1];
} EC_PRECOMP;

// ec_init_precomp precomputes multiples of `p` and writes the result to `out`.
// It returns one on success and zero on error. The resulting table may be used
// with `ec_point_mul_scalar_precomp`. This function will fail if `p` is the
// point at infinity.
//
// This function is not implemented for all curves. Add implementations as
// needed.
int ec_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
                    const EC_JACOBIAN *p);

// ec_point_mul_scalar_precomp sets `r` to `p0` * `scalar0` + `p1` * `scalar1` +
// `p2` * `scalar2`. `p1` or `p2` may be NULL to skip the corresponding term.
// The points are represented as `EC_PRECOMP` and must be initialized with
// `ec_init_precomp`. This function runs faster than `ec_point_mul_scalar_batch`
// but requires setup work per input point, so it is only appropriate for points
// which are used frequently.
//
// The inputs are treated as secret, however, this function leaks information
// about whether intermediate computations add a point to itself. Callers must
// ensure that discrete logs between `p0`, `p1`, and `p2` are uniformly
// distributed and independent of the scalars, which should be uniformly
// selected and not under the attackers control. This ensures the doubling case
// will occur with negligible probability.
//
// This function is not implemented for all curves. Add implementations as
// needed.
//
// TODO(davidben): This function does not use base point tables. For now, it is
// only used with the generic `EC_GFp_mont_method` implementation which has
// none. If generalizing to tuned curves, we should add a parameter for the base
// point and arrange for the generic implementation to have base point tables
// available.
int ec_point_mul_scalar_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
                                const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
                                const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
                                const EC_PRECOMP *p2, const EC_SCALAR *scalar2);

// ec_point_mul_scalar_public sets `r` to
// generator * `g_scalar` + `p` * `p_scalar`. It assumes that the inputs are
// public so there is no concern about leaking their values through timing.
int ec_point_mul_scalar_public(const EC_GROUP *group, EC_JACOBIAN *r,
                               const EC_SCALAR *g_scalar, const EC_JACOBIAN *p,
                               const EC_SCALAR *p_scalar);

// ec_point_mul_scalar_public_batch sets `r` to the sum of generator *
// `g_scalar` and `points[i]` * `scalars[i]` where `points` and `scalars` have
// `num` elements. It assumes that the inputs are public so there is no concern
// about leaking their values through timing. `g_scalar` may be NULL to skip
// that term.
//
// This function is not implemented for all curves. Add implementations as
// needed.
int ec_point_mul_scalar_public_batch(const EC_GROUP *group, EC_JACOBIAN *r,
                                     const EC_SCALAR *g_scalar,
                                     const EC_JACOBIAN *points,
                                     const EC_SCALAR *scalars, size_t num);

// ec_point_select, in constant time, sets `out` to `a` if `mask` is all ones
// and `b` if `mask` is all zeros.
void ec_point_select(const EC_GROUP *group, EC_JACOBIAN *out, BN_ULONG mask,
                     const EC_JACOBIAN *a, const EC_JACOBIAN *b);

// ec_affine_select behaves like `ec_point_select` but acts on affine points.
void ec_affine_select(const EC_GROUP *group, EC_AFFINE *out, BN_ULONG mask,
                      const EC_AFFINE *a, const EC_AFFINE *b);

// ec_precomp_select behaves like `ec_point_select` but acts on `EC_PRECOMP`.
void ec_precomp_select(const EC_GROUP *group, EC_PRECOMP *out, BN_ULONG mask,
                       const EC_PRECOMP *a, const EC_PRECOMP *b);

// ec_cmp_x_coordinate compares the x (affine) coordinate of `p`, mod the group
// order, with `r`. It returns one if the values match and zero if `p` is the
// point at infinity of the values do not match. `p` is treated as public.
int ec_cmp_x_coordinate(const EC_GROUP *group, const EC_JACOBIAN *p,
                        const EC_SCALAR *r);

// ec_get_x_coordinate_as_scalar sets `*out` to `p`'s x-coordinate, modulo
// `group->order`. It returns one on success and zero if `p` is the point at
// infinity.
int ec_get_x_coordinate_as_scalar(const EC_GROUP *group, EC_SCALAR *out,
                                  const EC_JACOBIAN *p);

// ec_get_x_coordinate_as_bytes writes `p`'s affine x-coordinate to `out`, which
// must have at must `max_out` bytes. It sets `*out_len` to the number of bytes
// written. The value is written big-endian and zero-padded to the size of the
// field. This function returns one on success and zero on failure.
int ec_get_x_coordinate_as_bytes(const EC_GROUP *group, uint8_t *out,
                                 size_t *out_len, size_t max_out,
                                 const EC_JACOBIAN *p);

// ec_point_byte_len returns the number of bytes in the byte representation of
// a non-infinity point in `group`, encoded according to `form`, or zero if
// `form` is invalid.
size_t ec_point_byte_len(const EC_GROUP *group, point_conversion_form_t form);

// ec_point_to_bytes encodes `point` according to `form` and writes the result
// `buf`. It returns the size of the output on success or zero on error. At most
// `max_out` bytes will be written. The buffer should be at least
// `ec_point_byte_len` long to guarantee success.
size_t ec_point_to_bytes(const EC_GROUP *group, const EC_AFFINE *point,
                         point_conversion_form_t form, uint8_t *buf,
                         size_t max_out);

// ec_point_from_uncompressed parses `in` as a point in uncompressed form and
// sets the result to `out`. It returns one on success and zero if the input was
// invalid.
int ec_point_from_uncompressed(const EC_GROUP *group, EC_AFFINE *out,
                               const uint8_t *in, size_t len);

// ec_set_to_safe_point sets `out` to an arbitrary point on `group`, either the
// generator or the point at infinity. This is used to guard against callers of
// external APIs not checking the return value.
void ec_set_to_safe_point(const EC_GROUP *group, EC_JACOBIAN *out);

// ec_affine_jacobian_equal returns one if `a` and `b` represent the same point
// and zero otherwise. It treats both inputs as secret.
int ec_affine_jacobian_equal(const EC_GROUP *group, const EC_AFFINE *a,
                             const EC_JACOBIAN *b);

BSSL_NAMESPACE_END

// Implementation details.

struct ec_method_st {
  // point_get_affine_coordinates sets `*x` and `*y` to the affine coordinates
  // of `p`. Either `x` or `y` may be NULL to omit it. It returns one on success
  // and zero if `p` is the point at infinity. It leaks whether `p` was the
  // point at infinity, but otherwise treats `p` as secret.
  int (*point_get_affine_coordinates)(const EC_GROUP *,
                                      const bssl::EC_JACOBIAN *p,
                                      bssl::EC_FELEM *x, bssl::EC_FELEM *y);

  // jacobian_to_affine_batch implements `ec_jacobian_to_affine_batch`.
  int (*jacobian_to_affine_batch)(const EC_GROUP *group, bssl::EC_AFFINE *out,
                                  const bssl::EC_JACOBIAN *in, size_t num);

  // add sets `r` to `a` + `b`.
  void (*add)(const EC_GROUP *group, bssl::EC_JACOBIAN *r,
              const bssl::EC_JACOBIAN *a, const bssl::EC_JACOBIAN *b);
  // dbl sets `r` to `a` + `a`.
  void (*dbl)(const EC_GROUP *group, bssl::EC_JACOBIAN *r,
              const bssl::EC_JACOBIAN *a);

  // mul sets `r` to `scalar`*`p`.
  void (*mul)(const EC_GROUP *group, bssl::EC_JACOBIAN *r,
              const bssl::EC_JACOBIAN *p, const bssl::EC_SCALAR *scalar);
  // mul_base sets `r` to `scalar`*generator.
  void (*mul_base)(const EC_GROUP *group, bssl::EC_JACOBIAN *r,
                   const bssl::EC_SCALAR *scalar);
  // mul_batch implements `ec_mul_scalar_batch`.
  void (*mul_batch)(const EC_GROUP *group, bssl::EC_JACOBIAN *r,
                    const bssl::EC_JACOBIAN *p0, const bssl::EC_SCALAR *scalar0,
                    const bssl::EC_JACOBIAN *p1, const bssl::EC_SCALAR *scalar1,
                    const bssl::EC_JACOBIAN *p2,
                    const bssl::EC_SCALAR *scalar2);
  // mul_public sets `r` to `g_scalar`*generator + `p_scalar`*`p`. It assumes
  // that the inputs are public so there is no concern about leaking their
  // values through timing.
  //
  // This function may be omitted if `mul_public_batch` is provided.
  void (*mul_public)(const EC_GROUP *group, bssl::EC_JACOBIAN *r,
                     const bssl::EC_SCALAR *g_scalar,
                     const bssl::EC_JACOBIAN *p,
                     const bssl::EC_SCALAR *p_scalar);
  // mul_public_batch implements `ec_point_mul_scalar_public_batch`.
  int (*mul_public_batch)(const EC_GROUP *group, bssl::EC_JACOBIAN *r,
                          const bssl::EC_SCALAR *g_scalar,
                          const bssl::EC_JACOBIAN *points,
                          const bssl::EC_SCALAR *scalars, size_t num);

  // init_precomp implements `ec_init_precomp`.
  int (*init_precomp)(const EC_GROUP *group, bssl::EC_PRECOMP *out,
                      const bssl::EC_JACOBIAN *p);
  // mul_precomp implements `ec_point_mul_scalar_precomp`.
  void (*mul_precomp)(const EC_GROUP *group, bssl::EC_JACOBIAN *r,
                      const bssl::EC_PRECOMP *p0,
                      const bssl::EC_SCALAR *scalar0,
                      const bssl::EC_PRECOMP *p1,
                      const bssl::EC_SCALAR *scalar1,
                      const bssl::EC_PRECOMP *p2,
                      const bssl::EC_SCALAR *scalar2);

  // scalar_inv0_montgomery implements `ec_scalar_inv0_montgomery`.
  void (*scalar_inv0_montgomery)(const EC_GROUP *group, bssl::EC_SCALAR *out,
                                 const bssl::EC_SCALAR *in);

  // scalar_to_montgomery_inv_vartime implements
  // `ec_scalar_to_montgomery_inv_vartime`.
  int (*scalar_to_montgomery_inv_vartime)(const EC_GROUP *group,
                                          bssl::EC_SCALAR *out,
                                          const bssl::EC_SCALAR *in);

  // cmp_x_coordinate compares the x (affine) coordinate of `p`, mod the group
  // order, with `r`. It returns one if the values match and zero if `p` is the
  // point at infinity of the values do not match.
  int (*cmp_x_coordinate)(const EC_GROUP *group, const bssl::EC_JACOBIAN *p,
                          const bssl::EC_SCALAR *r);
} /* EC_METHOD */;

BSSL_NAMESPACE_BEGIN

const EC_METHOD *EC_GFp_mont_method();

BSSL_NAMESPACE_END

struct ec_point_st {
  // group is an owning reference to `group`, unless this is
  // `group->generator`.
  EC_GROUP *group;
  // raw is the group-specific point data. Functions that take `EC_POINT`
  // typically check consistency with `EC_GROUP` while functions that take
  // `EC_JACOBIAN` do not. Thus accesses to this field should be externally
  // checked for consistency.
  bssl::EC_JACOBIAN raw;
} /* EC_POINT */;

struct ec_group_st {
  const EC_METHOD *meth;

  // Unlike all other `EC_POINT`s, `generator` does not own `generator->group`
  // to avoid a reference cycle. Additionally, Z is guaranteed to be one, so X
  // and Y are suitable for use as an `EC_AFFINE`. Before `has_order` is set, Z
  // is one, but X and Y are uninitialized.
  EC_POINT generator;

  BN_MONT_CTX order;
  BN_MONT_CTX field;

  bssl::EC_FELEM a, b;  // Curve coefficients.

  // comment is a human-readable string describing the curve.
  const char *comment;

  // curve_name is the optional NID for named curve.
  //
  // If curve_name is NID_undef, the actual type is ECCustomGroup and the
  // refcount must be respected when allocating/freeing.
  int curve_name;

  uint8_t oid[9];
  uint8_t oid_len;

  // a_is_minus3 is one if `a` is -3 mod `field` and zero otherwise. Point
  // arithmetic is optimized for -3.
  int a_is_minus3;

  // has_order is one if `generator` and `order` have been initialized.
  int has_order;

  // field_greater_than_order is one if `field` is greater than `order` and zero
  // otherwise.
  int field_greater_than_order;
} /* EC_GROUP */;

BSSL_NAMESPACE_BEGIN

class ECCustomGroup : public ec_group_st, public RefCounted<ECCustomGroup> {
 public:
  explicit ECCustomGroup(const EC_METHOD *meth);

 private:
  ~ECCustomGroup();
  friend RefCounted;
};

EC_GROUP *ec_group_new(const EC_METHOD *meth, const BIGNUM *p, const BIGNUM *a,
                       const BIGNUM *b, BN_CTX *ctx);

void ec_GFp_mont_mul(const EC_GROUP *group, EC_JACOBIAN *r,
                     const EC_JACOBIAN *p, const EC_SCALAR *scalar);
void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_JACOBIAN *r,
                          const EC_SCALAR *scalar);
void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_JACOBIAN *r,
                           const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
                           const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
                           const EC_JACOBIAN *p2, const EC_SCALAR *scalar2);
int ec_GFp_mont_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
                             const EC_JACOBIAN *p);
void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
                             const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
                             const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
                             const EC_PRECOMP *p2, const EC_SCALAR *scalar2);

// ec_compute_wNAF writes the modified width-(w+1) Non-Adjacent Form (wNAF) of
// `scalar` to `out`. `out` must have room for `bits` + 1 elements, each of
// which will be either zero or odd with an absolute value less than  2^w
// satisfying
//     scalar = \sum_j out[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.
void ec_compute_wNAF(const EC_GROUP *group, int8_t *out,
                     const EC_SCALAR *scalar, size_t bits, int w);

int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_JACOBIAN *r,
                                 const EC_SCALAR *g_scalar,
                                 const EC_JACOBIAN *points,
                                 const EC_SCALAR *scalars, size_t num);

// method functions in simple.c
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);
void ec_GFp_simple_point_init(EC_JACOBIAN *);
void ec_GFp_simple_point_copy(EC_JACOBIAN *, const EC_JACOBIAN *);
void ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_JACOBIAN *);
void ec_GFp_mont_add(const EC_GROUP *, EC_JACOBIAN *r, const EC_JACOBIAN *a,
                     const EC_JACOBIAN *b);
void ec_GFp_mont_dbl(const EC_GROUP *, EC_JACOBIAN *r, const EC_JACOBIAN *a);
void ec_GFp_simple_invert(const EC_GROUP *, EC_JACOBIAN *);
int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_JACOBIAN *);
int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_JACOBIAN *);
int ec_GFp_simple_points_equal(const EC_GROUP *, const EC_JACOBIAN *a,
                               const EC_JACOBIAN *b);
void ec_simple_scalar_inv0_montgomery(const EC_GROUP *group, EC_SCALAR *r,
                                      const EC_SCALAR *a);

int ec_simple_scalar_to_montgomery_inv_vartime(const EC_GROUP *group,
                                               EC_SCALAR *r,
                                               const EC_SCALAR *a);

int ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group, const EC_JACOBIAN *p,
                                   const EC_SCALAR *r);

void ec_GFp_nistp_recode_scalar_bits(crypto_word_t *sign, crypto_word_t *digit,
                                     crypto_word_t in);

const EC_METHOD *EC_GFp_nistp256_method();

// EC_GFp_nistz256_method is a GFp method using montgomery multiplication, with
// x86-64 optimized P256. See http://eprint.iacr.org/2013/816.
const EC_METHOD *EC_GFp_nistz256_method();

// An EC_WRAPPED_SCALAR is an `EC_SCALAR` with a parallel `BIGNUM`
// representation. It exists to support the `EC_KEY_get0_private_key` API.
typedef struct {
  BIGNUM bignum;
  EC_SCALAR scalar;
} EC_WRAPPED_SCALAR;

class ECKey : public ec_key_st, public RefCounted<ECKey> {
 public:
  explicit ECKey(const ENGINE *engine);

  EC_GROUP *group = nullptr;

  // Ideally `pub_key` would be an `EC_AFFINE` so serializing it does not pay an
  // inversion each time, but the `EC_KEY_get0_public_key` API implies public
  // keys are stored in an `EC_POINT`-compatible form.
  EC_POINT *pub_key = nullptr;
  bssl::EC_WRAPPED_SCALAR *priv_key = nullptr;

  unsigned int enc_flag = 0;
  point_conversion_form_t conv_form = POINT_CONVERSION_UNCOMPRESSED;

  ECDSA_METHOD *ecdsa_meth = nullptr;

  CRYPTO_EX_DATA ex_data = {};

 private:
  ~ECKey();
  friend RefCounted;
} /* EC_KEY */;

BSSL_NAMESPACE_END


#endif  // OPENSSL_HEADER_CRYPTO_FIPSMODULE_EC_INTERNAL_H
