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 */
void ecSub (ecPoint *p, const ecPoint *r) /* sets p := p - r */ { ecPoint t; gfCopy (t.x, r->x); gfAdd (t.y, r->x, r->y); ecAdd (p, &t); } /* ecSub */
static int gfSlowTrace (const gfPoint p) /* slowly evaluates to the trace of p (or an error code) */ { int i; gfPoint t; assert (logt != NULL && expt != NULL); assert (p != NULL); gfCopy (t, p); for (i = 1; i < GF_M; i++) { gfSquare (t, t); gfAdd (t, t, p); } return t[0] != 0; } /* gfSlowTrace */
void ecDouble (ecPoint *p) /* sets p := 2*p */ { gfPoint lambda, t1, t2; /* evaluate lambda = x + y/x: */ gfInvert (t1, p->x); gfMultiply (lambda, p->y, t1); gfAdd (lambda, lambda, p->x); /* evaluate x3 = lambda^2 + lambda: */ gfSquare (t1, lambda); gfAdd (t1, t1, lambda); /* now t1 = x3 */ /* evaluate y3 = x^2 + lambda*x3 + x3: */ gfSquare (p->y, p->x); gfMultiply (t2, lambda, t1); gfAdd (p->y, p->y, t2); gfAdd (p->y, p->y, t1); /* deposit the value of x3: */ gfCopy (p->x, t1); } /* ecDouble */
void gfSquareRoot (gfPoint p, lunit b) /* sets p := sqrt(b) = b^(2^(GF_M-1)) */ { int i; gfPoint q; assert (logt != NULL && expt != NULL); assert (p != NULL); q[0] = 1; q[1] = b; if ((GF_M - 1) & 1) { /* GF_M - 1 is odd */ gfSquare (p, q); i = GF_M - 2; } else { /* GF_M - 1 is even */ gfCopy (p, q); i = GF_M - 1; } while (i) { gfSquare (p, p); gfSquare (p, p); i -= 2; } } /* gfSquareRoot */
int gfInvert (gfPoint b, const gfPoint a) /* sets b := a^(-1) mod (x^GF_K + x^GF_T + 1) */ /* warning: a and b must not overlap! */ { gfPoint c, f, g; ltemp x, j, alpha; assert (logt != NULL && expt != NULL); assert (b != NULL); assert (a != NULL); assert (b != a); /* note that this test is not complete */ if (a[0] == 0) { /* a is not invertible */ return 1; } /* initialize b := 1; c := 0; f := p; g := x^GF_K + x^GF_T + 1: */ b[0] = 1; b[1] = 1; c[0] = 0; gfCopy (f, a); gfClear (g); g[0] = GF_K + 1; g[1] = 1; g[GF_T + 1] = 1; g[GF_K + 1] = 1; for (;;) { if (f[0] == 1) { assert (f[1] != 0); gfSmallDiv (b, f[1]); /* destroy potentially sensitive data: */ gfClear (c); gfClear (f); gfClear (g); x = j = alpha = 0; return 0; } if (f[0] < g[0]) { goto SWAP_FG; } SWAP_GF: j = f[0] - g[0]; x = logt[f[f[0]]] - logt[g[g[0]]] + TOGGLE; alpha = expt[x >= TOGGLE ? x - TOGGLE : x]; gfAddMul (f, alpha, j, g); gfAddMul (b, alpha, j, c); } /* basically same code with b,c,f,g swapped */ for (;;) { if (g[0] == 1) { assert (g[1] != 0); gfSmallDiv (c, g[1]); gfCopy (b, c); /* destroy potentially sensitive data: */ gfClear (c); gfClear (f); gfClear (g); x = j = alpha = 0; return 0; } if (g[0] < f[0]) { goto SWAP_GF; } SWAP_FG: j = g[0] - f[0]; x = logt[g[g[0]]] - logt[f[f[0]]] + TOGGLE; alpha = expt[x >= TOGGLE ? x - TOGGLE : x]; gfAddMul (g, alpha, j, f); gfAddMul (c, alpha, j, b); } } /* gfInvert */
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 */
void ecCopy (ecPoint *p, const ecPoint *q) /* sets p := q */ { gfCopy (p->x, q->x); gfCopy (p->y, q->y); } /* ecCopy */