Пример #1
0
/* Field multiplication using Montgomery reduction. */
mp_err
ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r,
				const GFMethod *meth)
{
	mp_err res = MP_OKAY;

#ifdef MP_MONT_USE_MP_MUL
	/* if MP_MONT_USE_MP_MUL is defined, then the function s_mp_mul_mont
	 * is not implemented and we have to use mp_mul and s_mp_redc directly 
	 */
	MP_CHECKOK(mp_mul(a, b, r));
	MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1));
#else
	mp_int s;

	MP_DIGITS(&s) = 0;
	/* s_mp_mul_mont doesn't allow source and destination to be the same */
	if ((a == r) || (b == r)) {
		MP_CHECKOK(mp_init(&s));
		MP_CHECKOK(s_mp_mul_mont
				   (a, b, &s, (mp_mont_modulus *) meth->extra1));
		MP_CHECKOK(mp_copy(&s, r));
		mp_clear(&s);
	} else {
		return s_mp_mul_mont(a, b, r, (mp_mont_modulus *) meth->extra1);
	}
#endif
  CLEANUP:
	return res;
}
Пример #2
0
/* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in
 * Montgomery projective coordinates. Uses algorithm Madd in appendix of
 * Lopex, J. and Dahab, R.  "Fast multiplication on elliptic curves over
 * GF(2^m) without precomputation". */
static mp_err
gf2m_Madd(const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2, mp_int *z2,
                  const ECGroup *group, int kmflag)
{
        mp_err res = MP_OKAY;
        mp_int t1, t2;

        MP_DIGITS(&t1) = 0;
        MP_DIGITS(&t2) = 0;
        MP_CHECKOK(mp_init(&t1, kmflag));
        MP_CHECKOK(mp_init(&t2, kmflag));

        MP_CHECKOK(mp_copy(x, &t1));
        MP_CHECKOK(group->meth->field_mul(x1, z2, x1, group->meth));
        MP_CHECKOK(group->meth->field_mul(z1, x2, z1, group->meth));
        MP_CHECKOK(group->meth->field_mul(x1, z1, &t2, group->meth));
        MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth));
        MP_CHECKOK(group->meth->field_sqr(z1, z1, group->meth));
        MP_CHECKOK(group->meth->field_mul(z1, &t1, x1, group->meth));
        MP_CHECKOK(group->meth->field_add(x1, &t2, x1, group->meth));

  CLEANUP:
        mp_clear(&t1);
        mp_clear(&t2);
        return res;
}
Пример #3
0
/* Allocate memory for a new ECGroup object. */
ECGroup *
ECGroup_new()
{
    mp_err res = MP_OKAY;
    ECGroup *group;
    group = (ECGroup *) malloc(sizeof(ECGroup));
    if (group == NULL)
        return NULL;
    group->constructed = MP_YES;
    group->meth = NULL;
    group->text = NULL;
    MP_DIGITS(&group->curvea) = 0;
    MP_DIGITS(&group->curveb) = 0;
    MP_DIGITS(&group->genx) = 0;
    MP_DIGITS(&group->geny) = 0;
    MP_DIGITS(&group->order) = 0;
    group->base_point_mul = NULL;
    group->points_mul = NULL;
    group->validate_point = NULL;
    group->extra1 = NULL;
    group->extra2 = NULL;
    group->extra_free = NULL;
    MP_CHECKOK(mp_init(&group->curvea));
    MP_CHECKOK(mp_init(&group->curveb));
    MP_CHECKOK(mp_init(&group->genx));
    MP_CHECKOK(mp_init(&group->geny));
    MP_CHECKOK(mp_init(&group->order));

CLEANUP:
    if (res != MP_OKAY) {
        ECGroup_free(group);
        return NULL;
    }
    return group;
}
Пример #4
0
/* computes T = REDC(T), 2^b == R */
mp_err s_mp_redc(mp_int *T, mp_mont_modulus *mmm)
{
  mp_err res;
  mp_size i;

  i = MP_USED(T) + MP_USED(&mmm->N) + 2;
  MP_CHECKOK( s_mp_pad(T, i) );
  for (i = 0; i < MP_USED(&mmm->N); ++i ) {
    mp_digit m_i = MP_DIGIT(T, i) * mmm->n0prime;
    /* T += N * m_i * (MP_RADIX ** i); */
    MP_CHECKOK( s_mp_mul_d_add_offset(&mmm->N, m_i, T, i) );
  }
  s_mp_clamp(T);

  /* T /= R */
  s_mp_div_2d(T, mmm->b); 

  if ((res = s_mp_cmp(T, &mmm->N)) >= 0) {
    /* T = T - N */
    MP_CHECKOK( s_mp_sub(T, &mmm->N) );
#ifdef DEBUG
    if ((res = mp_cmp(T, &mmm->N)) >= 0) {
      res = MP_UNDEF;
      goto CLEANUP;
    }
#endif
  }
  res = MP_OKAY;
CLEANUP:
  return res;
}
Пример #5
0
/* Test point doubling in Jacobian coordinates */
mp_err
testPointDoubleJac(ECGroup *ecgroup)
{
	mp_err res;
	mp_int pz, rx, ry, rz, rx2, ry2, rz2;
	ecfp_jac_pt p, p2;
	EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;

	MP_DIGITS(&pz) = 0;
	MP_DIGITS(&rx) = 0;
	MP_DIGITS(&ry) = 0;
	MP_DIGITS(&rz) = 0;
	MP_DIGITS(&rx2) = 0;
	MP_DIGITS(&ry2) = 0;
	MP_DIGITS(&rz2) = 0;

	MP_CHECKOK(mp_init(&pz));
	MP_CHECKOK(mp_init(&rx));
	MP_CHECKOK(mp_init(&ry));
	MP_CHECKOK(mp_init(&rz));
	MP_CHECKOK(mp_init(&rx2));
	MP_CHECKOK(mp_init(&ry2));
	MP_CHECKOK(mp_init(&rz2));

	MP_CHECKOK(mp_set_int(&pz, 5));

	/* Set p2 = 2P */
	ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
	ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
	ecfp_i2fp(p.z, &pz, ecgroup);
	ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);

	group->pt_dbl_jac(&p, &p2, group);
	M_TimeOperation(group->pt_dbl_jac(&p, &p2, group), 100000);

	/* Calculate doubling to compare against */
	ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2,
					  &rz2, ecgroup);
	ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);

	/* Do comparison */
	MP_CHECKOK(testJacPoint(&p2, &rx2, &ry2, ecgroup));

  CLEANUP:
	if (res == MP_OKAY)
		printf("  Test Passed - Point Doubling - Jacobian\n");
	else
		printf("TEST FAILED - Point Doubling - Jacobian\n");

	mp_clear(&pz);
	mp_clear(&rx);
	mp_clear(&ry);
	mp_clear(&rz);
	mp_clear(&rx2);
	mp_clear(&ry2);
	mp_clear(&rz2);

	return res;
}
Пример #6
0
STATIC
mp_err s_mp_to_mont(const mp_int *x, mp_mont_modulus *mmm, mp_int *xMont)
{
  mp_err res;

  /* xMont = x * R mod N   where  N is modulus */
  MP_CHECKOK( mpl_lsh(x, xMont, mmm->b) );  		/* xMont = x << b */
  MP_CHECKOK( mp_div(xMont, &mmm->N, 0, xMont) );	/*         mod N */
CLEANUP:
  return res;
}
Пример #7
0
/* Encode a field element in Montgomery form. See s_mp_to_mont in
 * mpi/mpmontg.c */
