Clear mallocs in ec_wNAF_mul.

EC_POINT is split into the existing public EC_POINT (where the caller is
sanity-checked about group mismatches) and the low-level EC_RAW_POINT
(which, like EC_FELEM and EC_SCALAR, assume that is your problem and is
a plain old struct). Having both EC_POINT and EC_RAW_POINT is a little
silly, but we're going to want different type signatures for functions
which return void anyway (my plan is to lift a non-BIGNUM
get_affine_coordinates up through the ECDSA and ECDH code), so I think
it's fine.

This wasn't strictly necessary, but wnaf.c is a lot tidier now. Perf is
a wash; once we get up to this layer, it's only 8 entries in the table
so not particularly interesting.

Bug: 239
Change-Id: I8ace749393d359f42649a5bb0734597bb7c07a2e
Reviewed-on: https://boringssl-review.googlesource.com/27706
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/ec/ec.c b/crypto/fipsmodule/ec/ec.c
index 7b5031f..a937e27 100644
--- a/crypto/fipsmodule/ec/ec.c
+++ b/crypto/fipsmodule/ec/ec.c
@@ -586,7 +586,7 @@
          BN_cmp(&a->field, &b->field) != 0 ||
          !ec_felem_equal(a, &a->a, &b->a) ||
          !ec_felem_equal(a, &a->b, &b->b) ||
-         ec_GFp_simple_cmp(a, a->generator, b->generator) != 0;
+         ec_GFp_simple_cmp(a, &a->generator->raw, &b->generator->raw) != 0;
 }
 
 const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) {
@@ -635,7 +635,7 @@
   }
 
   ret->group = EC_GROUP_dup(group);
-  ec_GFp_simple_point_init(ret);
+  ec_GFp_simple_point_init(&ret->raw);
   return ret;
 }
 
@@ -663,7 +663,7 @@
   if (dest == src) {
     return 1;
   }
-  ec_GFp_simple_point_copy(dest, src);
+  ec_GFp_simple_point_copy(&dest->raw, &src->raw);
   return 1;
 }
 
@@ -687,7 +687,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  ec_GFp_simple_point_set_to_infinity(group, point);
+  ec_GFp_simple_point_set_to_infinity(group, &point->raw);
   return 1;
 }
 
@@ -696,7 +696,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  return ec_GFp_simple_is_at_infinity(group, point);
+  return ec_GFp_simple_is_at_infinity(group, &point->raw);
 }
 
 int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
@@ -705,7 +705,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  return ec_GFp_simple_is_on_curve(group, point);
+  return ec_GFp_simple_is_on_curve(group, &point->raw);
 }
 
 int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
@@ -715,7 +715,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return -1;
   }
-  return ec_GFp_simple_cmp(group, a, b);
+  return ec_GFp_simple_cmp(group, &a->raw, &b->raw);
 }
 
 int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
@@ -729,7 +729,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  return group->meth->point_get_affine_coordinates(group, point, x, y);
+  return group->meth->point_get_affine_coordinates(group, &point->raw, x, y);
 }
 
 int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
@@ -739,7 +739,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  if (!ec_GFp_simple_point_set_affine_coordinates(group, point, x, y)) {
+  if (!ec_GFp_simple_point_set_affine_coordinates(group, &point->raw, x, y)) {
     return 0;
   }
 
@@ -751,7 +751,7 @@
     // constructing an arbitrary group. In this, we give up and hope they're
     // checking the return value.
     if (generator) {
-      EC_POINT_copy(point, generator);
+      ec_GFp_simple_point_copy(&point->raw, &generator->raw);
     }
     OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE);
     return 0;
@@ -768,7 +768,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  ec_GFp_simple_add(group, r, a, b);
+  ec_GFp_simple_add(group, &r->raw, &a->raw, &b->raw);
   return 1;
 }
 
@@ -779,7 +779,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  ec_GFp_simple_dbl(group, r, a);
+  ec_GFp_simple_dbl(group, &r->raw, &a->raw);
   return 1;
 }
 
@@ -789,7 +789,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  ec_GFp_simple_invert(group, a);
+  ec_GFp_simple_invert(group, &a->raw);
   return 1;
 }
 
@@ -873,7 +873,8 @@
     return 0;
   }
 
-  return group->meth->mul_public(group, r, g_scalar, p, p_scalar, ctx);
+  group->meth->mul_public(group, &r->raw, g_scalar, &p->raw, p_scalar);
+  return 1;
 }
 
 int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r,
