-static mp *fsqrt(field *ff, mp *d, mp *x)
-{
- fctx *f = (fctx *)ff;
- d = mpmont_reduce(&f->mm, x);
- d = mp_modsqrt(d, d, f->mm.m);
- return (mpmont_mul(&f->mm, d, d, f->mm.r2));
+static mp *ftpl(field *ff, mp *d, mp *x) {
+ fctx_prime *f = (fctx_prime *)ff; MP_DEST(d, MP_LEN(x) + 1, x->f);
+ MPX_UMULN(d->v, d->vl, x->v, x->vl, 3); d->f &= ~MP_UNDEF;
+ while (MP_CMP(d, >=, f->mm.m)) d = mp_sub(d, d, f->mm.m);
+ return (d);
+}
+
+static mp *fqdl(field *ff, mp *d, mp *x) {
+ fctx_prime *f = (fctx_prime *)ff; d = mp_lsl(d, x, 2);
+ while (MP_CMP(d, >=, f->mm.m)) d = mp_sub(d, d, f->mm.m);
+ return (d);
+}
+
+static mp *fhlv(field *ff, mp *d, mp *x) {
+ fctx_prime *f = (fctx_prime *)ff;
+ if (MP_ZEROP(x)) { MP_COPY(x); MP_DROP(d); return (x); }
+ if (x->v[0] & 1) { d = mp_add(d, x, f->mm.m); x = d; }
+ return (mp_lsr(d, x, 1));