Contract P-224 elements before returning them.

cfd50c63 switched to using the add/dbl of p224_64.c, but the outputs
weren't contracted before being returned and could be out of range,
giving invalid results.

Change-Id: I3cc295c7ddbff43375770dbafe73b37a668e4e6b
Reviewed-on: https://boringssl-review.googlesource.com/c/33184
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/ec/ec_test.cc b/crypto/fipsmodule/ec/ec_test.cc
index 87146ad..97c6d45 100644
--- a/crypto/fipsmodule/ec/ec_test.cc
+++ b/crypto/fipsmodule/ec/ec_test.cc
@@ -754,6 +754,17 @@
   EXPECT_EQ(0, EC_POINT_cmp(group(), ret.get(), g, nullptr));
 }
 
+TEST_P(ECCurveTest, GPlusMinusG) {
+  const EC_POINT *g = EC_GROUP_get0_generator(group());
+  bssl::UniquePtr<EC_POINT> p(EC_POINT_dup(g, group()));
+  ASSERT_TRUE(p);
+  ASSERT_TRUE(EC_POINT_invert(group(), p.get(), nullptr));
+  bssl::UniquePtr<EC_POINT> sum(EC_POINT_new(group()));
+
+  ASSERT_TRUE(EC_POINT_add(group(), sum.get(), g, p.get(), nullptr));
+  EXPECT_TRUE(EC_POINT_is_at_infinity(group(), sum.get()));
+}
+
 static std::vector<EC_builtin_curve> AllCurves() {
   const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
   std::vector<EC_builtin_curve> curves(num_curves);
diff --git a/crypto/fipsmodule/ec/p224-64.c b/crypto/fipsmodule/ec/p224-64.c
index 49d5328..96f7bb7 100644
--- a/crypto/fipsmodule/ec/p224-64.c
+++ b/crypto/fipsmodule/ec/p224-64.c
@@ -1011,8 +1011,12 @@
   p224_generic_to_felem(y2, &b->Y);
   p224_generic_to_felem(z2, &b->Z);
   p224_point_add(x1, y1, z1, x1, y1, z1, 0 /* both Jacobian */, x2, y2, z2);
+  // The outputs are already reduced, but still need to be contracted.
+  p224_felem_contract(x1, x1);
   p224_felem_to_generic(&r->X, x1);
+  p224_felem_contract(y1, y1);
   p224_felem_to_generic(&r->Y, y1);
+  p224_felem_contract(z1, z1);
   p224_felem_to_generic(&r->Z, z1);
 }
 
@@ -1023,8 +1027,12 @@
   p224_generic_to_felem(y, &a->Y);
   p224_generic_to_felem(z, &a->Z);
   p224_point_double(x, y, z, x, y, z);
+  // The outputs are already reduced, but still need to be contracted.
+  p224_felem_contract(x, x);
   p224_felem_to_generic(&r->X, x);
+  p224_felem_contract(y, y);
   p224_felem_to_generic(&r->Y, y);
+  p224_felem_contract(z, z);
   p224_felem_to_generic(&r->Z, z);
 }