@@ -891,7 +892,9 @@
     return 0;
   }
 
-  return group->meth->mul(group, r, g_scalar, p, p_scalar, ctx);
+  group->meth->mul(group, &r->raw, g_scalar, (p == NULL) ? NULL : &p->raw,
+                   p_scalar);
+  return 1;
 }
 
 void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) {}
diff --git a/crypto/fipsmodule/ec/ec_montgomery.c b/crypto/fipsmodule/ec/ec_montgomery.c
index c90b9f1..eb37e50 100644
--- a/crypto/fipsmodule/ec/ec_montgomery.c
+++ b/crypto/fipsmodule/ec/ec_montgomery.c
@@ -181,9 +181,9 @@
 }
 
 static int ec_GFp_mont_point_get_affine_coordinates(const EC_GROUP *group,
-                                                    const EC_POINT *point,
+                                                    const EC_RAW_POINT *point,
                                                     BIGNUM *x, BIGNUM *y) {
-  if (EC_POINT_is_at_infinity(group, point)) {
+  if (ec_GFp_simple_is_at_infinity(group, point)) {
     OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
     return 0;
   }
diff --git a/crypto/fipsmodule/ec/internal.h b/crypto/fipsmodule/ec/internal.h
index a70c869..aba7d1d 100644
--- a/crypto/fipsmodule/ec/internal.h
+++ b/crypto/fipsmodule/ec/internal.h
@@ -110,12 +110,21 @@
   BN_ULONG words[EC_MAX_SCALAR_WORDS];
 } EC_FELEM;
 
+// An EC_RAW_POINT represents an elliptic curve point. 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 {
+  EC_FELEM X, Y, Z;
+  // 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_RAW_POINT;
+
 struct ec_method_st {
   int (*group_init)(EC_GROUP *);
   void (*group_finish)(EC_GROUP *);
   int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
                          const BIGNUM *b, BN_CTX *);
-  int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *,
+  int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_RAW_POINT *,
                                       BIGNUM *x, BIGNUM *y);
 
   // Computes |r = g_scalar*generator + p_scalar*p| if |g_scalar| and |p_scalar|
@@ -123,14 +132,14 @@
   // Computes |r = p_scalar*p| if g_scalar is null. At least one of |g_scalar|
   // and |p_scalar| must be non-null, and |p| must be non-null if |p_scalar| is
   // non-null.
-  int (*mul)(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
-             const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
+  void (*mul)(const EC_GROUP *group, EC_RAW_POINT *r, const EC_SCALAR *g_scalar,
+              const EC_RAW_POINT *p, const EC_SCALAR *p_scalar);
   // mul_public performs the same computation as mul. It further assumes that
   // the inputs are public so there is no concern about leaking their values
   // through timing.
-  int (*mul_public)(const EC_GROUP *group, EC_POINT *r,
-                    const EC_SCALAR *g_scalar, const EC_POINT *p,
-                    const EC_SCALAR *p_scalar, BN_CTX *ctx);
+  void (*mul_public)(const EC_GROUP *group, EC_RAW_POINT *r,
+                     const EC_SCALAR *g_scalar, const EC_RAW_POINT *p,
+                     const EC_SCALAR *p_scalar);
 
   // felem_mul and felem_sqr implement multiplication and squaring,
   // respectively, so that the generic |EC_POINT_add| and |EC_POINT_dbl|
@@ -194,10 +203,7 @@
   // group is an owning reference to |group|, unless this is
   // |group->generator|.
   EC_GROUP *group;
-
-  // X, Y, and Z are Jacobian projective coordinates. They represent
-  // (X/Z^2, Y/Z^3) if Z != 0 and the point and infinite otherwise.
-  EC_FELEM X, Y, Z;
+  EC_RAW_POINT raw;
 } /* EC_POINT */;
 
 EC_GROUP *ec_group_new(const EC_METHOD *meth);
@@ -292,8 +298,9 @@
 void ec_compute_wNAF(const EC_GROUP *group, int8_t *out,
                      const EC_SCALAR *scalar, size_t bits, int w);
 
-int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
-                const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
+void ec_wNAF_mul(const EC_GROUP *group, EC_RAW_POINT *r,
+                 const EC_SCALAR *g_scalar, const EC_RAW_POINT *p,
+                 const EC_SCALAR *p_scalar);
 
 // method functions in simple.c
 int ec_GFp_simple_group_init(EC_GROUP *);
