Simplify and fix ec_GFp_simple_points_make_affine
(which didn't always handle value 0 correctly). Reviewed-by: emilia@openssl.org Conflicts: CHANGES crypto/ec/ectest.c
This commit is contained in:
		
							
								
								
									
										5
									
								
								CHANGES
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								CHANGES
									
									
									
									
									
								
							@@ -4,7 +4,10 @@
 | 
			
		||||
 | 
			
		||||
 Changes between 1.0.0m and 1.0.0n [xx XXX xxxx]
 | 
			
		||||
 | 
			
		||||
  *)
 | 
			
		||||
  *) Fix ec_GFp_simple_points_make_affine (thus, EC_POINTs_mul etc.)
 | 
			
		||||
     for corner cases. (Certain input points at infinity could lead to
 | 
			
		||||
     bogus results, with non-infinity inputs mapped to infinity too.)
 | 
			
		||||
     [Bodo Moeller]
 | 
			
		||||
 | 
			
		||||
 Changes between 1.0.0l and 1.0.0m [5 Jun 2014]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1540,9 +1540,8 @@ int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ct
 | 
			
		||||
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;
 | 
			
		||||
	BIGNUM *tmp, *tmp_Z;
 | 
			
		||||
	BIGNUM **prod_Z = NULL;
 | 
			
		||||
	size_t i;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