mp_err
ec_GFp_enc_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
{
	mp_mont_modulus *mmm;
	mp_err res = MP_OKAY;

	mmm = (mp_mont_modulus *) meth->extra1;
	MP_CHECKOK(mpl_lsh(a, r, mmm->b));
	MP_CHECKOK(mp_mod(r, &mmm->N, r));
  CLEANUP:
	return res;
}
Пример #8
0
/* Decode a field element from Montgomery form. */
mp_err
ec_GFp_dec_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
{
	mp_err res = MP_OKAY;

	if (a != r) {
		MP_CHECKOK(mp_copy(a, r));
	}
	MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1));
  CLEANUP:
	return res;
}
Пример #9
0
/* Tests the time required for a point multiplication */
mp_err
testPointMulTime(ECGroup *ecgroup)
{
	mp_err res = MP_OKAY;
	mp_int rx, ry, n;
	int size;

	MP_DIGITS(&rx) = 0;
	MP_DIGITS(&ry) = 0;
	MP_DIGITS(&n) = 0;

	MP_CHECKOK(mp_init(&rx));
	MP_CHECKOK(mp_init(&ry));
	MP_CHECKOK(mp_init(&n));

	/* compute random scalar */
	size = mpl_significant_bits(&ecgroup->meth->irr);
	if (size < MP_OKAY) {
		res = MP_NO;
		goto CLEANUP;
	}

	MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS));
	MP_CHECKOK(ecgroup->meth->field_mod(&n, &n, ecgroup->meth));

	M_TimeOperation(ec_GFp_pt_mul_jac_fp
					(&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
					 ecgroup), 1000);

	M_TimeOperation(ec_GFp_point_mul_jac_4w_fp
					(&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
					 ecgroup), 1000);

	M_TimeOperation(ec_GFp_point_mul_wNAF_fp
					(&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
					 ecgroup), 1000);

	M_TimeOperation(ec_GFp_pt_mul_jac
					(&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
					 ecgroup), 100);

  CLEANUP:
	if (res == MP_OKAY)
		printf("  Test Passed - Point Multiplication Timing\n");
	else
		printf("TEST FAILED - Point Multiplication Timing\n");
	mp_clear(&rx);
	mp_clear(&ry);
	mp_clear(&n);

	return res;
}
Пример #10
0
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
 * k2 * P(x, y), where G is the generator (base point) of the group of
 * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
 * Input and output values are assumed to be NOT field-encoded. */
mp_err
ECPoints_mul(const ECGroup *group, const mp_int *k1, const mp_int *k2,
                         const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry)
{
        mp_err res = MP_OKAY;
        mp_int k1t, k2t;
        const mp_int *k1p, *k2p;

        MP_DIGITS(&k1t) = 0;
        MP_DIGITS(&k2t) = 0;

        ARGCHK(group != NULL, MP_BADARG);

        /* want scalar to be less than or equal to group order */
        if (k1 != NULL) {
                if (mp_cmp(k1, &group->order) >= 0) {
                        MP_CHECKOK(mp_init(&k1t, FLAG(k1)));
                        MP_CHECKOK(mp_mod(k1, &group->order, &k1t));
                        k1p = &k1t;
                } else {
                        k1p = k1;
                }
        } else {
                k1p = k1;
        }
        if (k2 != NULL) {
                if (mp_cmp(k2, &group->order) >= 0) {
                        MP_CHECKOK(mp_init(&k2t, FLAG(k2)));
                        MP_CHECKOK(mp_mod(k2, &group->order, &k2t));
                        k2p = &k2t;
                } else {
                        k2p = k2;
                }
        } else {
                k2p = k2;
        }

        /* if points_mul is defined, then use it */
        if (group->points_mul) {
                res = group->points_mul(k1p, k2p, px, py, rx, ry, group);
        } else {
                res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group);
        }

  CLEANUP:
        mp_clear(&k1t);
        mp_clear(&k2t);
        return res;
}
Пример #11
0
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k * P(x,
 * y).  If x, y = NULL, then P is assumed to be the generator (base point)
 * of the group of points on the elliptic curve. Input and output values
 * are assumed to be NOT field-encoded. */
