- if ((q = buf_get(b, n * 2)) == 0) return (-1);
- EC_DESTROY(d);
- d->x = mp_loadb(MP_NEW, q, n);
- d->y = mp_loadb(MP_NEW, q + n, n);
- d->z = 0;
- return (0);
+ if ((q = buf_get(b, n)) == 0) goto done;
+ x = mp_loadb(x, q, n);
+
+ /* --- If we're compressing then figure out the right value --- *
+ *
+ * Also check that the format is acceptable to the caller.
+ */
+
+ switch (g & ~EC_EXPLY) {
+ case 0:
+ t.x = x; x = MP_NEW; break;
+ case EC_XONLY:
+ gwant = EC_XONLY; goto decompr;
+ case EC_CMPR: case EC_CMPR | EC_YBIT:
+ gwant = EC_LSB; goto decompr;
+ case EC_CMPR | EC_SORT: case EC_CMPR | EC_SORT | EC_YBIT:
+ gwant = EC_SORT; goto decompr;
+ default: goto done;
+ decompr:
+ if (!(f & gwant)) goto done;
+ if (!ec_find(c, &t, x)) goto done;
+ switch (gwant) {
+ case EC_LSB:
+ if (!EC_COMPR(c, &t) != !(g & EC_YBIT)) ec_neg(c, &t, &t);
+ if (!EC_COMPR(c, &t) != !(g & EC_YBIT)) goto done;
+ break;
+ case EC_SORT:
+ ec_neg(c, &tt, &t);
+ if (!MP_CMP(t.y, >, tt.y) != !(g & EC_YBIT)) {
+ if (MP_EQ(t.y, tt.y)) goto done;
+ MP_DROP(t.y); t.y = MP_COPY(tt.y);
+ }
+ break;
+ case EC_XONLY:
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /* --- If an explicit %$y$%-coordinate is specified, read it in --- */
+
+ if (g & EC_EXPLY) {
+ if (!(f & EC_EXPLY)) goto done;
+ if ((q = buf_get(b, n)) == 0) goto done;
+ y = mp_loadb(y, q, n);
+ if (!t.y) t.y = MP_COPY(y);
+ else if (!MP_EQ(y, t.y)) goto done;
+ }
+
+ /* --- We're ready --- */
+
+ EC_COPY(d, &t);
+ rc = 0;
+
+ /* --- Clean up --- */
+
+done:
+ if (x) MP_DROP(x);
+ if (y) MP_DROP(y);
+ if (t.x) MP_DROP(t.x); if (t.y) MP_DROP(t.y);
+ EC_DESTROY(&tt);
+ return (rc);