From: Mark Wooding Date: Fri, 5 Jan 2018 04:34:47 +0000 (+0000) Subject: symm/...: Start deploying the `rsvr' machinery. X-Git-Tag: 2.5.0~14^2~39 X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/commitdiff_plain/6a0eb24483f0e24865f9c93bb1690cdf3f54ead4 symm/...: Start deploying the `rsvr' machinery. --- diff --git a/symm/cfb-def.h b/symm/cfb-def.h index 8040d943..303bc9fd 100644 --- a/symm/cfb-def.h +++ b/symm/cfb-def.h @@ -59,6 +59,10 @@ # include "paranoia.h" #endif +#ifndef CATACOMB_RSVR_H +# include "rsvr.h" +#endif + /*----- Macros ------------------------------------------------------------*/ /* --- @CFB_DEF@ --- * @@ -106,7 +110,7 @@ void pre##_cfbgetiv(const pre##_cfbctx *ctx, void *iv) \ */ \ \ void pre##_cfbsetiv(pre##_cfbctx *ctx, const void *iv) \ - { memcpy(ctx->b, iv, PRE##_BLKSZ); ctx->off = PRE##_BLKSZ; } \ + { memcpy(ctx->b, iv, PRE##_BLKSZ); ctx->off = 0; } \ \ /* --- @pre_cfbbdry@ --- * \ * \ @@ -125,7 +129,7 @@ void pre##_cfbbdry(pre##_cfbctx *ctx) \ BLKC_LOAD(PRE, t, ctx->b); \ pre##_eblk(&ctx->ctx, t, t); \ BLKC_STORE(PRE, ctx->b, t); \ - ctx->off = PRE##_BLKSZ; \ + ctx->off = 0; \ BURN(t); \ } \ \ @@ -140,7 +144,7 @@ void pre##_cfbbdry(pre##_cfbctx *ctx) \ */ \ \ void pre##_cfbsetkey(pre##_cfbctx *ctx, const pre##_ctx *k) \ - { ctx->ctx = *k; ctx->off = PRE##_BLKSZ; } \ + { ctx->ctx = *k; ctx->off = 0; } \ \ /* --- @pre_cfbinit@ --- * \ * \ @@ -182,64 +186,75 @@ void pre##_cfbinit(pre##_cfbctx *ctx, \ * sensitive to block boundaries. \ */ \ \ +static const rsvr_policy pre##_cfbpolicy = { 0, PRE##_BLKSZ, PRE##_BLKSZ }; \ + \ void pre##_cfbencrypt(pre##_cfbctx *ctx, \ const void *src, void *dest, \ size_t sz) \ { \ + rsvr_plan plan; \ const octet *s = src; \ - octet *d = dest; \ - unsigned off = ctx->off; \ + octet *d = dest, *p; \ uint32 t[PRE##_BLKSZ/4]; \ octet y; \ \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) return; \ - \ - /* --- If I can deal with the block from my buffer, do that --- */ \ - \ - if (sz < PRE##_BLKSZ - off) goto small; \ - \ - /* --- Finish off what's left in my buffer --- */ \ - \ - while (off < PRE##_BLKSZ) { \ - y = s ? *s++ : 0; \ - ctx->b[off] ^= y; \ - if (d) *d++ = ctx->b[off]; \ - off++; sz--; \ - } \ - \ - /* --- Main encryption loop --- */ \ - \ + /* Construct a plan and prepare to follow through. */ \ + rsvr_mkplan(&plan, &pre##_cfbpolicy, ctx->off, sz); \ BLKC_LOAD(PRE, t, ctx->b); \ \ - for (;;) { \ - pre##_eblk(&ctx->ctx, t, t); \ - if (sz < PRE##_BLKSZ) break; \ - if (s) { BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ; } \ - if (d) { BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; } \ - sz -= PRE##_BLKSZ; \ + /* Initial portion, fulfilled from the buffer. If the chunk is small \ + * enough, then this will be the only portion. If the buffer is \ + * currently empty, then we must prepare it. \ + */ \ + if (plan.head) { \ + if (!ctx->off) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + } \ + p = ctx->b + ctx->off; ctx->off += plan.head; \ + if (s) while (plan.head--) { y = *s++ ^ *p; *p++ = y; if (d) *d++ = y; } \ + else if (d) { memcpy(d, p, plan.head); d += plan.head; } \ + BLKC_LOAD(PRE, t, ctx->b); \ } \ \ - BLKC_STORE(PRE, ctx->b, t); \ - off = 0; \ - \ - /* --- Tidying up the tail end --- */ \ - \ - if (sz) { \ - small: \ - do { \ - y = s ? *s++ : 0; \ - ctx->b[off] ^= y; \ - if (d) *d++ = ctx->b[off]; \ - off++; sz--; \ - } while (sz); \ + /* If the buffer is all used, then reset it ready for next time. */ \ + ctx->off -= plan.from_rsvr; \ + \ + /* Handle multiple whole blocks. */ \ + if (!d) { \ + if (!s) while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + plan.from_input -= PRE##_BLKSZ; \ + } else while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ + } \ + } else { \ + if (!s) while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ + } else while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ; \ + BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ + } \ } \ \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ + /* Final portion. Note that the buffer must be empty if there is a \ + * tail, since otherwise the input data would have been part of the \ + * head portion instad. */ \ + if (!plan.tail) \ + BLKC_STORE(PRE, ctx->b, t); \ + else { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + p = ctx->b; ctx->off += plan.tail; \ + if (s) while (plan.tail--) { y = *s++ ^ *p; *p++ = y; if (d) *d++ = y; } \ + else if (d) { memcpy(d, p, plan.tail); d += plan.tail; } \ + } \ } \ \ /* --- @pre_cfbdecrypt@ --- * \ @@ -260,53 +275,55 @@ void pre##_cfbdecrypt(pre##_cfbctx *ctx, \ const void *src, void *dest, \ size_t sz) \ { \ + rsvr_plan plan; \ const octet *s = src; \ - octet *d = dest; \ - unsigned off = ctx->off; \ + octet *d = dest, *p; \ uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ/4]; \ octet y; \ \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) return; \ - \ - /* --- If I can deal with the block from my buffer, do that --- */ \ - \ - if (sz < PRE##_BLKSZ - off) goto small; \ - \ - /* --- Finish off what's left in my buffer --- */ \ - \ - while (off < PRE##_BLKSZ) \ - { y = *s++; *d++ = ctx->b[off] ^ y; ctx->b[off++] = y; sz--; } \ + /* Construct a plan and prepare to follow through. */ \ + rsvr_mkplan(&plan, &pre##_cfbpolicy, ctx->off, sz); \ + BLKC_LOAD(PRE, t, ctx->b); \ \ - /* --- Main encryption loop --- */ \ + /* Initial portion, fulfilled from the buffer. If the chunk is small \ + * enough, then this will be the only portion. If the buffer is \ + * currently empty, then we must prepare it. \ + */ \ + if (plan.head) { \ + if (!ctx->off) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + } \ + p = ctx->b + ctx->off; \ + ctx->off += plan.head; \ + while (plan.head--) { y = *s++; *d++ = y ^ *p; *p++ = y; } \ + BLKC_LOAD(PRE, t, ctx->b); \ + } \ \ - BLKC_LOAD(PRE, t, ctx->b); \ + /* If the buffer is all used, then reset it ready for next time. */ \ + ctx->off -= plan.from_rsvr; \ \ - for (;;) { \ + /* Handle multiple whole blocks. */ \ + while (plan.from_input) { \ pre##_eblk(&ctx->ctx, t, t); \ - if (sz < PRE##_BLKSZ) break; \ BLKC_LOAD(PRE, u, s); s += PRE##_BLKSZ; \ BLKC_XSTORE(PRE, d, t, u); d += PRE##_BLKSZ; \ BLKC_MOVE(PRE, t, u); \ - sz -= PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ } \ \ - BLKC_STORE(PRE, ctx->b, t); \ - off = 0; \ - \ - /* --- Tidying up the tail end --- */ \ - \ - if (sz) { \ - small: \ - do { y = *s++; *d++ = ctx->b[off] ^ y; ctx->b[off++] = y; sz--; } \ - while (sz); \ + /* Final portion. Note that the buffer must be empty if there is a \ + * tail, since otherwise the input data would have been part of the \ + * head portion instad. */ \ + if (!plan.tail) \ + BLKC_STORE(PRE, ctx->b, t); \ + else { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + p = ctx->b; \ + ctx->off += plan.tail; \ + while (plan.tail--) { y = *s++; *d++ = y ^ *p; *p++ = y; } \ } \ - \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ } \ \ /* --- Generic cipher interface --- */ \ diff --git a/symm/chacha.c b/symm/chacha.c index a554c190..37c6cfbb 100644 --- a/symm/chacha.c +++ b/symm/chacha.c @@ -41,6 +41,7 @@ #include "grand.h" #include "keysz.h" #include "paranoia.h" +#include "rsvr.h" /*----- Global variables --------------------------------------------------*/ @@ -264,6 +265,8 @@ uint32 chacha_tell_ietf(chacha_ctx *ctx) * to @dest@. */ +static const rsvr_policy policy = { 0, CHACHA_OUTSZ, CHACHA_OUTSZ }; + #define CHACHA_ENCRYPT(r, ctx, src, dest, sz) \ chacha##r##_encrypt(ctx, src, dest, sz) #define DEFENCRYPT(r) \ @@ -273,41 +276,40 @@ uint32 chacha_tell_ietf(chacha_ctx *ctx) chacha_matrix b; \ const octet *s = src; \ octet *d = dest; \ - size_t n; \ + rsvr_plan plan; \ kludge64 pos, delta; \ \ - SALSA20_OUTBUF(ctx, d, s, sz); \ - if (!sz) return; \ - \ - if (!dest) { \ - n = sz/CHACHA_OUTSZ; \ - pos = chacha_tellu64(ctx); \ - ASSIGN64(delta, n); \ - ADD64(pos, pos, delta); \ - chacha_seeku64(ctx, pos); \ - sz = sz%CHACHA_OUTSZ; \ - } else if (!src) { \ - while (sz >= CHACHA_OUTSZ) { \ - core(r, ctx->a, b); \ - CHACHA_STEP(ctx->a); \ - SALSA20_GENFULL(b, d); \ - sz -= CHACHA_OUTSZ; \ + rsvr_mkplan(&plan, &policy, ctx->off, sz); \ + \ + if (plan.head) { \ + if (!ctx->off) { \ + core(r, ctx->a, b); CHACHA_STEP(ctx->a); \ + SALSA20_PREPBUF(ctx, b); \ } \ - } else { \ - while (sz >= CHACHA_OUTSZ) { \ - core(r, ctx->a, b); \ - CHACHA_STEP(ctx->a); \ - SALSA20_MIXFULL(b, d, s); \ - sz -= CHACHA_OUTSZ; \ + SALSA20_OUTBUF(ctx, d, s, plan.head); \ + } \ + \ + ctx->off -= plan.from_rsvr; \ + \ + if (!d) { \ + if (plan.from_input) { \ + pos = chacha_tellu64(ctx); \ + ASSIGN64(delta, plan.from_input/SALSA20_OUTSZ); \ + ADD64(pos, pos, delta); \ + chacha_seeku64(ctx, pos); \ } \ + } else if (!s) while (plan.from_input) { \ + core(r, ctx->a, b); CHACHA_STEP(ctx->a); \ + SALSA20_GENFULL(b, d); plan.from_input -= CHACHA_OUTSZ; \ + } else while (plan.from_input) { \ + core(r, ctx->a, b); CHACHA_STEP(ctx->a); \ + SALSA20_MIXFULL(b, d, s); plan.from_input -= CHACHA_OUTSZ; \ } \ \ - if (sz) { \ - core(r, ctx->a, b); \ - CHACHA_STEP(ctx->a); \ + if (plan.tail) { \ + core(r, ctx->a, b); CHACHA_STEP(ctx->a); \ SALSA20_PREPBUF(ctx, b); \ - SALSA20_OUTBUF(ctx, d, s, sz); \ - assert(!sz); \ + SALSA20_OUTBUF(ctx, d, s, plan.tail); \ } \ } CHACHA_VARS(DEFENCRYPT) diff --git a/symm/counter-def.h b/symm/counter-def.h index 8ec798d6..3c949c7a 100644 --- a/symm/counter-def.h +++ b/symm/counter-def.h @@ -56,6 +56,10 @@ # include "paranoia.h" #endif +#ifndef CATACOMB_RSVR_H +# include "rsvr.h" +#endif + /*----- Macros ------------------------------------------------------------*/ /* --- @COUNTER_DEF@ --- * @@ -167,61 +171,66 @@ void pre##_counterinit(pre##_counterctx *ctx, \ * use the cipher as a random data generator. \ */ \ \ +static const rsvr_policy pre##_counterpolicy = \ + { 0, PRE##_BLKSZ, PRE##_BLKSZ }; \ + \ void pre##_counterencrypt(pre##_counterctx *ctx, \ const void *src, void *dest, \ size_t sz) \ { \ - const octet *s = src; \ + rsvr_plan plan; \ + const octet *s = src, *p; \ octet *d = dest; \ - unsigned off = ctx->off; \ - uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ/4]; \ - octet y; \ - \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) return; \ - \ - /* --- If I can deal with the block from my buffer, do that --- */ \ - \ - if (sz < PRE##_BLKSZ - off) goto small; \ - \ - /* --- Finish off what's left in my buffer --- */ \ - \ - if (!d) sz -= PRE##_BLKSZ - off; \ - else while (off < PRE##_BLKSZ) \ - { y = s ? *s++ : 0; *d++ = ctx->b[off++] ^ y; sz--; } \ - \ - /* --- Main encryption loop --- */ \ - \ - for (;;) { \ - pre##_eblk(&ctx->ctx, ctx->c, t); \ - BLKC_STEP(PRE, ctx->c); \ - if (sz < PRE##_BLKSZ) break; \ - if (!d) /* do nothing */; \ - else if (!s) { BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; } \ - else { \ - BLKC_LOAD(PRE, u, s); s += PRE##_BLKSZ; \ - BLKC_XSTORE(PRE, d, t, u); d += PRE##_BLKSZ; \ + uint32 t[PRE##_BLKSZ/4]; \ + \ + /* Construct a plan and prepare to follow through. */ \ + rsvr_mkplan(&plan, &pre##_counterpolicy, ctx->off, sz); \ + \ + /* Initial portion, fulfilled from the buffer. If the chunk is small \ + * enough, then this will be the only portion. If the buffer is \ + * currently empty, then we must prepare it. \ + */ \ + if (plan.head) { \ + if (!ctx->off) { \ + pre##_eblk(&ctx->ctx, ctx->c, t); BLKC_STEP(PRE, ctx->c); \ + BLKC_STORE(PRE, ctx->b, t); \ } \ - sz -= PRE##_BLKSZ; \ + p = ctx->b + ctx->off; ctx->off += plan.head; \ + if (!d) /* nothing to do */; \ + else if (!s) { memcpy(d, p, plan.head); d += plan.head; } \ + else while (plan.head--) *d++ = *s++ ^ *p++; \ } \ \ - BLKC_STORE(PRE, ctx->b, t); \ - off = 0; \ - \ - /* --- Tidying up the tail end --- */ \ - \ - if (sz) { \ - small: \ - if (!d) off += sz; \ - else do { y = s ? *s++ : 0; *d++ = ctx->b[off++] ^ y; sz--; } \ - while (sz); \ + /* If the buffer is all used, then reset it ready for next time. */ \ + ctx->off -= plan.from_rsvr; \ + \ + /* Handle multiple whole blocks. */ \ + if (!d) \ + BLKC_ADD(PRE, ctx->c, plan.from_input/PRE##_BLKSZ); \ + else if (!s) while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, ctx->c, t); BLKC_STEP(PRE, ctx->c); \ + BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ + } else while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, ctx->c, t); BLKC_STEP(PRE, ctx->c); \ + BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ; \ + BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ } \ \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ + /* Final portion. Note that the buffer must be empty if there is a \ + * tail, since otherwise the input data would have been part of the \ + * head portion instad. */ \ + if (!plan.tail) \ + BLKC_STORE(PRE, ctx->b, t); \ + else { \ + pre##_eblk(&ctx->ctx, ctx->c, t); BLKC_STEP(PRE, ctx->c); \ + BLKC_STORE(PRE, ctx->b, t); \ + p = ctx->b; ctx->off += plan.tail; \ + if (!d) /* nothing to do */; \ + else if (!s) { memcpy(d, p, plan.tail); d += plan.tail; } \ + else while (plan.tail--) *d++ = *s++ ^ *p++; \ + } \ } \ \ /* --- Generic cipher interface --- */ \ diff --git a/symm/hash.h b/symm/hash.h index 420277d2..3d0c1179 100644 --- a/symm/hash.h +++ b/symm/hash.h @@ -38,6 +38,10 @@ #include +#ifndef CATACOMB_RSVR_H +# include "rsvr.h" +#endif + /*----- Macros ------------------------------------------------------------*/ /* --- @HASH_BUFFER@ --- * @@ -58,9 +62,10 @@ #define HASH_BUFFER(PRE, pre, ictx, ibuf, isz) do { \ pre##_ctx *_bctx = (ictx); \ size_t _bsz = (isz); \ - const octet *_bbuf = (octet *)(ibuf); \ - size_t _s; \ + const octet *_bbuf = (octet *)(ibuf), *_p; \ + static const rsvr_policy _pol = { 0, PRE##_BUFSZ, PRE##_BUFSZ }; \ uint32 _l, _h; \ + rsvr_state _st; \ \ /* --- Add on the size done so far --- * \ * \ @@ -72,33 +77,11 @@ _bctx->nl += _l; if (_bctx->nl < _l || _bctx->nl & ~(uint32)MASK32) _h++; \ _bctx->nh += _h; \ \ - /* --- Handle very small contributions --- */ \ - \ - if (_bctx->off + _bsz < PRE##_BUFSZ) \ - { memcpy(_bctx->buf + _bctx->off, _bbuf, _bsz); _bctx->off += _bsz; } \ - else { \ - \ - /* --- Handle an initial partial buffer --- */ \ - \ - if (_bctx->off) { \ - _s = PRE##_BUFSZ - _bctx->off; \ - memcpy(_bctx->buf + _bctx->off, _bbuf, _s); \ - pre##_compress(_bctx, _bctx->buf); \ - _bsz -= _s; _bbuf += _s; \ - } \ + /* --- Accumulate the input data --- */ \ \ - /* --- Do whole buffers while we can --- */ \ - \ - while (_bsz >= PRE##_BUFSZ) { \ - pre##_compress(_bctx, _bbuf); \ - _bsz -= PRE##_BUFSZ; _bbuf += PRE##_BUFSZ; \ - } \ - \ - /* --- And wrap up at the end --- */ \ - \ - if (_bsz) memcpy(_bctx->buf, _bbuf, _bsz); \ - _bctx->off = _bsz; \ - } \ + rsvr_setup(&_st, &_pol, _bctx->buf, &_bctx->off, _bbuf, _bsz); \ + RSVR_DO(&_st) while ((_p = RSVR_NEXT(&_st, PRE##_BUFSZ)) != 0) \ + pre##_compress(_bctx, _p); \ } while (0) /* --- @HASH_PAD@ --- * diff --git a/symm/ofb-def.h b/symm/ofb-def.h index 10f799c3..e065f08a 100644 --- a/symm/ofb-def.h +++ b/symm/ofb-def.h @@ -56,6 +56,10 @@ # include "paranoia.h" #endif +#ifndef CATACOMB_RSVR_H +# include "rsvr.h" +#endif + /*----- Macros ------------------------------------------------------------*/ /* --- @OFB_DEF@ --- * @@ -103,7 +107,7 @@ void pre##_ofbgetiv(const pre##_ofbctx *ctx, void *iv) \ */ \ \ void pre##_ofbsetiv(pre##_ofbctx *ctx, const void *iv) \ - { memcpy(ctx->b, iv, PRE##_BLKSZ); ctx->off = PRE##_BLKSZ; } \ + { memcpy(ctx->b, iv, PRE##_BLKSZ); ctx->off = 0; } \ \ /* --- @pre_ofbbdry@ --- * \ * \ @@ -122,7 +126,7 @@ void pre##_ofbbdry(pre##_ofbctx *ctx) \ BLKC_LOAD(PRE, t, ctx->b); \ pre##_eblk(&ctx->ctx, t, t); \ BLKC_STORE(PRE, ctx->b, t); \ - ctx->off = PRE##_BLKSZ; \ + ctx->off = 0; \ BURN(t); \ } \ \ @@ -181,62 +185,67 @@ void pre##_ofbinit(pre##_ofbctx *ctx, \ * cipher as a random data generator. \ */ \ \ +static const rsvr_policy pre##_ofbpolicy = { 0, PRE##_BLKSZ, PRE##_BLKSZ }; \ + \ void pre##_ofbencrypt(pre##_ofbctx *ctx, \ const void *src, void *dest, \ size_t sz) \ { \ - const octet *s = src; \ + rsvr_plan plan; \ + const octet *s = src, *p; \ octet *d = dest; \ - unsigned off = ctx->off; \ uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ/4]; \ - octet y; \ - \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) return; \ - \ - /* --- If I can deal with the block from my buffer, do that --- */ \ - \ - if (sz < PRE##_BLKSZ - off) goto small; \ - \ - /* --- Finish off what's left in my buffer --- */ \ - \ - if (!d) sz -= PRE##_BLKSZ - off; \ - else while (off < PRE##_BLKSZ) \ - { y = s ? *s++ : 0; *d++ = ctx->b[off++] ^ y; sz--; } \ - \ - /* --- Main encryption loop --- */ \ \ + /* Construct a plan and prepare to follow through. */ \ + rsvr_mkplan(&plan, &pre##_ofbpolicy, ctx->off, sz); \ BLKC_LOAD(PRE, t, ctx->b); \ \ - for (;;) { \ - pre##_eblk(&ctx->ctx, t, t); \ - if (sz < PRE##_BLKSZ) break; \ - if (!d) /* do nothing */; \ - else if (!s) { BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; } \ - else { \ - BLKC_LOAD(PRE, u, s); s += PRE##_BLKSZ; \ - BLKC_XSTORE(PRE, d, t, u); d += PRE##_BLKSZ; \ + /* Initial portion, fulfilled from the buffer. If the chunk is small \ + * enough, then this will be the only portion. If the buffer is \ + * currently empty, then we must prepare it. \ + */ \ + if (plan.head) { \ + if (!ctx->off) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ } \ - sz -= PRE##_BLKSZ; \ + p = ctx->b + ctx->off; ctx->off += plan.head; \ + if (!d) /* nothing to do */; \ + else if (!s) { memcpy(d, p, plan.head); d += plan.head; } \ + else while (plan.head--) *d++ = *s++ ^ *p++; \ } \ \ - BLKC_STORE(PRE, ctx->b, t); \ - off = 0; \ + /* If the buffer is all used, then reset it ready for next time. */ \ + ctx->off -= plan.from_rsvr; \ \ - /* --- Tidying up the tail end --- */ \ - \ - if (sz) { \ - small: \ - if (!d) off += sz; \ - else do { y = s ? *s++ : 0; *d++ = ctx->b[off++] ^ y; sz--; } \ - while (sz); \ + /* Handle multiple whole blocks. */ \ + if (!d) while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + plan.from_input -= PRE##_BLKSZ; \ + } else if (!s) while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ + } else while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_LOAD(PRE, u, s); s += PRE##_BLKSZ; \ + BLKC_XSTORE(PRE, d, t, u); d += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ } \ \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ + /* Final portion. Note that the buffer must be empty if there is a \ + * tail, since otherwise the input data would have been part of the \ + * head portion instad. */ \ + if (!plan.tail) \ + BLKC_STORE(PRE, ctx->b, t); \ + else { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + p = ctx->b; ctx->off += plan.tail; \ + if (!d) /* nothing to do */; \ + else if (!s) { memcpy(d, p, plan.tail); d += plan.tail; } \ + else while (plan.tail--) *d++ = *s++ ^ *p++; \ + } \ } \ \ /* --- Generic cipher interface --- */ \ diff --git a/symm/poly1305.c b/symm/poly1305.c index d237d4e7..c4a88a84 100644 --- a/symm/poly1305.c +++ b/symm/poly1305.c @@ -33,6 +33,7 @@ #include #include "poly1305.h" +#include "rsvr.h" /*----- Global variables --------------------------------------------------*/ @@ -536,28 +537,15 @@ static void update_full(poly1305_ctx *ctx, const octet *p) ctx->count++; } +static const rsvr_policy pol = { 0, 16, 16 }; + void poly1305_hash(poly1305_ctx *ctx, const void *p, size_t sz) { - const octet *pp = p; - size_t n; - - if (ctx->nbuf) { - if (sz < 16 - ctx->nbuf) { - memcpy(ctx->buf + ctx->nbuf, p, sz); - ctx->nbuf += sz; - return; - } - n = 16 - ctx->nbuf; - memcpy(ctx->buf + ctx->nbuf, pp, n); - update_full(ctx, ctx->buf); - pp += n; sz -= n; - } - while (sz >= 16) { - update_full(ctx, pp); - pp += 16; sz -= 16; - } - if (sz) memcpy(ctx->buf, pp, sz); - ctx->nbuf = sz; + rsvr_state st; + const octet *q = p; + + rsvr_setup(&st, &pol, &ctx->buf, &ctx->nbuf, p, sz); + RSVR_DO(&st) while ((q = RSVR_NEXT(&st, 16)) != 0) update_full(ctx, q); } /* --- @poly1305_flush@ --- * diff --git a/symm/salsa20-core.h b/symm/salsa20-core.h index 352fec3f..e64e7331 100644 --- a/symm/salsa20-core.h +++ b/symm/salsa20-core.h @@ -174,12 +174,13 @@ * @n@ is decreased appropriately. */ #define SALSA20_OUTBUF(ctx, d, s, n) do { \ - size_t _n = (n), _left = SALSA20_OUTSZ - (ctx)->off; \ - if (_n > _left) _n = _left; \ - (n) -= _n; \ - if (!(d)) (ctx)->off += _n; \ - else if (s) while (_n--) *(d)++ = (ctx)->b[(ctx)->off++] ^ *(s)++; \ - else while (_n--) *(d)++ = (ctx)->b[(ctx)->off++]; \ + const octet *_p = (ctx)->b + (ctx)->off; \ + size_t _n = (n); \ + \ + (ctx)->off += _n; \ + if (!(d)) /* nothing to do */; \ + else if (!(s)) { memcpy((d), _p, _n); (d) += _n; } \ + else while (_n--) *(d)++ = *(s)++ ^ *_p++; \ } while (0) /*----- Variants and naming -----------------------------------------------*/ diff --git a/symm/salsa20.c b/symm/salsa20.c index 64ae8ae3..a055f3b1 100644 --- a/symm/salsa20.c +++ b/symm/salsa20.c @@ -39,6 +39,7 @@ #include "grand.h" #include "keysz.h" #include "paranoia.h" +#include "rsvr.h" #include "salsa20.h" #include "salsa20-core.h" @@ -233,7 +234,7 @@ void salsa20_seek(salsa20_ctx *ctx, unsigned long i) void salsa20_seeku64(salsa20_ctx *ctx, kludge64 i) { ctx->a[8] = LO64(i); ctx->a[5] = HI64(i); - ctx->off = SALSA20_OUTSZ; + ctx->off = 0; } void salsa20_seek_ietf(salsa20_ctx *ctx, uint32 i) @@ -273,6 +274,8 @@ uint32 salsa20_tell_ietf(salsa20_ctx *ctx) * to @dest@. */ +static const rsvr_policy policy = { 0, SALSA20_OUTSZ, SALSA20_OUTSZ }; + #define SALSA20_ENCRYPT(r, ctx, src, dest, sz) \ SALSA20_DECOR(salsa20, r, _encrypt)(ctx, src, dest, sz) #define DEFENCRYPT(r) \ @@ -282,41 +285,40 @@ uint32 salsa20_tell_ietf(salsa20_ctx *ctx) salsa20_matrix b; \ const octet *s = src; \ octet *d = dest; \ - size_t n; \ + rsvr_plan plan; \ kludge64 pos, delta; \ \ - SALSA20_OUTBUF(ctx, d, s, sz); \ - if (!sz) return; \ + rsvr_mkplan(&plan, &policy, ctx->off, sz); \ \ - if (!dest) { \ - n = sz/SALSA20_OUTSZ; \ - pos = salsa20_tellu64(ctx); \ - ASSIGN64(delta, n); \ - ADD64(pos, pos, delta); \ - salsa20_seeku64(ctx, pos); \ - sz = sz%SALSA20_OUTSZ; \ - } else if (!src) { \ - while (sz >= SALSA20_OUTSZ) { \ - core(r, ctx->a, b); \ - SALSA20_STEP(ctx->a); \ - SALSA20_GENFULL(b, d); \ - sz -= SALSA20_OUTSZ; \ + if (plan.head) { \ + if (!ctx->off) { \ + core(r, ctx->a, b); SALSA20_STEP(ctx->a); \ + SALSA20_PREPBUF(ctx, b); \ } \ - } else { \ - while (sz >= SALSA20_OUTSZ) { \ - core(r, ctx->a, b); \ - SALSA20_STEP(ctx->a); \ - SALSA20_MIXFULL(b, d, s); \ - sz -= SALSA20_OUTSZ; \ + SALSA20_OUTBUF(ctx, d, s, plan.head); \ + } \ + \ + ctx->off -= plan.from_rsvr; \ + \ + if (!d) { \ + if (plan.from_input) { \ + pos = salsa20_tellu64(ctx); \ + ASSIGN64(delta, plan.from_input/SALSA20_OUTSZ); \ + ADD64(pos, pos, delta); \ + salsa20_seeku64(ctx, pos); \ } \ + } else if (!s) while (plan.from_input) { \ + core(r, ctx->a, b); SALSA20_STEP(ctx->a); \ + SALSA20_GENFULL(b, d); plan.from_input -= SALSA20_OUTSZ; \ + } else while (plan.from_input) { \ + core(r, ctx->a, b); SALSA20_STEP(ctx->a); \ + SALSA20_MIXFULL(b, d, s); plan.from_input -= SALSA20_OUTSZ; \ } \ \ - if (sz) { \ - core(r, ctx->a, b); \ - SALSA20_STEP(ctx->a); \ + if (plan.tail) { \ + core(r, ctx->a, b); SALSA20_STEP(ctx->a); \ SALSA20_PREPBUF(ctx, b); \ - SALSA20_OUTBUF(ctx, d, s, sz); \ - assert(!sz); \ + SALSA20_OUTBUF(ctx, d, s, plan.tail); \ } \ } SALSA20_VARS(DEFENCRYPT)