mp_err
ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
                        const mp_int *py, mp_int *rx, mp_int *ry)
{
        mp_err res = MP_OKAY;
        mp_int kt;

        ARGCHK((k != NULL) && (group != NULL), MP_BADARG);
        MP_DIGITS(&kt) = 0;

        /* want scalar to be less than or equal to group order */
        if (mp_cmp(k, &group->order) > 0) {
                MP_CHECKOK(mp_init(&kt, FLAG(k)));
                MP_CHECKOK(mp_mod(k, &group->order, &kt));
        } else {
                MP_SIGN(&kt) = MP_ZPOS;
                MP_USED(&kt) = MP_USED(k);
                MP_ALLOC(&kt) = MP_ALLOC(k);
                MP_DIGITS(&kt) = MP_DIGITS(k);
        }

        if ((px == NULL) || (py == NULL)) {
                if (group->base_point_mul) {
                        MP_CHECKOK(group->base_point_mul(&kt, rx, ry, group));
                } else {
                        MP_CHECKOK(group->
                                           point_mul(&kt, &group->genx, &group->geny, rx, ry,
                                                                 group));
                }
        } else {
                if (group->meth->field_enc) {
                        MP_CHECKOK(group->meth->field_enc(px, rx, group->meth));
                        MP_CHECKOK(group->meth->field_enc(py, ry, group->meth));
                        MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group));
                } else {
                        MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group));
                }
        }
        if (group->meth->field_dec) {
                MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
                MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
        }

  CLEANUP:
        if (MP_DIGITS(&kt) != MP_DIGITS(k)) {
                mp_clear(&kt);
        }
        return res;
}
Пример #12
0
/* Computes R = P - Q. Elliptic curve points P, Q, and R can all be
 * identical. Uses affine coordinates. Assumes input is already
 * field-encoded using field_enc, and returns output that is still
 * field-encoded. */
mp_err
ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
                  const mp_int *qy, mp_int *rx, mp_int *ry,
                  const ECGroup *group)
{
    mp_err res = MP_OKAY;
    mp_int nqy;

    MP_DIGITS(&nqy) = 0;
    MP_CHECKOK(mp_init(&nqy));
    /* nqy = -qy */
    MP_CHECKOK(group->meth->field_neg(qy, &nqy, group->meth));
    res = group->point_add(px, py, qx, &nqy, rx, ry, group);
CLEANUP:
    mp_clear(&nqy);
    return res;
}
Пример #13
0
/*! c <- REDC( a * b ) mod N
    \param a < N  i.e. "reduced"
    \param b < N  i.e. "reduced"
    \param mmm modulus N and n0' of N
*/
mp_err
s_mp_mul_mont(const mp_int *a, const mp_int *b, mp_int *c,
              mp_mont_modulus *mmm)
{
    mp_digit *pb;
    mp_digit m_i;
    mp_err res;
    mp_size ib; /* "index b": index of current digit of B */
    mp_size useda, usedb;

    ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);

    if (MP_USED(a) < MP_USED(b)) {
        const mp_int *xch = b; /* switch a and b, to do fewer outer loops */
        b = a;
        a = xch;
    }

    MP_USED(c) = 1;
    MP_DIGIT(c, 0) = 0;
    ib = (MP_USED(&mmm->N) << 1) + 1;
    if ((res = s_mp_pad(c, ib)) != MP_OKAY)
        goto CLEANUP;

    useda = MP_USED(a);
    pb = MP_DIGITS(b);
    s_mpv_mul_d(MP_DIGITS(a), useda, *pb++, MP_DIGITS(c));
    s_mp_setz(MP_DIGITS(c) + useda + 1, ib - (useda + 1));
    m_i = MP_DIGIT(c, 0) * mmm->n0prime;
    s_mp_mul_d_add_offset(&mmm->N, m_i, c, 0);

    /* Outer loop:  Digits of b */
    usedb = MP_USED(b);
    for (ib = 1; ib < usedb; ib++) {
        mp_digit b_i = *pb++;

        /* Inner product:  Digits of a */
        if (b_i)
            s_mpv_mul_d_add_prop(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib);
        m_i = MP_DIGIT(c, ib) * mmm->n0prime;
        s_mp_mul_d_add_offset(&mmm->N, m_i, c, ib);
    }
    if (usedb < MP_USED(&mmm->N)) {
        for (usedb = MP_USED(&mmm->N); ib < usedb; ++ib) {
            m_i = MP_DIGIT(c, ib) * mmm->n0prime;
            s_mp_mul_d_add_offset(&mmm->N, m_i, c, ib);
        }
    }
    s_mp_clamp(c);
    s_mp_rshd(c, MP_USED(&mmm->N)); /* c /= R */
    if (s_mp_cmp(c, &mmm->N) >= 0) {
        MP_CHECKOK(s_mp_sub(c, &mmm->N));
    }
    res = MP_OKAY;

