aboutsummaryrefslogtreecommitdiffstats
path: root/digest.c
diff options
context:
space:
mode:
Diffstat (limited to 'digest.c')
-rw-r--r--digest.c147
1 files changed, 120 insertions, 27 deletions
diff --git a/digest.c b/digest.c
index 902d549..c7302f6 100644
--- a/digest.c
+++ b/digest.c
@@ -232,51 +232,56 @@ libkeccak_to_lane64(register const unsigned char *restrict message, register siz
/**
- * pad 10*1
+ * Right-pad message with a 10*1-pad
*
- * @param state The hashing state, `state->M` and `state->mptr` will be updated,
- * `state->M` should have `state->r / 8` bytes left over at the end
- * @param bits The number of bits in the end of the message that does not make a whole byte
+ * @param r Should be `state->r` where `state` is the hashing state
+ * @param msg The message to append padding to; should have `r / 8`
+ * extra bytes allocated at the end for the function to
+ * write the pad to
+ * @param msglen The length of the message to append padding to
+ * @param bits The number of bits in the end of the message that does not make a whole byte
+ * @return The length of the message after padding
*/
LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__, __gnu_inline__)))
-static inline void
-libkeccak_pad10star1(register struct libkeccak_state *restrict state, register size_t bits)
+static inline size_t
+libkeccak_pad10star1(register size_t r, unsigned char *msg, size_t msglen, register size_t bits)
{
- register size_t r = (size_t)(state->r);
- register size_t nrf = state->mptr - !!bits;
+ register size_t nrf = msglen - !!bits;
register size_t len = (nrf << 3) | bits;
register size_t ll = len % r;
- register unsigned char b = (unsigned char)(bits ? (state->M[nrf] | (1 << bits)) : 1);
+ register unsigned char b = (unsigned char)(bits ? (msg[nrf] | (1 << bits)) : 1);
if (r - 8 <= ll && ll <= r - 2) {
- state->M[nrf] = (unsigned char)(b ^ 0x80);
- state->mptr = nrf + 1;
+ msg[nrf] = (unsigned char)(b ^ 0x80);
+ msglen = nrf + 1;
} else {
len = ++nrf << 3;
len = (len - (len % r) + (r - 8)) >> 3;
- state->mptr = len + 1;
+ msglen = len + 1;
- state->M[nrf - 1] = b;
- __builtin_memset(state->M + nrf, 0, (len - nrf) * sizeof(char));
- state->M[len] = (unsigned char)0x80;
+ msg[nrf - 1] = b;
+ __builtin_memset(&msg[nrf], 0, (len - nrf) * sizeof(char));
+ msg[len] = (unsigned char)0x80;
}
+ return msglen;
}
/**
* Perform the absorption phase
*
- * @param state The hashing state
- * @param len The number of bytes from `state->M` to absorb
+ * @param state The hashing state
+ * @param message The bytes to absorb
+ * @param len The number of bytes from `message` to absorb
*/
LIBKECCAK_GCC_ONLY(__attribute__((__nonnull__, __nothrow__)))
static void
-libkeccak_absorption_phase(register struct libkeccak_state *restrict state, register size_t len)
+libkeccak_absorption_phase(register struct libkeccak_state *restrict state,
+ register const unsigned char *restrict message, register size_t len)
{
register long int rr = state->r >> 3;
register long int ww = state->w >> 3;
register long int n = (long)len / rr;
- register const unsigned char *restrict message = state->M;
if (__builtin_expect(ww >= 8, 1)) { /* ww > 8 is impossible, it is just for optimisation possibilities. */
while (n--) {
#define X(N) state->S[N] ^= libkeccak_to_lane64(message, len, rr, (size_t)(LANE_TRANSPOSE_MAP[N] * 8));
@@ -335,6 +340,28 @@ libkeccak_squeezing_phase(register struct libkeccak_state *restrict state, long
/**
* Absorb more of the message to the Keccak sponge
+ * without copying the data to an internal buffer
+ *
+ * It is safe run zero-copy functions before non-zero-copy
+ * functions for the same state, running zero-copy functions
+ * after non-zero-copy functions on the other hand can
+ * cause the message to be misread
+ *
+ * @param state The hashing state
+ * @param msg The partial message
+ * @param msglen The length of the partial message; must be a
+ * multiple of `libkeccak_zerocopy_chunksize(state)`
+ * (undefined behaviour otherwise)
+ */
+void
+libkeccak_zerocopy_update(struct libkeccak_state *restrict state, const void *restrict msg, size_t msglen)
+{
+ libkeccak_absorption_phase(state, msg, msglen);
+}
+
+
+/**
+ * Absorb more of the message to the Keccak sponge
* without wiping sensitive data when possible
*
* @param state The hashing state
@@ -361,10 +388,10 @@ libkeccak_fast_update(struct libkeccak_state *restrict state, const void *restri
__builtin_memcpy(state->M + state->mptr, msg, msglen * sizeof(char));
state->mptr += msglen;
len = state->mptr;
- len -= state->mptr % (size_t)((state->r * state->b) >> 3);
+ len -= state->mptr % (size_t)(state->r >> 3);
state->mptr -= len;
- libkeccak_absorption_phase(state, len);
+ libkeccak_absorption_phase(state, state->M, len);
__builtin_memmove(state->M, state->M + len, state->mptr * sizeof(char));
return 0;
@@ -401,10 +428,10 @@ libkeccak_update(struct libkeccak_state *restrict state, const void *restrict ms
__builtin_memcpy(state->M + state->mptr, msg, msglen * sizeof(char));
state->mptr += msglen;
len = state->mptr;
- len -= state->mptr % (size_t)((state->r * state->b) >> 3);
+ len -= state->mptr % (size_t)(state->r >> 3);
state->mptr -= len;
- libkeccak_absorption_phase(state, len);
+ libkeccak_absorption_phase(state, state->M, len);
__builtin_memmove(state->M, state->M + len, state->mptr * sizeof(char));
return 0;
@@ -413,6 +440,72 @@ libkeccak_update(struct libkeccak_state *restrict state, const void *restrict ms
/**
* Absorb the last part of the message and squeeze the Keccak sponge
+ * without copying the data to an internal buffer
+ *
+ * It is safe run zero-copy functions before non-zero-copy
+ * functions for the same state, running zero-copy functions
+ * after non-zero-copy functions on the other hand can
+ * cause the message to be misread
+ *
+ * @param state The hashing state
+ * @param msg_ The rest of the message; will be edited; extra memory
+ * shall be allocated such that `suffix` and a 10*1 pad (which
+ * is at least 2 bits long) can be added in a why the makes it's
+ * length a multiple of `libkeccak_zerocopy_chunksize(state)`
+ * @param msglen The length of the partial message
+ * @param bits The number of bits at the end of the message not covered by `msglen`
+ * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination
+ * @param hashsum Output parameter for the hashsum, may be `NULL`
+ */
+void
+libkeccak_zerocopy_digest(struct libkeccak_state *restrict state, void *restrict msg_, size_t msglen,
+ size_t bits, const char *restrict suffix, void *restrict hashsum)
+{
+ unsigned char *restrict msg = msg_;
+ auto unsigned char *restrict new;
+ register long int rr = state->r >> 3;
+ auto size_t suffix_len = suffix ? __builtin_strlen(suffix) : 0;
+ register size_t ext;
+ register long int i;
+
+ if (!msg) {
+ msglen = 0;
+ bits = 0;
+ } else {
+ msglen += bits >> 3;
+ bits &= 7;
+ }
+
+ if (bits)
+ msg[msglen] = msg[msglen] & (unsigned char)((1 << bits) - 1);
+ if (__builtin_expect(!!suffix_len, 1)) {
+ if (!bits)
+ msg[msglen] = 0;
+ while (suffix_len--) {
+ msg[msglen] |= (unsigned char)((*suffix++ & 1) << bits++);
+ if (bits == 8) {
+ bits = 0;
+ msg[++msglen] = 0;
+ }
+ }
+ }
+ if (bits)
+ msglen++;
+
+ msglen = libkeccak_pad10star1((size_t)state->r, msg, msglen, bits);
+ libkeccak_absorption_phase(state, msg, msglen);
+
+ if (hashsum) {
+ libkeccak_squeezing_phase(state, rr, (state->n + 7) >> 3, state->w >> 3, hashsum);
+ } else {
+ for (i = (state->n - 1) / state->r; i--;)
+ libkeccak_f(state);
+ }
+}
+
+
+/**
+ * Absorb the last part of the message and squeeze the Keccak sponge
* without wiping sensitive data when possible
*
* @param state The hashing state
@@ -473,8 +566,8 @@ libkeccak_fast_digest(struct libkeccak_state *restrict state, const void *restri
if (bits)
state->mptr++;
- libkeccak_pad10star1(state, bits);
- libkeccak_absorption_phase(state, state->mptr);
+ state->mptr = libkeccak_pad10star1((size_t)state->r, state->M, state->mptr, bits);
+ libkeccak_absorption_phase(state, state->M, state->mptr);
if (hashsum) {
libkeccak_squeezing_phase(state, rr, (state->n + 7) >> 3, state->w >> 3, hashsum);
@@ -551,8 +644,8 @@ libkeccak_digest(struct libkeccak_state *restrict state, const void *restrict ms
if (bits)
state->mptr++;
- libkeccak_pad10star1(state, bits);
- libkeccak_absorption_phase(state, state->mptr);
+ state->mptr = libkeccak_pad10star1((size_t)state->r, state->M, state->mptr, bits);
+ libkeccak_absorption_phase(state, state->M, state->mptr);
if (hashsum) {
libkeccak_squeezing_phase(state, rr, (state->n + 7) >> 3, state->w >> 3, hashsum);