X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a..HEAD:/math/ec-raw.c diff --git a/math/ec-raw.c b/math/ec-raw.c index 54310c8f..497e191b 100644 --- a/math/ec-raw.c +++ b/math/ec-raw.c @@ -32,63 +32,227 @@ /*----- Main code ---------------------------------------------------------*/ -/* --- @ec_putraw@ --- * +/* --- @ec_ec2osp@ --- * * * Arguments: @ec_curve *c@ = elliptic curve + * @unsigned f@ = format flags for output * @buf *b@ = pointer to a buffer * @const ec *p@ = an elliptic curve point * * Returns: Zero on success, nonzero on failure. * * Use: Puts an elliptic curve point to the given buffer using the - * standard uncompressed format described in P1383 and SEC1. + * standard uncompressed format described in P1363 and SEC1. * This requires at most @1 + 2 * c->f->noctets@ space in the - * buffer. We don't do point compression. + * buffer. + * + * Point compression features are determined by @f@ as follows. + * If @EC_CMPR@ is set then point compression is performed and a + * compressed form of the %$y$%-coordinate is contained in the + * first output byte; if @EC_SORT@ is set then P1363a `SORT' + * compression is used, otherwise LSB compression. If + * @EC_EXPLY@ is set, then an explicit %$y$%-coordinate is + * output in full. Otherwise the %$y$%-coordinate is + * suppressed. + * + * Returns failure (@-1@) if the flags are invalid, or if there + * isn't enough space in the output buffer. */ -int ec_putraw(ec_curve *c, buf *b, const ec *p) +int ec_ec2osp(ec_curve *c, unsigned f, buf *b, const ec *p) { octet *q; size_t n; + ec t = EC_INIT; + + /* --- Check the requested flags for sanity --- */ + + if (!f) f = EC_XONLY; + if (f & ~((f & EC_XONLY) ? EC_XONLY : + (f & EC_CMPR) ? (EC_CMPR | EC_EXPLY | EC_SORT) : + (f & EC_EXPLY) ? EC_EXPLY : + 0u)) + return (-1); + + /* --- Point at infinity --- */ if (EC_ATINF(p)) return (buf_putbyte(b, 0)); - buf_putbyte(b, 4); + + /* --- Fix up the format byte, compressing the %$y$%-coordinate --- */ + + if (f & EC_CMPR) { + if (!(f & EC_SORT)) + f |= EC_COMPR(c, p) ? EC_YBIT : 0; + else { + ec_neg(c, &t, p); + f |= MP_CMP(p->y, >, t.y); + EC_DESTROY(&t); + } + } + + /* --- Write the format byte --- */ + + if (buf_putbyte(b, f)) return (-1); + + /* --- Write the %$x$%-coordinate --- */ + n = c->f->noctets; - if ((q = buf_get(b, n * 2)) == 0) return (-1); + if ((q = buf_get(b, n)) == 0) return (-1); mp_storeb(p->x, q, n); - mp_storeb(p->y, q + n, n); + + /* --- Write the %$y$%-coordinate if we need one --- */ + + if (f & EC_EXPLY) { + if ((q = buf_get(b, n)) == 0) return (-1); + mp_storeb(p->y, q, n); + } + + /* --- All done --- */ + return (0); } -/* --- @ec_getraw@ --- * +/* --- @ec_os2ecp@ --- * * - * Arguments: @ec_curve *c@ = elliptic curve + * Arguments: @ec_curve *c = elliptic curve + * @unsigned f@ = format flags for input * @buf *b@ = pointer to a buffer * @ec *d@ = an elliptic curve point * * Returns: Zero on success, nonzero on failure. * * Use: Reads an elliptic curve point from the given buffer using the - * standard uncompressed format described in P1383 and SEC1. - * We don't do point compression. + * standard uncompressed format described in P1363 and SEC1. + * + * Point compression features are determined by @f@ as follows. + * If @EC_LSB@ is set, then accept an LSB-compressed %$y$%- + * coordinate; if @EC_SORT@ is set, then accept a SORT- + * compressed %$y$%-coordinate; if @EC_EXPLY@ is set, then + * accept an explicit %$y$%-coordinate; if @EC_XONLY@ is set + * then accept a bare %$x$%-coordinate (a correct + * %$y$%-coordinate is chosen arbitrarily). Hybrid forms are + * acceptable, and the input is checked to verify that the + * redundant representations are consistent. If no flags are + * set in @f@, then no input (other than the point at infinity) + * will be acceptable. */ -int ec_getraw(ec_curve *c, buf *b, ec *d) +int ec_os2ecp(ec_curve *c, unsigned f, buf *b, ec *d) { const octet *q; size_t n; - int u; + ec t = EC_INIT, tt = EC_INIT; + mp *x = MP_NEW, *y = MP_NEW; + int g, gwant; + int rc = -1; + + /* --- Read the format byte --- */ + + if ((g = buf_getbyte(b)) < 0) goto done; + + /* --- Point at infinity --- */ + + if (!g) { EC_SETINF(d); rc = 0; goto done; } + + /* --- Fetch the %$x$%-coordinate --- */ - if ((u = buf_getbyte(b)) < 0) return (-1); - if (!u) { EC_SETINF(d); return (0); } - if (!(u & 4)) return (-1); n = c->f->noctets; - 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); } +/* --- @ec_putraw@ --- * + * + * Arguments: @ec_curve *c@ = elliptic curve + * @buf *b@ = pointer to a buffer + * @const ec *p@ = an elliptic curve point + * + * Returns: Zero on success, nonzero on failure. + * + * Use: Puts an elliptic curve point to the given buffer using the + * standard uncompressed format described in P1363 and SEC1. + * This requires at most @1 + 2 * c->f->noctets@ space in the + * buffer. We don't do point compression. + */ + +int ec_putraw(ec_curve *c, buf *b, const ec *p) + { return (ec_ec2osp(c, EC_EXPLY, b, p)); } + +/* --- @ec_getraw@ --- * + * + * Arguments: @ec_curve *c@ = elliptic curve + * @buf *b@ = pointer to a buffer + * @ec *d@ = an elliptic curve point + * + * Returns: Zero on success, nonzero on failure. + * + * Use: Reads an elliptic curve point from the given buffer using the + * standard uncompressed format described in P1363 and SEC1. + * We don't do point compression. + */ + +int ec_getraw(ec_curve *c, buf *b, ec *d) + { return (ec_os2ecp(c, EC_LSB | EC_SORT | EC_EXPLY, b, d)); } + /*----- That's all, folks -------------------------------------------------*/