CLEANUP:
    return res;
}
Пример #14
0
/* Field division using Montgomery reduction. */
mp_err
ec_GFp_div_mont(const mp_int *a, const mp_int *b, mp_int *r,
				const GFMethod *meth)
{
	mp_err res = MP_OKAY;

	/* if A=aZ represents a encoded in montgomery coordinates with Z and # 
	 * and \ respectively represent multiplication and division in
	 * montgomery coordinates, then A\B = (a/b)Z = (A/B)Z and Binv =
	 * (1/b)Z = (1/B)(Z^2) where B # Binv = Z */
	MP_CHECKOK(ec_GFp_div(a, b, r, meth));
	MP_CHECKOK(ec_GFp_enc_mont(r, r, meth));
	if (a == NULL) {
		MP_CHECKOK(ec_GFp_enc_mont(r, r, meth));
	}
  CLEANUP:
	return res;
}
Пример #15
0
/* Tests point doubling in Chudnovsky Jacobian coordinates */
mp_err
testPointDoubleChud(ECGroup *ecgroup)
{
	mp_err res;
	mp_int px, py, pz, rx2, ry2, rz2;
	ecfp_aff_pt p;
	ecfp_chud_pt p2;
	EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;

	MP_DIGITS(&rx2) = 0;
	MP_DIGITS(&ry2) = 0;
	MP_DIGITS(&rz2) = 0;
	MP_DIGITS(&px) = 0;
	MP_DIGITS(&py) = 0;
	MP_DIGITS(&pz) = 0;

	MP_CHECKOK(mp_init(&rx2));
	MP_CHECKOK(mp_init(&ry2));
	MP_CHECKOK(mp_init(&rz2));
	MP_CHECKOK(mp_init(&px));
	MP_CHECKOK(mp_init(&py));
	MP_CHECKOK(mp_init(&pz));

	/* Set p2 = 2P */
	ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
	ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
	ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);

	group->pt_dbl_aff2chud(&p, &p2, group);

	/* Calculate doubling to compare against */
	MP_CHECKOK(mp_set_int(&pz, 1));
	ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2,
					  &rz2, ecgroup);
	ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);

	/* Do comparison and check az^4 */
	MP_CHECKOK(testChudPoint(&p2, &rx2, &ry2, ecgroup));

  CLEANUP:
	if (res == MP_OKAY)
		printf("  Test Passed - Point Doubling - Chudnovsky Jacobian\n");
	else
		printf("TEST FAILED - Point Doubling - Chudnovsky Jacobian\n");

	mp_clear(&rx2);
	mp_clear(&ry2);
	mp_clear(&rz2);
	mp_clear(&px);
	mp_clear(&py);
	mp_clear(&pz);

	return res;
}
Пример #16
0
/* Converts a point P(px, py) from affine coordinates to Jacobian
 * projective coordinates R(rx, ry, rz). Assumes input is already
 * field-encoded using field_enc, and returns output that is still
 * field-encoded. */
mp_err
ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx,
				  mp_int *ry, mp_int *rz, const ECGroup *group)
{
	mp_err res = MP_OKAY;

	if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) {
		MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
	} else {
		MP_CHECKOK(mp_copy(px, rx));
		MP_CHECKOK(mp_copy(py, ry));
		MP_CHECKOK(mp_set_int(rz, 1));
		if (group->meth->field_enc) {
			MP_CHECKOK(group->meth->field_enc(rz, rz, group->meth));
		}
	}
  CLEANUP:
	return res;
}
Пример #17
0
/* Construct a generic GFMethod for arithmetic over prime fields with
 * irreducible irr. */
GFMethod *
GFMethod_consGFp(const mp_int *irr)
{
    mp_err res = MP_OKAY;
    GFMethod *meth = NULL;

    meth = GFMethod_new();
    if (meth == NULL)
        return NULL;

    MP_CHECKOK(mp_copy(irr, &meth->irr));
    meth->irr_arr[0] = mpl_significant_bits(irr);
    meth->irr_arr[1] = meth->irr_arr[2] = meth->irr_arr[3] =
        meth->irr_arr[4] = 0;
    switch (MP_USED(&meth->irr)) {
        /* maybe we need 1 and 2 words here as well?*/
        case 3:
            meth->field_add = &ec_GFp_add_3;
            meth->field_sub = &ec_GFp_sub_3;
            break;
        case 4:
            meth->field_add = &ec_GFp_add_4;
            meth->field_sub = &ec_GFp_sub_4;
            break;
        case 5:
            meth->field_add = &ec_GFp_add_5;
            meth->field_sub = &ec_GFp_sub_5;
            break;
        case 6:
            meth->field_add = &ec_GFp_add_6;
            meth->field_sub = &ec_GFp_sub_6;
            break;
        default:
            meth->field_add = &ec_GFp_add;
            meth->field_sub = &ec_GFp_sub;
    }
    meth->field_neg = &ec_GFp_neg;
    meth->field_mod = &ec_GFp_mod;
    meth->field_mul = &ec_GFp_mul;
    meth->field_sqr = &ec_GFp_sqr;
    meth->field_div = &ec_GFp_div;
    meth->field_enc = NULL;
    meth->field_dec = NULL;
    meth->extra1 = NULL;
    meth->extra2 = NULL;
    meth->extra_free = NULL;

CLEANUP:
    if (res != MP_OKAY) {
        GFMethod_free(meth);
        return NULL;
    }
    return meth;
}
Пример #18
0
/* Subtracts two field elements.  Assumes that 0 <= a, b < meth->irr */
mp_err
ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r,
           const GFMethod *meth)
{
    mp_err res = MP_OKAY;

    /* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a - b (mod p) */
    res = mp_sub(a, b, r);
    if (res == MP_RANGE) {
        MP_CHECKOK(mp_sub(b, a, r));
        if (mp_cmp_z(r) < 0) {
            MP_CHECKOK(mp_add(r, &meth->irr, r));
        }
        MP_CHECKOK(ec_GFp_neg(r, r, meth));
    }
    if (mp_cmp_z(r) < 0) {
        MP_CHECKOK(mp_add(r, &meth->irr, r));
    }
CLEANUP:
    return res;
}
Пример #19
0
/* Divides two field elements. If a is NULL, then returns the inverse of
 * b. */