@@ -303,18 +310,21 @@
 int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
                                   BIGNUM *b);
 unsigned ec_GFp_simple_group_get_degree(const EC_GROUP *);
-void ec_GFp_simple_point_init(EC_POINT *);
-void ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *);
-void ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
-int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
-                                               const BIGNUM *x, const BIGNUM *y);
-void ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
-                       const EC_POINT *b);
-void ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a);
-void ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *);
-int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *);
-int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_POINT *);
-int ec_GFp_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b);
+void ec_GFp_simple_point_init(EC_RAW_POINT *);
+void ec_GFp_simple_point_copy(EC_RAW_POINT *, const EC_RAW_POINT *);
+void ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_RAW_POINT *);
+int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_RAW_POINT *,
+                                               const BIGNUM *x,
+                                               const BIGNUM *y);
+void ec_GFp_simple_add(const EC_GROUP *, EC_RAW_POINT *r, const EC_RAW_POINT *a,
+                       const EC_RAW_POINT *b);
+void ec_GFp_simple_dbl(const EC_GROUP *, EC_RAW_POINT *r,
+                       const EC_RAW_POINT *a);
+void ec_GFp_simple_invert(const EC_GROUP *, EC_RAW_POINT *);
+int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_RAW_POINT *);
+int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_RAW_POINT *);
+int ec_GFp_simple_cmp(const EC_GROUP *, const EC_RAW_POINT *a,
+                      const EC_RAW_POINT *b);
 void ec_simple_scalar_inv_montgomery(const EC_GROUP *group, EC_SCALAR *r,
                                      const EC_SCALAR *a);
 
diff --git a/crypto/fipsmodule/ec/p224-64.c b/crypto/fipsmodule/ec/p224-64.c
index 96ca041..606108f 100644
--- a/crypto/fipsmodule/ec/p224-64.c
+++ b/crypto/fipsmodule/ec/p224-64.c
@@ -970,10 +970,9 @@
 
 // Takes the Jacobian coordinates (X, Y, Z) of a point and returns
 // (X', Y') = (X/Z^2, Y/Z^3)
