root/include/crypto/internal/blockhash.h
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Handle partial blocks for block hash.
 *
 * Copyright (c) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
 * Copyright (c) 2025 Herbert Xu <herbert@gondor.apana.org.au>
 */

#ifndef _CRYPTO_INTERNAL_BLOCKHASH_H
#define _CRYPTO_INTERNAL_BLOCKHASH_H

#include <linux/string.h>
#include <linux/types.h>

#define BLOCK_HASH_UPDATE_BASE(block_fn, state, src, nbytes, bs, dv,    \
                               buf, buflen)                             \
        ({                                                              \
                typeof(block_fn) *_block_fn = &(block_fn);              \
                typeof(state + 0) _state = (state);                     \
                unsigned int _buflen = (buflen);                        \
                size_t _nbytes = (nbytes);                              \
                unsigned int _bs = (bs);                                \
                const u8 *_src = (src);                                 \
                u8 *_buf = (buf);                                       \
                while ((_buflen + _nbytes) >= _bs) {                    \
                        const u8 *data = _src;                          \
                        size_t len = _nbytes;                           \
                        size_t blocks;                                  \
                        int remain;                                     \
                        if (_buflen) {                                  \
                                remain = _bs - _buflen;                 \
                                memcpy(_buf + _buflen, _src, remain);   \
                                data = _buf;                            \
                                len = _bs;                              \
                        }                                               \
                        remain = len % bs;                              \
                        blocks = (len - remain) / (dv);                 \
                        (*_block_fn)(_state, data, blocks);             \
                        _src += len - remain - _buflen;                 \
                        _nbytes -= len - remain - _buflen;              \
                        _buflen = 0;                                    \
                }                                                       \
                memcpy(_buf + _buflen, _src, _nbytes);                  \
                _buflen += _nbytes;                                     \
        })

#define BLOCK_HASH_UPDATE(block, state, src, nbytes, bs, buf, buflen) \
        BLOCK_HASH_UPDATE_BASE(block, state, src, nbytes, bs, 1, buf, buflen)
#define BLOCK_HASH_UPDATE_BLOCKS(block, state, src, nbytes, bs, buf, buflen) \
        BLOCK_HASH_UPDATE_BASE(block, state, src, nbytes, bs, bs, buf, buflen)

#endif  /* _CRYPTO_INTERNAL_BLOCKHASH_H */