mp_err
ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r,
           const GFMethod *meth)
{
    mp_err res = MP_OKAY;
    mp_int t;

    /* If a is NULL, then return the inverse of b, otherwise return a/b. */
    if (a == NULL) {
        return mp_invmod(b, &meth->irr, r);
    } else {
        /* MPI doesn't support divmod, so we implement it using invmod and
         * mulmod. */
        MP_CHECKOK(mp_init(&t));
        MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
        MP_CHECKOK(mp_mulmod(a, &t, &meth->irr, r));
    CLEANUP:
        mp_clear(&t);
        return res;
    }
}
Пример #20
0
/* Divides two field elements. If a is NULL, then returns the inverse of
 * b. */
mp_err
ec_GF2m_div(const mp_int *a, const mp_int *b, mp_int *r,
            const GFMethod *meth)
{
    mp_err res = MP_OKAY;
    mp_int t;

    /* If a is NULL, then return the inverse of b, otherwise return a/b. */
    if (a == NULL) {
        /* The GF(2^m) portion of MPI doesn't support invmod, so we
         * compute 1/b. */
        MP_CHECKOK(mp_init(&t));
        MP_CHECKOK(mp_set_int(&t, 1));
        MP_CHECKOK(mp_bdivmod(&t, b, &meth->irr, meth->irr_arr, r));
    CLEANUP:
        mp_clear(&t);
        return res;
    } else {
        return mp_bdivmod(a, b, &meth->irr, meth->irr_arr, r);
    }
}
Пример #21
0
/* Construct a generic ECGroup for elliptic curves over prime fields with
 * field arithmetic implemented in Montgomery coordinates. */
ECGroup *
ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea,
                     const mp_int *curveb, const mp_int *genx,
                     const mp_int *geny, const mp_int *order, int cofactor)
{
    mp_err res = MP_OKAY;
    ECGroup *group = NULL;

    group = ECGroup_new();
    if (group == NULL)
        return NULL;

    group->meth = GFMethod_consGFp_mont(irr);
    if (group->meth == NULL) {
        res = MP_MEM;
        goto CLEANUP;
    }
    MP_CHECKOK(group->meth->
               field_enc(curvea, &group->curvea, group->meth));
    MP_CHECKOK(group->meth->
               field_enc(curveb, &group->curveb, group->meth));
    MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth));
    MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth));
    MP_CHECKOK(mp_copy(order, &group->order));
    group->cofactor = cofactor;
    group->point_add = &ec_GFp_pt_add_aff;
    group->point_sub = &ec_GFp_pt_sub_aff;
    group->point_dbl = &ec_GFp_pt_dbl_aff;
    group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
    group->base_point_mul = NULL;
    group->points_mul = &ec_GFp_pts_mul_jac;
    group->validate_point = &ec_GFp_validate_point;

CLEANUP:
    if (res != MP_OKAY) {
        ECGroup_free(group);
        return NULL;
    }
    return group;
}
Пример #22
0
/* Tests point addition of Jacobian + Affine -> Jacobian */
mp_err
testPointAddJacAff(ECGroup *ecgroup)
{
	mp_err res;
	mp_int pz, rx2, ry2, rz2;
	ecfp_jac_pt p, r;
	ecfp_aff_pt q;
	EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;

	/* Init */
	MP_DIGITS(&pz) = 0;
	MP_DIGITS(&rx2) = 0;
	MP_DIGITS(&ry2) = 0;
	MP_DIGITS(&rz2) = 0;
	MP_CHECKOK(mp_init(&pz));
	MP_CHECKOK(mp_init(&rx2));
	MP_CHECKOK(mp_init(&ry2));
	MP_CHECKOK(mp_init(&rz2));

	MP_CHECKOK(mp_set_int(&pz, 5));

	/* Set p */
	ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
	ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
	ecfp_i2fp(p.z, &pz, ecgroup);
	/* Set q */
	ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
	ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);

	/* Do calculations */
	group->pt_add_jac_aff(&p, &q, &r, group);

	/* Do calculation in integer to compare against */
	MP_CHECKOK(ec_GFp_pt_add_jac_aff
			   (&ecgroup->genx, &ecgroup->geny, &pz, &ecgroup->geny,
				&ecgroup->genx, &rx2, &ry2, &rz2, ecgroup));
	/* convert result R to affine coordinates */
	ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);

	MP_CHECKOK(testJacPoint(&r, &rx2, &ry2, ecgroup));

  CLEANUP:
	if (res == MP_OKAY)
		printf("  Test Passed - Point Addition - Jacobian & Affine\n");
	else
		printf("TEST FAILED - Point Addition - Jacobian & Affine\n");

	mp_clear(&pz);
	mp_clear(&rx2);
	mp_clear(&ry2);
	mp_clear(&rz2);

	return res;
}
Пример #23
0
/* Construct a generic ECGroup for elliptic curves over binary polynomial
 * fields. */