-static int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
-                                                        const EC_POINT *point,
-                                                        BIGNUM *x, BIGNUM *y) {
-  if (EC_POINT_is_at_infinity(group, point)) {
+static int ec_GFp_nistp224_point_get_affine_coordinates(
+    const EC_GROUP *group, const EC_RAW_POINT *point, BIGNUM *x, BIGNUM *y) {
+  if (ec_GFp_simple_is_at_infinity(group, point)) {
     OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
     return 0;
   }
@@ -1014,10 +1013,10 @@
   return 1;
 }
 
-static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
-                                      const EC_SCALAR *g_scalar,
-                                      const EC_POINT *p,
-                                      const EC_SCALAR *p_scalar, BN_CTX *ctx) {
+static void ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_RAW_POINT *r,
+                                       const EC_SCALAR *g_scalar,
+                                       const EC_RAW_POINT *p,
+                                       const EC_SCALAR *p_scalar) {
   p224_felem p_pre_comp[17][3];
   p224_felem x_in, y_in, z_in, x_out, y_out, z_out;
 
@@ -1060,7 +1059,6 @@
   p224_felem_to_generic(&r->Y, y_in);
   p224_felem_contract(z_in, z_out);
   p224_felem_to_generic(&r->Z, z_in);
-  return 1;
 }
 
 static void ec_GFp_nistp224_felem_mul(const EC_GROUP *group, EC_FELEM *r,
diff --git a/crypto/fipsmodule/ec/p256-x86_64.c b/crypto/fipsmodule/ec/p256-x86_64.c
index ea9749f..a4f6515 100644
--- a/crypto/fipsmodule/ec/p256-x86_64.c
+++ b/crypto/fipsmodule/ec/p256-x86_64.c
@@ -199,7 +199,7 @@
 
 // r = p * p_scalar
 static void ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
-                                      const EC_POINT *p,
+                                      const EC_RAW_POINT *p,
                                       const EC_SCALAR *p_scalar) {
   assert(p != NULL);
   assert(p_scalar != NULL);
@@ -289,10 +289,10 @@
   ecp_nistz256_point_add(r, r, &h);
 }
 
-static int ecp_nistz256_points_mul(const EC_GROUP *group, EC_POINT *r,
-                                   const EC_SCALAR *g_scalar,
-                                   const EC_POINT *p_,
-                                   const EC_SCALAR *p_scalar, BN_CTX *ctx) {
+static void ecp_nistz256_points_mul(const EC_GROUP *group, EC_RAW_POINT *r,
+                                    const EC_SCALAR *g_scalar,
+                                    const EC_RAW_POINT *p_,
+                                    const EC_SCALAR *p_scalar) {
   assert((p_ != NULL) == (p_scalar != NULL));
 
   static const unsigned kWindowSize = 7;
@@ -361,12 +361,12 @@
   OPENSSL_memcpy(r->X.words, p.p.X, P256_LIMBS * sizeof(BN_ULONG));
   OPENSSL_memcpy(r->Y.words, p.p.Y, P256_LIMBS * sizeof(BN_ULONG));
   OPENSSL_memcpy(r->Z.words, p.p.Z, P256_LIMBS * sizeof(BN_ULONG));
-  return 1;
 }
 
-static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
-                                   BIGNUM *x, BIGNUM *y) {
-  if (EC_POINT_is_at_infinity(group, point)) {
+static int ecp_nistz256_get_affine(const EC_GROUP *group,
+                                   const EC_RAW_POINT *point, BIGNUM *x,
+                                   BIGNUM *y) {
+  if (ec_GFp_simple_is_at_infinity(group, point)) {
     OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
     return 0;
   }
diff --git a/crypto/fipsmodule/ec/simple.c b/crypto/fipsmodule/ec/simple.c
index 995b421..8bbb5a9 100644
--- a/crypto/fipsmodule/ec/simple.c
+++ b/crypto/fipsmodule/ec/simple.c
@@ -175,25 +175,28 @@
   return BN_num_bits(&group->field);
 }
 
-void ec_GFp_simple_point_init(EC_POINT *point) {
+void ec_GFp_simple_point_init(EC_RAW_POINT *point) {
   OPENSSL_memset(&point->X, 0, sizeof(EC_FELEM));
   OPENSSL_memset(&point->Y, 0, sizeof(EC_FELEM));
   OPENSSL_memset(&point->Z, 0, sizeof(EC_FELEM));
 }
 
-void ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) {
+void ec_GFp_simple_point_copy(EC_RAW_POINT *dest, const EC_RAW_POINT *src) {
   OPENSSL_memcpy(&dest->X, &src->X, sizeof(EC_FELEM));
   OPENSSL_memcpy(&dest->Y, &src->Y, sizeof(EC_FELEM));
   OPENSSL_memcpy(&dest->Z, &src->Z, sizeof(EC_FELEM));
 }
 
 void ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
-                                         EC_POINT *point) {
-  OPENSSL_memset(&point->Z, 0, sizeof(EC_FELEM));
+                                         EC_RAW_POINT *point) {
+  // Although it is strictly only necessary to zero Z, we zero the entire point
+  // in case |point| was stack-allocated and yet to be initialized.
+  ec_GFp_simple_point_init(point);
 }
 
 int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
-                                               EC_POINT *point, const BIGNUM *x,
+                                               EC_RAW_POINT *point,
+                                               const BIGNUM *x,
                                                const BIGNUM *y) {
   if (x == NULL || y == NULL) {
     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
@@ -209,8 +212,8 @@
   return 1;
 }
 
-void ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *out, const EC_POINT *a,
-                       const EC_POINT *b) {
+void ec_GFp_simple_add(const EC_GROUP *group, EC_RAW_POINT *out,
+                       const EC_RAW_POINT *a, const EC_RAW_POINT *b) {
   if (a == b) {
     ec_GFp_simple_dbl(group, out, a);
     return;
@@ -327,7 +330,8 @@
   ec_felem_select(group, &out->Z, z2nz, &z_out, &a->Z);
 }
 
-void ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a) {
+void ec_GFp_simple_dbl(const EC_GROUP *group, EC_RAW_POINT *r,
+                       const EC_RAW_POINT *a) {
   void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
                           const EC_FELEM *b) = group->meth->felem_mul;
   void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
@@ -426,16 +430,18 @@
   }
 }
 
-void ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point) {
+void ec_GFp_simple_invert(const EC_GROUP *group, EC_RAW_POINT *point) {
   ec_felem_neg(group, &point->Y, &point->Y);
 }
 
-int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
+int ec_GFp_simple_is_at_infinity(const EC_GROUP *group,
+                                 const EC_RAW_POINT *point) {
   return ec_felem_non_zero_mask(group, &point->Z) == 0;
 }
 
-int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point) {
-  if (EC_POINT_is_at_infinity(group, point)) {
+int ec_GFp_simple_is_on_curve(const EC_GROUP *group,
+                              const EC_RAW_POINT *point) {
+  if (ec_GFp_simple_is_at_infinity(group, point)) {
     return 1;
   }
 
@@ -491,8 +497,8 @@
   return ec_felem_equal(group, &tmp, &rh);
 }
 
-int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
-                      const EC_POINT *b) {
+int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_RAW_POINT *a,
+                      const EC_RAW_POINT *b) {
   // Note this function returns zero if |a| and |b| are equal and 1 if they are
   // not equal.
   if (ec_GFp_simple_is_at_infinity(group, a)) {
diff --git a/crypto/fipsmodule/ec/wnaf.c b/crypto/fipsmodule/ec/wnaf.c
index e6f0cf9..ca346ce 100644
--- a/crypto/fipsmodule/ec/wnaf.c
+++ b/crypto/fipsmodule/ec/wnaf.c
@@ -74,7 +74,6 @@
 #include <openssl/err.h>
 #include <openssl/mem.h>
 #include <openssl/thread.h>
-#include <openssl/type_check.h>
 
 #include "internal.h"
 #include "../bn/internal.h"
@@ -171,163 +170,92 @@
 // |window_bits_for_scalar_size|.
 #define EC_WNAF_MAX_WINDOW_BITS 4
 
-// compute_precomp sets |out[i]| to a newly-allocated |EC_POINT| containing
-// (2*i+1)*p, for i from 0 to |len|. It returns one on success and
-// zero on error.
-static int compute_precomp(const EC_GROUP *group, EC_POINT **out,
-                           const EC_POINT *p, size_t len, BN_CTX *ctx) {
-  out[0] = EC_POINT_new(group);
-  if (out[0] == NULL ||
-      !EC_POINT_copy(out[0], p)) {
-    return 0;
-  }
-
-  int ret = 0;
-  EC_POINT *two_p = EC_POINT_new(group);
-  if (two_p == NULL ||
-      !EC_POINT_dbl(group, two_p, p, ctx)) {
-    goto err;
-  }
-
+// compute_precomp sets |out[i]| to (2*i+1)*p, for i from 0 to |len|.
+static void compute_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
+                            const EC_RAW_POINT *p, size_t len) {
+  ec_GFp_simple_point_copy(&out[0], p);
+  EC_RAW_POINT two_p;
+  ec_GFp_simple_dbl(group, &two_p, p);
   for (size_t i = 1; i < len; i++) {
-    out[i] = EC_POINT_new(group);
-    if (out[i] == NULL ||
-        !EC_POINT_add(group, out[i], out[i - 1], two_p, ctx)) {
-      goto err;
-    }
+    ec_GFp_simple_add(group, &out[i], &out[i - 1], &two_p);
   }
-
-  ret = 1;
-
-err:
-  EC_POINT_free(two_p);
-  return ret;
 }
 
-static int lookup_precomp(const EC_GROUP *group, EC_POINT *out,
-                          EC_POINT *const *precomp, int digit, BN_CTX *ctx) {
+static void lookup_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
+                           const EC_RAW_POINT *precomp, int digit) {
   if (digit < 0) {
     digit = -digit;
-    return EC_POINT_copy(out, precomp[digit >> 1]) &&
-           EC_POINT_invert(group, out, ctx);
+    ec_GFp_simple_point_copy(out, &precomp[digit >> 1]);
+    ec_GFp_simple_invert(group, out);
+  } else {
+    ec_GFp_simple_point_copy(out, &precomp[digit >> 1]);
   }
-
-  return EC_POINT_copy(out, precomp[digit >> 1]);
 }
 
-int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
-                const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx) {
-  BN_CTX *new_ctx = NULL;
-  EC_POINT *precomp_storage[2 * (1 << (EC_WNAF_MAX_WINDOW_BITS - 1))] = {NULL};
-  EC_POINT **g_precomp = NULL, **p_precomp = NULL;
-  int8_t g_wNAF[EC_MAX_SCALAR_BYTES * 8 + 1];
-  int8_t p_wNAF[EC_MAX_SCALAR_BYTES * 8 + 1];
-  EC_POINT *tmp = NULL;
-  int ret = 0;
-
-  if (ctx == NULL) {
-    ctx = new_ctx = BN_CTX_new();
-    if (ctx == NULL) {
-      goto err;
-    }
-  }
-
+void ec_wNAF_mul(const EC_GROUP *group, EC_RAW_POINT *r,
+                 const EC_SCALAR *g_scalar, const EC_RAW_POINT *p,
+                 const EC_SCALAR *p_scalar) {
   size_t bits = BN_num_bits(&group->order);
   size_t wsize = window_bits_for_scalar_size(bits);
   size_t wNAF_len = bits + 1;
   size_t precomp_len = (size_t)1 << (wsize - 1);
 
-  OPENSSL_COMPILE_ASSERT(
-      OPENSSL_ARRAY_SIZE(g_wNAF) == OPENSSL_ARRAY_SIZE(p_wNAF),
-      g_wNAF_and_p_wNAF_are_different_sizes);
-
-  if (wNAF_len > OPENSSL_ARRAY_SIZE(g_wNAF) ||
-      2 * precomp_len > OPENSSL_ARRAY_SIZE(precomp_storage)) {
-    OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
-    goto err;
-  }
+  assert(wsize <= EC_WNAF_MAX_WINDOW_BITS);
 
   // TODO(davidben): |mul_public| is for ECDSA verification which can assume
   // non-NULL inputs, but this code is also used for |mul| which cannot. It's
   // not constant-time, so replace the generic |mul| and remove the NULL checks.
-  size_t total_precomp = 0;
+  int8_t g_wNAF[EC_MAX_SCALAR_BYTES * 8 + 1];
+  EC_RAW_POINT g_precomp[1 << (EC_WNAF_MAX_WINDOW_BITS - 1)];
+  assert(precomp_len <= OPENSSL_ARRAY_SIZE(g_precomp));
+  assert(wNAF_len <= OPENSSL_ARRAY_SIZE(g_wNAF));
   if (g_scalar != NULL) {
-    const EC_POINT *g = EC_GROUP_get0_generator(group);
-    if (g == NULL) {
-      OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR);
-      goto err;
-    }
-    g_precomp = precomp_storage + total_precomp;
-    total_precomp += precomp_len;
+    const EC_RAW_POINT *g = &group->generator->raw;
     ec_compute_wNAF(group, g_wNAF, g_scalar, bits, wsize);
-    if (!compute_precomp(group, g_precomp, g, precomp_len, ctx)) {
-      goto err;
-    }
+    compute_precomp(group, g_precomp, g, precomp_len);
   }
 
+  int8_t p_wNAF[EC_MAX_SCALAR_BYTES * 8 + 1];
+  EC_RAW_POINT p_precomp[1 << (EC_WNAF_MAX_WINDOW_BITS - 1)];
+  assert(precomp_len <= OPENSSL_ARRAY_SIZE(p_precomp));
+  assert(wNAF_len <= OPENSSL_ARRAY_SIZE(p_wNAF));
   if (p_scalar != NULL) {
-    p_precomp = precomp_storage + total_precomp;
-    total_precomp += precomp_len;
     ec_compute_wNAF(group, p_wNAF, p_scalar, bits, wsize);
-    if (!compute_precomp(group, p_precomp, p, precomp_len, ctx)) {
-      goto err;
-    }
+    compute_precomp(group, p_precomp, p, precomp_len);
   }
 
-  tmp = EC_POINT_new(group);
-  if (tmp == NULL) {
-    goto err;
-  }
-
+  EC_RAW_POINT tmp;
   int r_is_at_infinity = 1;
   for (size_t k = wNAF_len - 1; k < wNAF_len; k--) {
-    if (!r_is_at_infinity && !EC_POINT_dbl(group, r, r, ctx)) {
-      goto err;
+    if (!r_is_at_infinity) {
+      ec_GFp_simple_dbl(group, r, r);
     }
 
     if (g_scalar != NULL && g_wNAF[k] != 0) {
-      if (!lookup_precomp(group, tmp, g_precomp, g_wNAF[k], ctx)) {
-        goto err;
-      }
+      lookup_precomp(group, &tmp, g_precomp, g_wNAF[k]);
       if (r_is_at_infinity) {
-        if (!EC_POINT_copy(r, tmp)) {
-          goto err;
-        }
+        ec_GFp_simple_point_copy(r, &tmp);
         r_is_at_infinity = 0;
-      } else if (!EC_POINT_add(group, r, r, tmp, ctx)) {
-        goto err;
+      } else {
+        ec_GFp_simple_add(group, r, r, &tmp);
       }
     }
 
     if (p_scalar != NULL && p_wNAF[k] != 0) {
-      if (!lookup_precomp(group, tmp, p_precomp, p_wNAF[k], ctx)) {
-        goto err;
-      }
+      lookup_precomp(group, &tmp, p_precomp, p_wNAF[k]);
       if (r_is_at_infinity) {
-        if (!EC_POINT_copy(r, tmp)) {
-          goto err;
-        }
+        ec_GFp_simple_point_copy(r, &tmp);
         r_is_at_infinity = 0;
-      } else if (!EC_POINT_add(group, r, r, tmp, ctx)) {
-        goto err;
+      } else {
+        ec_GFp_simple_add(group, r, r, &tmp);
       }
     }
   }
 
-  if (r_is_at_infinity &&
-      !EC_POINT_set_to_infinity(group, r)) {
-    goto err;
+  if (r_is_at_infinity) {
+    ec_GFp_simple_point_set_to_infinity(group, r);
   }
 
-  ret = 1;
-
-err:
-  BN_CTX_free(new_ctx);
-  EC_POINT_free(tmp);
   OPENSSL_cleanse(&g_wNAF, sizeof(g_wNAF));
   OPENSSL_cleanse(&p_wNAF, sizeof(p_wNAF));
-  for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(precomp_storage); i++) {
-    EC_POINT_free(precomp_storage[i]);
-  }
-  return ret;
 }
diff --git a/third_party/fiat/p256.c b/third_party/fiat/p256.c
index 5920963..f42f8fe 100644
--- a/third_party/fiat/p256.c
+++ b/third_party/fiat/p256.c
@@ -1630,11 +1630,10 @@
 
 // Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') =
 // (X/Z^2, Y/Z^3).
-static int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
-                                                        const EC_POINT *point,
-                                                        BIGNUM *x_out,
-                                                        BIGNUM *y_out) {
-  if (EC_POINT_is_at_infinity(group, point)) {
+static int ec_GFp_nistp256_point_get_affine_coordinates(
+    const EC_GROUP *group, const EC_RAW_POINT *point, BIGNUM *x_out,
+    BIGNUM *y_out) {
+  if (ec_GFp_simple_is_at_infinity(group, point)) {
     OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
     return 0;
   }
@@ -1673,11 +1672,10 @@
   return 1;
 }
 
-static int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
-                                      const EC_SCALAR *g_scalar,
-                                      const EC_POINT *p,
-                                      const EC_SCALAR *p_scalar,
-                                      BN_CTX *unused_ctx) {
+static void ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_RAW_POINT *r,
+                                       const EC_SCALAR *g_scalar,
+                                       const EC_RAW_POINT *p,
+                                       const EC_SCALAR *p_scalar) {
   fe p_pre_comp[17][3];
   fe x_out, y_out, z_out;
 
@@ -1713,14 +1711,13 @@
   fe_to_generic(&r->X, x_out);
   fe_to_generic(&r->Y, y_out);
   fe_to_generic(&r->Z, z_out);
-  return 1;
 }
 
-static int ec_GFp_nistp256_point_mul_public(const EC_GROUP *group, EC_POINT *r,
-                                            const EC_SCALAR *g_scalar,
-                                            const EC_POINT *p,
-                                            const EC_SCALAR *p_scalar,
-                                            BN_CTX *unused_ctx) {
+static void ec_GFp_nistp256_point_mul_public(const EC_GROUP *group,
+                                             EC_RAW_POINT *r,
+                                             const EC_SCALAR *g_scalar,
+                                             const EC_RAW_POINT *p,
+                                             const EC_SCALAR *p_scalar) {
 #define P256_WSIZE_PUBLIC 4
   // Precompute multiples of |p|. p_pre_comp[i] is (2*i+1) * |p|.
   fe p_pre_comp[1 << (P256_WSIZE_PUBLIC-1)][3];
@@ -1795,7 +1792,6 @@
   fe_to_generic(&r->X, ret[0]);
   fe_to_generic(&r->Y, ret[1]);
   fe_to_generic(&r->Z, ret[2]);
-  return 1;
 }
 
 DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp256_method) {