@@ -1557,124 +1556,104 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	BN_CTX_start(ctx);
 | 
			
		||||
	tmp0 = BN_CTX_get(ctx);
 | 
			
		||||
	tmp1 = BN_CTX_get(ctx);
 | 
			
		||||
	if (tmp0  == NULL || tmp1 == NULL) goto err;
 | 
			
		||||
	tmp = BN_CTX_get(ctx);
 | 
			
		||||
	tmp_Z = BN_CTX_get(ctx);
 | 
			
		||||
	if (tmp == NULL || tmp_Z == 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 = OPENSSL_malloc(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;
 | 
			
		||||
	prod_Z = OPENSSL_malloc(num * sizeof prod_Z[0]);
 | 
			
		||||
	if (prod_Z == NULL) goto err;
 | 
			
		||||
	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;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		prod_Z[i] = BN_new();
 | 
			
		||||
		if (prod_Z[i] == NULL) goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	/* invert heap[1] */
 | 
			
		||||
	if (!BN_is_zero(heap[1]))
 | 
			
		||||
		{
 | 
			
		||||
		if (!BN_mod_inverse(heap[1], heap[1], &group->field, ctx))
 | 
			
		||||
			{
 | 
			
		||||
			ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, 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 each prod_Z[i] to the product of points[0]->Z .. points[i]->Z,
 | 
			
		||||
	 * skipping any zero-valued inputs (pretend that they're 1). */
 | 
			
		||||
 | 
			
		||||
	/* set other heap[i]'s to their inverses */
 | 
			
		||||
	for (i = 2; i < pow2/2 + num; i += 2)
 | 
			
		||||
	if (!BN_is_zero(&points[0]->Z))
 | 
			
		||||
		{
 | 
			
		||||
		/* i is even */
 | 
			
		||||
		if ((heap[i + 1] != NULL) && !BN_is_zero(heap[i + 1]))
 | 
			
		||||
		if (!BN_copy(prod_Z[0], &points[0]->Z)) goto err;
 | 
			
		||||
		}
 | 
			
		||||
	else
 | 
			
		||||
		{
 | 
			
		||||
		if (group->meth->field_set_to_one != 0)
 | 
			
		||||
			{
 | 
			
		||||
			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;
 | 
			
		||||
			if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) goto err;
 | 
			
		||||
			}
 | 
			
		||||
		else
 | 
			
		||||
			{
 | 
			
		||||
			if (!BN_copy(heap[i], heap[i/2])) goto err;
 | 
			
		||||
			if (!BN_one(prod_Z[0])) goto err;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	/* we have replaced all non-zero Z's by their inverses, now fix up all the points */
 | 
			
		||||
	for (i = 1; i < num; i++)
 | 
			
		||||
		{
 | 
			
		||||
		if (!BN_is_zero(&points[i]->Z))
 | 
			
		||||
			{
 | 
			
		||||
			if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1], &points[i]->Z, ctx)) goto err;
 | 
			
		||||
			}
 | 
			
		||||
		else
 | 
			
		||||
			{
 | 
			
		||||
			if (!BN_copy(prod_Z[i], prod_Z[i - 1])) goto err;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	/* Now use a single explicit inversion to replace every
 | 
			
		||||
	 * non-zero points[i]->Z by its inverse. */
 | 
			
		||||
 | 
			
		||||
	if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx))
 | 
			
		||||
		{
 | 
			
		||||
		ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, 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 need to multiply by the Montgomery factor twice. */
 | 
			
		||||
		if (!group->meth->field_encode(group, tmp, tmp, ctx)) goto err;
 | 
			
		||||
		if (!group->meth->field_encode(group, tmp, tmp, ctx)) goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	for (i = num - 1; i > 0; --i)
 | 
			
		||||
		{
 | 
			
		||||
		/* Loop invariant: tmp is the product of the inverses of
 | 
			
		||||
		 * points[0]->Z .. points[i]->Z (zero-valued inputs skipped). */
 | 
			
		||||
		if (!BN_is_zero(&points[i]->Z))
 | 
			
		||||
			{
 | 
			
		||||
			/* Set tmp_Z to the inverse of points[i]->Z (as product
 | 
			
		||||
			 * of Z inverses 0 .. i, Z values 0 .. i - 1). */
 | 
			
		||||
			if (!group->meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx)) goto err;
 | 
			
		||||
			/* Update tmp to satisfy the loop invariant for i - 1. */
 | 
			
		||||
			if (!group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx)) goto err;
 | 
			
		||||
			/* Replace points[i]->Z by its inverse. */
 | 
			
		||||
			if (!BN_copy(&points[i]->Z, tmp_Z)) goto err;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	if (!BN_is_zero(&points[0]->Z))
 | 
			
		||||
		{
 | 
			
		||||
		/* Replace points[0]->Z by its inverse. */
 | 
			
		||||
		if (!BN_copy(&points[0]->Z, tmp)) goto err;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	/* Finally, fix up the X and Y coordinates for all 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_sqr(group, tmp, &p->Z, ctx)) goto err;
 | 
			
		||||
			if (!group->meth->field_mul(group, &p->X, &p->X, tmp, ctx)) goto err;
 | 
			
		||||
 | 
			
		||||
			if (!group->meth->field_mul(group, tmp, tmp, &p->Z, ctx)) goto err;
 | 
			
		||||
			if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp, 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;
 | 
			
		||||
@@ -1688,20 +1667,19 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	ret = 1;
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
 err:
 | 
			
		||||
	BN_CTX_end(ctx);
 | 
			
		||||
	if (new_ctx != NULL)
 | 
			
		||||
		BN_CTX_free(new_ctx);
 | 
			
		||||
	if (heap != NULL)
 | 
			
		||||
	if (prod_Z != NULL)
 | 
			
		||||
		{
 | 
			
		||||
		/* heap[pow2/2] .. heap[pow2-1] have not been allocated locally! */
 | 
			
		||||
		for (i = pow2/2 - 1; i > 0; i--)
 | 
			
		||||
		for (i = 0; i < num; i++)
 | 
			
		||||
			{
 | 
			
		||||
			if (heap[i] != NULL)
 | 
			
		||||
				BN_clear_free(heap[i]);
 | 
			
		||||
			if (prod_Z[i] != NULL)
 | 
			
		||||
				BN_clear_free(prod_Z[i]);
 | 
			
		||||
			}
 | 
			
		||||
		OPENSSL_free(heap);
 | 
			
		||||
		OPENSSL_free(prod_Z);
 | 
			
		||||
		}
 | 
			
		||||
	return ret;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user