ECGroup *
ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5],
                 const mp_int *curvea, const mp_int *curveb,
                 const mp_int *genx, const mp_int *geny,
                 const mp_int *order, int cofactor)
{
    mp_err res = MP_OKAY;
    ECGroup *group = NULL;

    group = ECGroup_new();
    if (group == NULL)
        return NULL;

    group->meth = GFMethod_consGF2m(irr, irr_arr);
    if (group->meth == NULL) {
        res = MP_MEM;
        goto CLEANUP;
    }
    MP_CHECKOK(mp_copy(curvea, &group->curvea));
    MP_CHECKOK(mp_copy(curveb, &group->curveb));
    MP_CHECKOK(mp_copy(genx, &group->genx));
    MP_CHECKOK(mp_copy(geny, &group->geny));
    MP_CHECKOK(mp_copy(order, &group->order));
    group->cofactor = cofactor;
    group->point_add = &ec_GF2m_pt_add_aff;
    group->point_sub = &ec_GF2m_pt_sub_aff;
    group->point_dbl = &ec_GF2m_pt_dbl_aff;
    group->point_mul = &ec_GF2m_pt_mul_mont;
    group->base_point_mul = NULL;
    group->points_mul = &ec_pts_mul_basic;
    group->validate_point = &ec_GF2m_validate_point;

CLEANUP:
    if (res != MP_OKAY) {
        ECGroup_free(group);
        return NULL;
    }
    return group;
}
Пример #24
0
/* Allocate memory for a new ECGroup object. */
ECGroup *
ECGroup_new(int kmflag)
{
	mp_err res = MP_OKAY;
	ECGroup *group;
#ifdef _KERNEL
	group = (ECGroup *) kmem_alloc(sizeof(ECGroup), kmflag);
#else
	group = (ECGroup *) malloc(sizeof(ECGroup));
#endif
	if (group == NULL)
		return NULL;
	group->constructed = MP_YES;
        group->meth = NULL;
	group->text = NULL;
	MP_DIGITS(&group->curvea) = 0;
	MP_DIGITS(&group->curveb) = 0;
	MP_DIGITS(&group->genx) = 0;
	MP_DIGITS(&group->geny) = 0;
	MP_DIGITS(&group->order) = 0;
	group->base_point_mul = NULL;
	group->points_mul = NULL;
	group->validate_point = NULL;
	group->extra1 = NULL;
	group->extra2 = NULL;
	group->extra_free = NULL;
	MP_CHECKOK(mp_init(&group->curvea, kmflag));
	MP_CHECKOK(mp_init(&group->curveb, kmflag));
	MP_CHECKOK(mp_init(&group->genx, kmflag));
	MP_CHECKOK(mp_init(&group->geny, kmflag));
	MP_CHECKOK(mp_init(&group->order, kmflag));

  CLEANUP:
	if (res != MP_OKAY) {
		ECGroup_free(group);
		return NULL;
	}
	return group;
}
Пример #25
0
/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
 * be an array of signed char's to output to, bitsize should be the number
 * of bits of out, in is the original scalar, and w is the window size.
 * NAF is discussed in the paper: D. Hankerson, J. Hernandez and A.
 * Menezes, "Software implementation of elliptic curve cryptography over
 * binary fields", Proc. CHES 2000. */
mp_err
ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in, int w)
{
        mp_int k;
        mp_err res = MP_OKAY;
        int i, twowm1, mask;

        twowm1 = ec_twoTo(w - 1);
        mask = 2 * twowm1 - 1;

        MP_DIGITS(&k) = 0;
        MP_CHECKOK(mp_init_copy(&k, in));

        i = 0;
        /* Compute wNAF form */
        while (mp_cmp_z(&k) > 0) {
                if (mp_isodd(&k)) {
                        out[i] = MP_DIGIT(&k, 0) & mask;
                        if (out[i] >= twowm1)
                                out[i] -= 2 * twowm1;

                        /* Subtract off out[i].  Note mp_sub_d only works with
                         * unsigned digits */
                        if (out[i] >= 0) {
                                mp_sub_d(&k, out[i], &k);
                        } else {
                                mp_add_d(&k, -(out[i]), &k);
                        }
                } else {
                        out[i] = 0;
                }
                mp_div_2(&k, &k);
                i++;
        }
        /* Zero out the remaining elements of the out array. */
        for (; i < bitsize + 1; i++) {
                out[i] = 0;
        }
  CLEANUP:
        mp_clear(&k);
        return res;

}
Пример #26
0
/* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery
 * projective coordinates. Uses algorithm Mdouble in appendix of Lopez, J.
 * and Dahab, R.  "Fast multiplication on elliptic curves over GF(2^m)
 * without precomputation". modified to not require precomputation of
 * c=b^{2^{m-1}}. */
