Welcome to little lamb

Code » limb » master » tree

[master] / src / liblimb / chacha20.h / chacha20_crypt.c

/* This file is part of limb                           https://lila.oss/limb
 * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
/* SPDX-License-Identifier: GPL-2.0-only */
#include <string.h>
#include <limb/chacha20.h>
#include <limb/memxor.h>
#include <limb/u32.h>

#define ROUNDS 20
#define LR(a,b) a = (((a) << (b)) | ((a) >> ((-(b) & 31))))
#define QUARTERROUND(out,a,b,c,d) \
    out[a] += out[b]; out[d] ^= out[a]; LR(out[d], 16); \
    out[c] += out[d]; out[b] ^= out[c]; LR(out[b], 12); \
    out[a] += out[b]; out[d] ^= out[a]; LR(out[d],  8); \
    out[c] += out[d]; out[b] ^= out[c]; LR(out[b],  7)

static void
block(u32 out[CHACHA_U32_BLOCK_SIZE], const u32 in[CHACHA_U32_BLOCK_SIZE])
{
    memcpy(out, in, CHACHA_BLOCK_SIZE);
    for (int i = 0; i < ROUNDS; i += 2) {
        QUARTERROUND(out, 0, 4,  8, 12);
        QUARTERROUND(out, 1, 5,  9, 13);
        QUARTERROUND(out, 2, 6, 10, 14);
        QUARTERROUND(out, 3, 7, 11, 15);
        QUARTERROUND(out, 0, 5, 10, 15);
        QUARTERROUND(out, 1, 6, 11, 12);
        QUARTERROUND(out, 2, 7,  8, 13);
        QUARTERROUND(out, 3, 4,  9, 14);
    }

    for (int i = 0; i < CHACHA_U32_BLOCK_SIZE; ++i)
        out[i] += in[i];
    u32pa_le(out, CHACHA_U32_BLOCK_SIZE);
}

void
chacha20_crypt(void *dst_, const void *msg_, size_t mlen, void *ctx_)
{
    chacha20_ctx *ctx = ctx_;
    u8 *dst = dst_;
    const u8 *msg = msg_;
    u32 output[CHACHA_U32_BLOCK_SIZE];

    if (!mlen) return;

    for (;;) {
        size_t l = CHACHA_BLOCK_SIZE - ctx->part;

        block(output, ctx->in);

        if (mlen <= l) {
            memmove(dst, msg, mlen);
            memxor(dst, (u8 *) output + ctx->part, mlen);
            ctx->part = (ctx->part + mlen) % CHACHA_BLOCK_SIZE;
            if (!ctx->part)
                if (!++ctx->in[12]) ++ctx->in[13];
            return;
        }

        memmove(dst, msg, l);
        memxor(dst, (u8 *) output + ctx->part, l);
        mlen -= l;
        dst += l;
        msg += l;
        if (!++ctx->in[12]) ++ctx->in[13];
        ctx->part = 0;
    }
}