void ecMultiply (ecPoint *p, const vlPoint k) /* sets p := k*p */ { vlPoint h; int z, hi, ki; word16 i; ecPoint r; gfCopy (r.x, p->x); p->x[0] = 0; gfCopy (r.y, p->y); p->y[0] = 0; vlShortMultiply (h, k, 3); z = vlNumBits (h) - 1; /* so vlTakeBit (h, z) == 1 */ i = 1; for (;;) { hi = vlTakeBit (h, i); ki = vlTakeBit (k, i); if (hi == 1 && ki == 0) { ecAdd (p, &r); } if (hi == 0 && ki == 1) { ecSub (p, &r); } if (i >= z) { break; } i++; ecDouble (&r); } } /* ecMultiply */
void ecAdd (ecPoint *p, const ecPoint *q) /* sets p := p + q */ { gfPoint lambda, t, tx, ty, x3; /* first check if there is indeed work to do (q != 0): */ if (q->x[0] != 0 || q->y[0] != 0) { if (p->x[0] != 0 || p->y[0] != 0) { /* p != 0 and q != 0 */ if (gfEqual (p->x, q->x)) { /* either p == q or p == -q: */ if (gfEqual (p->y, q->y)) { /* points are equal; double p: */ ecDouble (p); } else { /* must be inverse: result is zero */ /* (should assert that q->y = p->x + p->y) */ p->x[0] = p->y[0] = 0; } } else { /* p != 0, q != 0, p != q, p != -q */ /* evaluate lambda = (y1 + y2)/(x1 + x2): */ gfAdd (ty, p->y, q->y); gfAdd (tx, p->x, q->x); gfInvert (t, tx); gfMultiply (lambda, ty, t); /* evaluate x3 = lambda^2 + lambda + x1 + x2: */ gfSquare (x3, lambda); gfAdd (x3, x3, lambda); gfAdd (x3, x3, tx); /* evaluate y3 = lambda*(x1 + x3) + x3 + y1: */ gfAdd (tx, p->x, x3); gfMultiply (t, lambda, tx); gfAdd (t, t, x3); gfAdd (p->y, t, p->y); /* deposit the value of x3: */ gfCopy (p->x, x3); } } else { /* just copy q into p: */ gfCopy (p->x, q->x); gfCopy (p->y, q->y); } } } /* ecAdd */
error_t ecFullAdd(const EcDomainParameters *params, EcPoint *r, const EcPoint *s, const EcPoint *t) { error_t error; //Check whether Sz == 0 if(!mpiCompInt(&s->z, 0)) { //Set R = T MPI_CHECK(mpiCopy(&r->x, &t->x)); MPI_CHECK(mpiCopy(&r->y, &t->y)); MPI_CHECK(mpiCopy(&r->z, &t->z)); } //Check whether Tz == 0 else if(!mpiCompInt(&t->z, 0)) { //Set R = S MPI_CHECK(mpiCopy(&r->x, &s->x)); MPI_CHECK(mpiCopy(&r->y, &s->y)); MPI_CHECK(mpiCopy(&r->z, &s->z)); } else { //Compute R = S + T EC_CHECK(ecAdd(params, r, s, t)); //Check whether R == (0, 0, 0) if(!mpiCompInt(&r->x, 0) && !mpiCompInt(&r->y, 0) && !mpiCompInt(&r->z, 0)) { //Compute R = 2 * S EC_CHECK(ecDouble(params, r, s)); } } end: //Return status code return error; }
error_t ecTwinMult(const EcDomainParameters *params, EcPoint *r, const Mpi *d0, const EcPoint *s, const Mpi *d1, const EcPoint *t) { error_t error; int_t k; uint_t m; uint_t m0; uint_t m1; uint_t c0; uint_t c1; uint_t h0; uint_t h1; int_t u0; int_t u1; EcPoint spt; EcPoint smt; //Initialize EC points ecInit(&spt); ecInit(&smt); //Precompute SpT = S + T EC_CHECK(ecFullAdd(params, &spt, s, t)); //Precompute SmT = S - T EC_CHECK(ecFullSub(params, &smt, s, t)); //Let m0 be the bit length of d0 m0 = mpiGetBitLength(d0); //Let m1 be the bit length of d1 m1 = mpiGetBitLength(d1); //Let m = MAX(m0, m1) m = MAX(m0, m1); //Let c be a 2 x 6 binary matrix c0 = mpiGetBitValue(d0, m - 4); c0 |= mpiGetBitValue(d0, m - 3) << 1; c0 |= mpiGetBitValue(d0, m - 2) << 2; c0 |= mpiGetBitValue(d0, m - 1) << 3; c1 = mpiGetBitValue(d1, m - 4); c1 |= mpiGetBitValue(d1, m - 3) << 1; c1 |= mpiGetBitValue(d1, m - 2) << 2; c1 |= mpiGetBitValue(d1, m - 1) << 3; //Set R = (1, 1, 0) MPI_CHECK(mpiSetValue(&r->x, 1)); MPI_CHECK(mpiSetValue(&r->y, 1)); MPI_CHECK(mpiSetValue(&r->z, 0)); //Calculate both multiplications at the same time for(k = m; k >= 0; k--) { //Compute h(0) = 16 * c(0,1) + 8 * c(0,2) + 4 * c(0,3) + 2 * c(0,4) + c(0,5) h0 = c0 & 0x1F; //Check whether c(0,0) == 1 if(c0 & 0x20) h0 = 31 - h0; //Compute h(1) = 16 * c(1,1) + 8 * c(1,2) + 4 * c(1,3) + 2 * c(1,4) + c(1,5) h1 = c1 & 0x1F; //Check whether c(1,0) == 1 if(c1 & 0x20) h1 = 31 - h1; //Compute u(0) if(h0 < ecTwinMultF(h1)) u0 = 0; else if(c0 & 0x20) u0 = -1; else u0 = 1; //Compute u(1) if(h1 < ecTwinMultF(h0)) u1 = 0; else if(c1 & 0x20) u1 = -1; else u1 = 1; //Update c matrix c0 <<= 1; c0 |= mpiGetBitValue(d0, k - 5); c0 ^= u0 ? 0x20 : 0x00; c1 <<= 1; c1 |= mpiGetBitValue(d1, k - 5); c1 ^= u1 ? 0x20 : 0x00; //Point doubling EC_CHECK(ecDouble(params, r, r)); //Check u(0) and u(1) if(u0 == -1 && u1 == -1) { //Compute R = R - SpT EC_CHECK(ecFullSub(params, r, r, &spt)); } else if(u0 == -1 && u1 == 0) { //Compute R = R - S EC_CHECK(ecFullSub(params, r, r, s)); } else if(u0 == -1 && u1 == 1) { //Compute R = R - SmT EC_CHECK(ecFullSub(params, r, r, &smt)); } else if(u0 == 0 && u1 == -1) { //Compute R = R - T EC_CHECK(ecFullSub(params, r, r, t)); } else if(u0 == 0 && u1 == 1) { //Compute R = R + T EC_CHECK(ecFullAdd(params, r, r, t)); } else if(u0 == 1 && u1 == -1) { //Compute R = R + SmT EC_CHECK(ecFullAdd(params, r, r, &smt)); } else if(u0 == 1 && u1 == 0) { //Compute R = R + S EC_CHECK(ecFullAdd(params, r, r, s)); } else if(u0 == 1 && u1 == 1) { //Compute R = R + SpT EC_CHECK(ecFullAdd(params, r, r, &spt)); } } end: //Release EC points ecFree(&spt); ecFree(&smt); //Return status code return error; }
error_t ecMult(const EcDomainParameters *params, EcPoint *r, const Mpi *d, const EcPoint *s) { error_t error; uint_t i; Mpi h; //Initialize multiple precision integer mpiInit(&h); //Check whether d == 0 if(!mpiCompInt(d, 0)) { //Set R = (1, 1, 0) MPI_CHECK(mpiSetValue(&r->x, 1)); MPI_CHECK(mpiSetValue(&r->y, 1)); MPI_CHECK(mpiSetValue(&r->z, 0)); } //Check whether d == 1 else if(!mpiCompInt(d, 1)) { //Set R = S MPI_CHECK(mpiCopy(&r->x, &s->x)); MPI_CHECK(mpiCopy(&r->y, &s->y)); MPI_CHECK(mpiCopy(&r->z, &s->z)); } //Check whether Sz == 0 else if(!mpiCompInt(&s->z, 0)) { //Set R = (1, 1, 0) MPI_CHECK(mpiSetValue(&r->x, 1)); MPI_CHECK(mpiSetValue(&r->y, 1)); MPI_CHECK(mpiSetValue(&r->z, 0)); } else { //Check whether Sz != 1 if(mpiCompInt(&s->z, 1)) { //Normalize S EC_CHECK(ecAffinify(params, r, s)); EC_CHECK(ecProjectify(params, r, r)); } else { //Set R = S MPI_CHECK(mpiCopy(&r->x, &s->x)); MPI_CHECK(mpiCopy(&r->y, &s->y)); MPI_CHECK(mpiCopy(&r->z, &s->z)); } //Left-to-right binary method #if 0 for(i = mpiGetBitLength(d) - 1; i >= 1; i--) { //Point doubling EC_CHECK(ecDouble(params, r, r)); if(mpiGetBitValue(d, i - 1)) { //Compute R = R + S EC_CHECK(ecFullAdd(params, r, r, s)); } } //Fast left-to-right binary method #else //Precompute h = 3 * d MPI_CHECK(mpiAdd(&h, d, d)); MPI_CHECK(mpiAdd(&h, &h, d)); //Scalar multiplication for(i = mpiGetBitLength(&h) - 2; i >= 1; i--) { //Point doubling EC_CHECK(ecDouble(params, r, r)); //Check whether h(i) == 1 and k(i) == 0 if(mpiGetBitValue(&h, i) && !mpiGetBitValue(d, i)) { //Compute R = R + S EC_CHECK(ecFullAdd(params, r, r, s)); } //Check whether h(i) == 0 and k(i) == 1 else if(!mpiGetBitValue(&h, i) && mpiGetBitValue(d, i)) { //Compute R = R - S EC_CHECK(ecFullSub(params, r, r, s)); } } #endif } end: //Release multiple precision integer mpiFree(&h); //Return status code return error; }
int ecSelfTest (int test_count) /* perform test_count self tests */ { int i, yb, nfail = 0, afail = 0, sfail = 0, cfail = 0, qfail = 0, pfail = 0, yfail = 0; ecPoint f, g, x, y; vlPoint m, n, p; clock_t elapsed = 0L; srand ((unsigned)(time(NULL) % 65521U)); printf ("Executing %d curve self tests...", test_count); for (i = 0; i < test_count; i++) { ecRandom (&f); ecRandom (&g); vlRandom (m); vlRandom (n); /* negation test: -(-f) = f */ ecCopy (&x, &f); ecNegate (&x); ecNegate (&x); if (!ecEqual (&x, &f)) { nfail++; /* printf ("Addition test #%d failed!\n", i); */ } /* addition test: f+g = g+f */ ecCopy (&x, &f); ecAdd (&x, &g); ecCopy (&y, &g); ecAdd (&y, &f); if (!ecEqual (&x, &y)) { afail++; /* printf ("Addition test #%d failed!\n", i); */ } /* subtraction test: f-g = f+(-g) */ ecCopy (&x, &f); ecSub (&x, &g); ecCopy (&y, &g); ecNegate (&y); ecAdd (&y, &f); if (!ecEqual (&x, &y)) { sfail++; /* printf ("Subtraction test #%d failed!\n", i); */ } /* quadruplication test: 2*(2*f) = f + f + f + f */ ecCopy (&x, &f); ecDouble (&x); ecDouble (&x); ecClear (&y); ecAdd (&y, &f); ecAdd (&y, &f); ecAdd (&y, &f); ecAdd (&y, &f); if (!ecEqual (&x, &y)) { qfail++; /* printf ("Quadruplication test #%d failed!\n", i); */ } /* scalar multiplication commutativity test: m*(n*f) = n*(m*f) */ ecCopy (&x, &f); ecCopy (&y, &f); elapsed -= clock (); ecMultiply (&x, n); ecMultiply (&x, m); ecMultiply (&y, m); ecMultiply (&y, n); elapsed += clock (); if (!ecEqual (&x, &y)) { cfail++; /* printf ("Commutativity test #%d failed!\n", i); */ } /* y calculation test: */ yb = ecYbit (&f); ecClear (&x); gfCopy (x.x, f.x); ecCalcY (&x, yb); if (!ecEqual (&f, &x)) { yfail++; /* printf ("Y calculation test #%d failed!\n", i); */ } /* packing test: unpack (pack (f)) = f */ ecPack (&f, p); ecUnpack (&x, p); if (!ecEqual (&f, &x)) { pfail++; /* printf ("Packing test #%d failed!\n", i); */ } } printf (" done, scalar multiplication time: %.3f s/op.\n", (float)elapsed/CLOCKS_PER_SEC/(test_count?4*test_count:4)); if (nfail) printf ("---> %d negations failed <---\n", nfail); if (afail) printf ("---> %d additions failed <---\n", afail); if (sfail) printf ("---> %d subtractions failed <---\n", sfail); if (qfail) printf ("---> %d quadruplications failed <---\n", qfail); if (cfail) printf ("---> %d commutativities failed <---\n", cfail); if (yfail) printf ("---> %d y calculations failed <---\n", yfail); if (pfail) printf ("---> %d packings failed <---\n", pfail); return nfail || afail || sfail || qfail || cfail || yfail || pfail; } /* ecSelfTest */