static mp_err
gf2m_Mdouble(mp_int *x, mp_int *z, const ECGroup *group, int kmflag)
{
        mp_err res = MP_OKAY;
        mp_int t1;

        MP_DIGITS(&t1) = 0;
        MP_CHECKOK(mp_init(&t1, kmflag));

        MP_CHECKOK(group->meth->field_sqr(x, x, group->meth));
        MP_CHECKOK(group->meth->field_sqr(z, &t1, group->meth));
        MP_CHECKOK(group->meth->field_mul(x, &t1, z, group->meth));
        MP_CHECKOK(group->meth->field_sqr(x, x, group->meth));
        MP_CHECKOK(group->meth->field_sqr(&t1, &t1, group->meth));
        MP_CHECKOK(group->meth->
                           field_mul(&group->curveb, &t1, &t1, group->meth));
        MP_CHECKOK(group->meth->field_add(x, &t1, x, group->meth));

  CLEANUP:
        mp_clear(&t1);
        return res;
}
Пример #27
0
/* Allocate memory for a new GFMethod object. */
GFMethod *
GFMethod_new()
{
    mp_err res = MP_OKAY;
    GFMethod *meth;
    meth = (GFMethod *)malloc(sizeof(GFMethod));
    if (meth == NULL)
        return NULL;
    meth->constructed = MP_YES;
    MP_DIGITS(&meth->irr) = 0;
    meth->extra_free = NULL;
    MP_CHECKOK(mp_init(&meth->irr));

CLEANUP:
    if (res != MP_OKAY) {
        GFMethod_free(meth);
        return NULL;
    }
    return meth;
}
Пример #28
0
/* Tests a point p in Jacobian coordinates, comparing against the
 * expected affine result (x, y). */
mp_err
testJacPoint(ecfp_jac_pt * p, mp_int *x, mp_int *y, ECGroup *ecgroup)
{
	char s[1000];
	mp_int rx, ry, rz;
	mp_err res = MP_OKAY;

	MP_DIGITS(&rx) = 0;
	MP_DIGITS(&ry) = 0;
	MP_DIGITS(&rz) = 0;

	MP_CHECKOK(mp_init(&rx));
	MP_CHECKOK(mp_init(&ry));
	MP_CHECKOK(mp_init(&rz));

	ecfp_fp2i(&rx, p->x, ecgroup);
	ecfp_fp2i(&ry, p->y, ecgroup);
	ecfp_fp2i(&rz, p->z, ecgroup);

	/* convert result R to affine coordinates */
	ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup);

	/* Compare to expected result */
	if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) {
		printf("  Error: Jacobian Floating Point Incorrect.\n");
		MP_CHECKOK(mp_toradix(&rx, s, 16));
		printf("floating point result\nrx    %s\n", s);
		MP_CHECKOK(mp_toradix(&ry, s, 16));
		printf("ry    %s\n", s);
		MP_CHECKOK(mp_toradix(x, s, 16));
		printf("integer result\nx   %s\n", s);
		MP_CHECKOK(mp_toradix(y, s, 16));
		printf("y   %s\n", s);
		res = MP_NO;
		goto CLEANUP;
	}

  CLEANUP:
	mp_clear(&rx);
	mp_clear(&ry);
	mp_clear(&rz);

	return res;
}
Пример #29
0
/* Computes R = 2P.  Elliptic curve points P and R can be identical.  Uses
 * Modified Jacobian coordinates.
 *
 * Assumes input is already field-encoded using field_enc, and returns
 * output that is still field-encoded.
 *
 */
mp_err
ec_GFp_pt_dbl_jm(const mp_int *px, const mp_int *py, const mp_int *pz,
                                 const mp_int *paz4, mp_int *rx, mp_int *ry, mp_int *rz,
                                 mp_int *raz4, mp_int scratch[], const ECGroup *group)
{
        mp_err res = MP_OKAY;
        mp_int *t0, *t1, *M, *S;

        t0 = &scratch[0];
        t1 = &scratch[1];
        M = &scratch[2];
        S = &scratch[3];

#if MAX_SCRATCH < 4
#error "Scratch array defined too small "
#endif

        /* Check for point at infinity */
        if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
                /* Set r = pt at infinity by setting rz = 0 */

                MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
                goto CLEANUP;
        }

        /* M = 3 (px^2) + a*(pz^4) */
        MP_CHECKOK(group->meth->field_sqr(px, t0, group->meth));
        MP_CHECKOK(group->meth->field_add(t0, t0, M, group->meth));
        MP_CHECKOK(group->meth->field_add(t0, M, t0, group->meth));
        MP_CHECKOK(group->meth->field_add(t0, paz4, M, group->meth));

        /* rz = 2 * py * pz */
        MP_CHECKOK(group->meth->field_mul(py, pz, S, group->meth));
        MP_CHECKOK(group->meth->field_add(S, S, rz, group->meth));

        /* t0 = 2y^2 , t1 = 8y^4 */
        MP_CHECKOK(group->meth->field_sqr(py, t0, group->meth));
        MP_CHECKOK(group->meth->field_add(t0, t0, t0, group->meth));
        MP_CHECKOK(group->meth->field_sqr(t0, t1, group->meth));
        MP_CHECKOK(group->meth->field_add(t1, t1, t1, group->meth));

        /* S = 4 * px * py^2 = 2 * px * t0 */
        MP_CHECKOK(group->meth->field_mul(px, t0, S, group->meth));
        MP_CHECKOK(group->meth->field_add(S, S, S, group->meth));


        /* rx = M^2 - 2S */
        MP_CHECKOK(group->meth->field_sqr(M, rx, group->meth));
        MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth));
        MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth));

        /* ry = M * (S - rx) - t1 */
        MP_CHECKOK(group->meth->field_sub(S, rx, S, group->meth));
        MP_CHECKOK(group->meth->field_mul(S, M, ry, group->meth));
        MP_CHECKOK(group->meth->field_sub(ry, t1, ry, group->meth));

        /* ra*z^4 = 2*t1*(apz4) */
        MP_CHECKOK(group->meth->field_mul(paz4, t1, raz4, group->meth));
        MP_CHECKOK(group->meth->field_add(raz4, raz4, raz4, group->meth));


  CLEANUP:
        return res;
}
Пример #30
0
/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
 * curve points P and R can be identical. Uses mixed Modified-Jacobian
 * co-ordinates for doubling and Chudnovsky Jacobian coordinates for
 * additions. Assumes input is already field-encoded using field_enc, and
 * returns output that is still field-encoded. Uses 5-bit window NAF
 * method (algorithm 11) for scalar-point multiplication from Brown,
 * Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic
 * Curves Over Prime Fields. */
