diff options
Diffstat (limited to 'libkeccak_cshake_initialise.c')
-rw-r--r-- | libkeccak_cshake_initialise.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/libkeccak_cshake_initialise.c b/libkeccak_cshake_initialise.c new file mode 100644 index 0000000..dd47fc6 --- /dev/null +++ b/libkeccak_cshake_initialise.c @@ -0,0 +1,275 @@ +#include <stdio.h> +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Encode a number in big-endian with a size prefix + * + * @param state The hashing state the feed the number to + * @param buf Buffer that is at least `byterate` bytes large + * @param byterate The byterate of the hashing algorithm + * @param value The number to send to the hashing sponge + * @param off Current offset in `buf` + * @return New offset in `buf` + */ +static size_t +encode_left(struct libkeccak_state *restrict state, uint8_t *restrict buf, size_t byterate, size_t value, size_t off) +{ + size_t x, n, j, i = off; + + for (x = value, n = 0; x; x >>= 8) + n += 1; + if (!n) + n = 1; + buf[i++] = (uint8_t)n; + if (i == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + i = 0; + } + + for (j = 0; j < n;) { + buf[i++] = (uint8_t)(value >> ((n - ++j) << 3)); + if (i == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + i = 0; + } + } + + return i; +} + + +/** + * Encode a number in big-endian with a size prefix + * + * @param state The hashing state the feed the number to + * @param buf Buffer that is at least `byterate` bytes large + * @param byterate The byterate of the hashing algorithm + * @param value The number to send to the hashing sponge + * @param off Current offset in `buf` + * @param bitoff The number of bits to shift the encoded message left + * @return New offset in `buf` + */ +static size_t +encode_left_shifted(struct libkeccak_state *restrict state, uint8_t *restrict buf, + size_t byterate, size_t value, size_t off, size_t bitoff) +{ + size_t x, n, j, i = off; + uint16_t v; + + for (x = value, n = 0; x; x >>= 8) + n += 1; + if (!n) + n = 1; + v = (uint16_t)((n & 255UL) << bitoff); + buf[i++] |= (uint8_t)v; + if (i == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + i = 0; + } + buf[i] = (uint8_t)(n >> 8); + + for (j = 0; j < n;) { + v = (uint16_t)(((value >> ((n - ++j) << 3)) & 255UL) << bitoff); + buf[i++] |= (uint8_t)v; + if (i == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + i = 0; + } + buf[i] = (uint8_t)(v >> 8); + } + + return i; +} + + +/** + * Feed text to the sponge + * + * @param state The hashing state tofeed + * @param buf Buffer that is at least `byterate` bytes large + * @param text Text to feed the sponge + * @param bytes The number of whole bytes in `text` + * @param bits The number of bits at the end of `text` + * that does not make up a whole byte + * @param suffix Bit-string (encoded with ASCII 0/1 digits) + * of additional bytes after `text` + * @param off The current byte offset in `buf` + * @param byterate The byterate of the hashing algorithm + * @param bitoffp Output parameter for the non-whole + * byte bit-offset (current must be 0) + * @return The new byte offset in `buf` + */ +static size_t +feed_text(struct libkeccak_state *restrict state, uint8_t *restrict buf, const uint8_t *restrict text, size_t bytes, + size_t bits, const char *restrict suffix, size_t off, size_t byterate, size_t *restrict bitoffp) +{ + size_t n, bitoff; + + if (off) { + n = bytes < byterate - off ? bytes : byterate - off; + memcpy(&buf[off], text, n); + off += n; + if (off == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + off = 0; + } + text = &text[n]; + bytes -= n; + } + if (bytes) { + n = bytes; + n -= bytes %= byterate; + libkeccak_zerocopy_update(state, text, n); + text = &text[n]; + } + memcpy(&buf[off], text, bytes + !!bits); + off += bytes; + bitoff = bits; + if (!bitoff) + buf[off] = 0; + for (; *suffix; suffix++) { + if (*suffix == '1') + buf[off] |= (uint8_t)(1 << bitoff); + if (++bitoff == 8) { + if (++off == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + off = 0; + } + bitoff = 0; + buf[off] = 0; + } + } + + *bitoffp = bitoff; + return off; +} + + +/** + * Feed text to the sponge + * + * @param state The hashing state tofeed + * @param buf Buffer that is at least `byterate` bytes large + * @param text Text to feed the sponge + * @param bytes The number of whole bytes in `text` + * @param bits The number of bits at the end of `text` + * that does not make up a whole byte + * @param suffix Bit-string (encoded with ASCII 0/1 digits) + * of additional bytes after `text` + * @param off The current byte offset in `buf` + * @param byterate The byterate of the hashing algorithm + * @param bitoffp Pointer to the non-whole byte bit-offset, + * shall be the current (non-zero) bit-offset + * upon entry and will be set to the new + * bit-offset on return + * @return The new byte offset in `buf` + */ +static size_t +feed_text_shifted(struct libkeccak_state *restrict state, uint8_t *restrict buf, const uint8_t *restrict text, size_t bytes, + size_t bits, const char *restrict suffix, size_t off, size_t byterate, size_t *restrict bitoffp) +{ + size_t i, bitoff = *bitoffp; + uint16_t v; + + for (i = 0; i < bytes; i++) { + v = (uint16_t)((uint16_t)text[i] << bitoff); + buf[off] |= (uint8_t)v; + if (++off == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + off = 0; + } + buf[off] = (uint8_t)(v >> 8); + } + if (bits) { + v = (uint16_t)((uint16_t)text[bytes] << bitoff); + buf[off] |= (uint8_t)v; + bitoff += bits; + if (bitoff >= 8) { + if (++off == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + off = 0; + } + bitoff &= 7; + buf[off] = (uint8_t)(v >> 8); + } + } + if (!bitoff) + buf[off] = 0; + for (; *suffix; suffix++) { + if (*suffix == '1') + buf[off] |= (uint8_t)(1 << bitoff); + if (++bitoff == 8) { + if (++off == byterate) { + libkeccak_zerocopy_update(state, buf, byterate); + off = 0; + } + bitoff = 0; + buf[off] = 0; + } + } + + *bitoffp = bitoff; + return off; +} + + +/** + * Create and absorb the initialisation blocks for cSHAKE hashing + * + * @param state The hashing state + * @param n_text Function name-string + * @param n_len Byte-length of `n_text` (only whole byte) + * @param n_bits Bit-length of `n_text`, minus `n_len * 8` + * @param n_suffix Bit-string, represented by a NUL-terminated + * string of '1':s and '0's:, making up the part + * after `n_text` of the function-name bit-string; + * `NULL` is treated as the empty string + * @param s_text Customisation-string + * @param s_len Byte-length of `s_text` (only whole byte) + * @param s_bits Bit-length of `s_text`, minus `s_len * 8` + * @param s_suffix Bit-string, represented by a NUL-terminated + * string of '1':s and '0's:, making up the part + * after `s_text` of the customisation bit-string; + * `NULL` is treated as the empty string + */ +void +libkeccak_cshake_initialise(struct libkeccak_state *restrict state, + const void *n_text, size_t n_len, size_t n_bits, const char *n_suffix, + const void *s_text, size_t s_len, size_t s_bits, const char *s_suffix) +{ + size_t off = 0, bitoff, byterate = (size_t)state->r >> 3; + + if (!n_suffix) + n_suffix = ""; + if (!s_suffix) + s_suffix = ""; + + if (!n_len && !s_len && !n_bits && !s_bits && !*n_suffix && !*s_suffix) + return; + + n_len += n_bits >> 3; + s_len += s_bits >> 3; + n_bits &= 7; + s_bits &= 7; + + off = encode_left(state, state->M, byterate, byterate, off); + off = encode_left(state, state->M, byterate, (n_len << 3) + n_bits + strlen(n_suffix), off); + off = feed_text(state, state->M, n_text, n_len, n_bits, n_suffix, off, byterate, &bitoff); + + if (!bitoff) { + off = encode_left(state, state->M, byterate, (s_len << 3) + s_bits + strlen(s_suffix), off); + off = feed_text(state, state->M, s_text, s_len, s_bits, s_suffix, off, byterate, &bitoff); + } else { + off = encode_left_shifted(state, state->M, byterate, (s_len << 3) + s_bits + strlen(s_suffix), off, bitoff); + off = feed_text_shifted(state, state->M, s_text, s_len, s_bits, s_suffix, off, byterate, &bitoff); + } + + if (bitoff) + off++; + if (off) { + memset(&state->M[off], 0, byterate - off); + libkeccak_zerocopy_update(state, state->M, byterate); + } +} |