void ec_multiply (ec_point *p, const vl_point k) /* sets p := k*p */ { vl_point h; int z, hi, ki; word16 i; ec_point r; gf_copy (r.x, p->x); p->x[0] = 0; gf_copy (r.y, p->y); p->y[0] = 0; vl_shortmultiply (h, k, 3); z = vl_numbits (h) - 1; /* so vl_takebit (h, z) == 1 */ i = 1; for (;;) { hi = vl_takebit (h, i); ki = vl_takebit (k, i); if (hi == 1 && ki == 0) { ec_add (p, &r); } if (hi == 0 && ki == 1) { ec_sub (p, &r); } if (i >= z) { break; } i++; ec_double (&r); } } /* ec_multiply */
static void niels_to_pt(curve448_point_t e, const niels_t n) { gf_add(e->y, n->b, n->a); gf_sub(e->x, n->b, n->a); gf_mul(e->t, e->y, e->x); gf_copy(e->z, ONE); }
void ec_add (ec_point *p, const ec_point *q) /* sets p := p + q */ { gf_point 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 (gf_equal (p->x, q->x)) { /* either p == q or p == -q: */ if (gf_equal (p->y, q->y)) { /* points are equal; double p: */ ec_double (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): */ gf_add (ty, p->y, q->y); gf_add (tx, p->x, q->x); gf_invert (t, tx); gf_multiply (lambda, ty, t); /* evaluate x3 = lambda^2 + lambda + x1 + x2: */ gf_square (x3, lambda); gf_add (x3, x3, lambda); gf_add (x3, x3, tx); /* evaluate y3 = lambda*(x1 + x3) + x3 + y1: */ gf_add (tx, p->x, x3); gf_multiply (t, lambda, tx); gf_add (t, t, x3); gf_add (p->y, t, p->y); /* deposit the value of x3: */ gf_copy (p->x, x3); } } else { /* just copy q into p: */ gf_copy (p->x, q->x); gf_copy (p->y, q->y); } } } /* ec_add */
static void sub_pniels_from_pt(curve448_point_t p, const pniels_t pn, int before_double) { gf L0; gf_mul(L0, p->z, pn->z); gf_copy(p->z, L0); sub_niels_from_pt(p, pn->n, before_double); }
void ec_sub (ec_point *p, const ec_point *r) /* sets p := p - r */ { ec_point t; gf_copy (t.x, r->x); gf_add (t.y, r->x, r->y); ec_add (p, &t); } /* ec_sub */
/* Inverse. */ static void gf_invert(gf y, const gf x, int assert_nonzero) { mask_t ret; gf t1, t2; gf_sqr(t1, x); /* o^2 */ ret = gf_isr(t2, t1); /* +-1/sqrt(o^2) = +-1/o */ (void)ret; if (assert_nonzero) assert(ret); gf_sqr(t1, t2); gf_mul(t2, t1, x); /* not direct to y in case of alias. */ gf_copy(y, t2); }
void ec_double (ec_point *p) /* sets p := 2*p */ { gf_point lambda, t1, t2; /* evaluate lambda = x + y/x: */ gf_invert (t1, p->x); gf_multiply (lambda, p->y, t1); gf_add (lambda, lambda, p->x); /* evaluate x3 = lambda^2 + lambda: */ gf_square (t1, lambda); gf_add (t1, t1, lambda); /* now t1 = x3 */ /* evaluate y3 = x^2 + lambda*x3 + x3: */ gf_square (p->y, p->x); gf_multiply (t2, lambda, t1); gf_add (p->y, p->y, t2); gf_add (p->y, p->y, t1); /* deposit the value of x3: */ gf_copy (p->x, t1); } /* ec_double */
void ec_copy (ec_point *p, const ec_point *q) /* sets p := q */ { gf_copy (p->x, q->x); gf_copy (p->y, q->y); } /* ec_copy */