mp_err
ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
                                          mp_int *rx, mp_int *ry, const ECGroup *group)
{
        mp_err res = MP_OKAY;
        mp_int precomp[16][2], rz, tpx, tpy;
        mp_int raz4;
        mp_int scratch[MAX_SCRATCH];
        signed char *naf = NULL;
        int i, orderBitSize;

        MP_DIGITS(&rz) = 0;
        MP_DIGITS(&raz4) = 0;
        MP_DIGITS(&tpx) = 0;
        MP_DIGITS(&tpy) = 0;
        for (i = 0; i < 16; i++) {
                MP_DIGITS(&precomp[i][0]) = 0;
                MP_DIGITS(&precomp[i][1]) = 0;
        }
        for (i = 0; i < MAX_SCRATCH; i++) {
                MP_DIGITS(&scratch[i]) = 0;
        }

        ARGCHK(group != NULL, MP_BADARG);
        ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);

        /* initialize precomputation table */
        MP_CHECKOK(mp_init(&tpx, FLAG(n)));
        MP_CHECKOK(mp_init(&tpy, FLAG(n)));;
        MP_CHECKOK(mp_init(&rz, FLAG(n)));
        MP_CHECKOK(mp_init(&raz4, FLAG(n)));

        for (i = 0; i < 16; i++) {
                MP_CHECKOK(mp_init(&precomp[i][0], FLAG(n)));
                MP_CHECKOK(mp_init(&precomp[i][1], FLAG(n)));
        }
        for (i = 0; i < MAX_SCRATCH; i++) {
                MP_CHECKOK(mp_init(&scratch[i], FLAG(n)));
        }

        /* Set out[8] = P */
        MP_CHECKOK(mp_copy(px, &precomp[8][0]));
        MP_CHECKOK(mp_copy(py, &precomp[8][1]));

        /* Set (tpx, tpy) = 2P */
        MP_CHECKOK(group->
                           point_dbl(&precomp[8][0], &precomp[8][1], &tpx, &tpy,
                                                 group));

        /* Set 3P, 5P, ..., 15P */
        for (i = 8; i < 15; i++) {
                MP_CHECKOK(group->
                                   point_add(&precomp[i][0], &precomp[i][1], &tpx, &tpy,
                                                         &precomp[i + 1][0], &precomp[i + 1][1],
                                                         group));
        }

        /* Set -15P, -13P, ..., -P */
        for (i = 0; i < 8; i++) {
                MP_CHECKOK(mp_copy(&precomp[15 - i][0], &precomp[i][0]));
                MP_CHECKOK(group->meth->
                                   field_neg(&precomp[15 - i][1], &precomp[i][1],
                                                         group->meth));
        }

        /* R = inf */
        MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));

        orderBitSize = mpl_significant_bits(&group->order);

        /* Allocate memory for NAF */
#ifdef _KERNEL
        naf = (signed char *) kmem_alloc((orderBitSize + 1), FLAG(n));
#else
        naf = (signed char *) malloc(sizeof(signed char) * (orderBitSize + 1));
        if (naf == NULL) {
                res = MP_MEM;
                goto CLEANUP;
        }
#endif

        /* Compute 5NAF */
        ec_compute_wNAF(naf, orderBitSize, n, 5);

        /* wNAF method */
        for (i = orderBitSize; i >= 0; i--) {
                /* R = 2R */
                ec_GFp_pt_dbl_jm(rx, ry, &rz, &raz4, rx, ry, &rz,
                                             &raz4, scratch, group);
                if (naf[i] != 0) {
                        ec_GFp_pt_add_jm_aff(rx, ry, &rz, &raz4,
                                                                 &precomp[(naf[i] + 15) / 2][0],
                                                                 &precomp[(naf[i] + 15) / 2][1], rx, ry,
                                                                 &rz, &raz4, scratch, group);
                }
        }

        /* convert result S to affine coordinates */
        MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));

  CLEANUP:
        for (i = 0; i < MAX_SCRATCH; i++) {
                mp_clear(&scratch[i]);
        }
        for (i = 0; i < 16; i++) {
                mp_clear(&precomp[i][0]);
                mp_clear(&precomp[i][1]);
        }
        mp_clear(&tpx);
        mp_clear(&tpy);
        mp_clear(&rz);
        mp_clear(&raz4);
#ifdef _KERNEL
        kmem_free(naf, (orderBitSize + 1));
#else
        free(naf);
#endif
        return res;
}