summaryrefslogtreecommitdiff
path: root/lib/liboqs/src/common/sha3/xkcp_sha3.c
diff options
context:
space:
mode:
authorRobert Relyea <rrelyea@redhat.com>2023-02-27 17:19:39 -0800
committerRobert Relyea <rrelyea@redhat.com>2023-02-27 17:19:39 -0800
commitfceb08b2428170ae51938fa93bc2b2c00bd1d5ad (patch)
treebea248d594fa867f3995d63990d313eb72c5af68 /lib/liboqs/src/common/sha3/xkcp_sha3.c
parentf4262a3db99a22b38fc8d6d9e8103ad31a697f9f (diff)
downloadnss-hg-fceb08b2428170ae51938fa93bc2b2c00bd1d5ad.tar.gz
Add liboqs
Diffstat (limited to 'lib/liboqs/src/common/sha3/xkcp_sha3.c')
-rw-r--r--lib/liboqs/src/common/sha3/xkcp_sha3.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/lib/liboqs/src/common/sha3/xkcp_sha3.c b/lib/liboqs/src/common/sha3/xkcp_sha3.c
new file mode 100644
index 000000000..ede460734
--- /dev/null
+++ b/lib/liboqs/src/common/sha3/xkcp_sha3.c
@@ -0,0 +1,388 @@
+/**
+* \file sha3_xkcp.c
+* \brief Implementation of the OQS SHA3 API using the XKCP low interface.
+* The high level keccak_absorb, squeezeblocks, etc. are based on fips202.c
+* from PQClean (https://github.com/PQClean/PQClean/tree/master/common)
+*
+* SPDX-License-Identifier: MIT
+*/
+
+#include "sha3.h"
+
+#include "xkcp_dispatch.h"
+
+#include <oqs/common.h>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define KECCAK_CTX_ALIGNMENT 32
+#define _KECCAK_CTX_BYTES (200+sizeof(uint64_t))
+#define KECCAK_CTX_BYTES (KECCAK_CTX_ALIGNMENT * \
+ ((_KECCAK_CTX_BYTES + KECCAK_CTX_ALIGNMENT - 1)/KECCAK_CTX_ALIGNMENT))
+
+/* The first call to Keccak_Initialize will be routed through dispatch, which
+ * updates all of the function pointers used below.
+ */
+static KeccakInitFn Keccak_Dispatch;
+static KeccakInitFn *Keccak_Initialize_ptr = &Keccak_Dispatch;
+static KeccakAddByteFn *Keccak_AddByte_ptr = NULL;
+static KeccakAddBytesFn *Keccak_AddBytes_ptr = NULL;
+static KeccakPermuteFn *Keccak_Permute_ptr = NULL;
+static KeccakExtractBytesFn *Keccak_ExtractBytes_ptr = NULL;
+static KeccakFastLoopAbsorbFn *Keccak_FastLoopAbsorb_ptr = NULL;
+
+static void Keccak_Dispatch(void *state) {
+// TODO: Simplify this when we have a Windows-compatible AVX2 implementation of SHA3
+#if defined(OQS_DIST_X86_64_BUILD)
+#if defined(OQS_ENABLE_SHA3_xkcp_low_avx2)
+ if (OQS_CPU_has_extension(OQS_CPU_EXT_AVX2)) {
+ Keccak_Initialize_ptr = &KeccakP1600_Initialize_avx2;
+ Keccak_AddByte_ptr = &KeccakP1600_AddByte_avx2;
+ Keccak_AddBytes_ptr = &KeccakP1600_AddBytes_avx2;
+ Keccak_Permute_ptr = &KeccakP1600_Permute_24rounds_avx2;
+ Keccak_ExtractBytes_ptr = &KeccakP1600_ExtractBytes_avx2;
+ Keccak_FastLoopAbsorb_ptr = &KeccakF1600_FastLoop_Absorb_avx2;
+ } else {
+ Keccak_Initialize_ptr = &KeccakP1600_Initialize_plain64;
+ Keccak_AddByte_ptr = &KeccakP1600_AddByte_plain64;
+ Keccak_AddBytes_ptr = &KeccakP1600_AddBytes_plain64;
+ Keccak_Permute_ptr = &KeccakP1600_Permute_24rounds_plain64;
+ Keccak_ExtractBytes_ptr = &KeccakP1600_ExtractBytes_plain64;
+ Keccak_FastLoopAbsorb_ptr = &KeccakF1600_FastLoop_Absorb_plain64;
+ }
+#else // Windows
+ Keccak_Initialize_ptr = &KeccakP1600_Initialize_plain64;
+ Keccak_AddByte_ptr = &KeccakP1600_AddByte_plain64;
+ Keccak_AddBytes_ptr = &KeccakP1600_AddBytes_plain64;
+ Keccak_Permute_ptr = &KeccakP1600_Permute_24rounds_plain64;
+ Keccak_ExtractBytes_ptr = &KeccakP1600_ExtractBytes_plain64;
+ Keccak_FastLoopAbsorb_ptr = &KeccakF1600_FastLoop_Absorb_plain64;
+#endif
+#else
+ Keccak_Initialize_ptr = &KeccakP1600_Initialize;
+ Keccak_AddByte_ptr = &KeccakP1600_AddByte;
+ Keccak_AddBytes_ptr = &KeccakP1600_AddBytes;
+ Keccak_Permute_ptr = &KeccakP1600_Permute_24rounds;
+ Keccak_ExtractBytes_ptr = &KeccakP1600_ExtractBytes;
+ Keccak_FastLoopAbsorb_ptr = &KeccakF1600_FastLoop_Absorb;
+#endif
+
+ (*Keccak_Initialize_ptr)(state);
+}
+
+/*************************************************
+ * Name: keccak_inc_reset
+ *
+ * Description: Initializes the incremental Keccak state to zero.
+ *
+ * Arguments: - uint64_t *s: pointer to input/output incremental state
+ * First 25 values represent Keccak state.
+ * 26th value represents either the number of absorbed bytes
+ * that have not been permuted, or not-yet-squeezed bytes.
+ **************************************************/
+static void keccak_inc_reset(uint64_t *s) {
+ (*Keccak_Initialize_ptr)(s);
+ s[25] = 0;
+}
+
+/*************************************************
+ * Name: keccak_inc_absorb
+ *
+ * Description: Incremental keccak absorb
+ * Preceded by keccak_inc_reset, succeeded by keccak_inc_finalize
+ *
+ * Arguments: - uint64_t *s: pointer to input/output incremental state
+ * First 25 values represent Keccak state.
+ * 26th value represents either the number of absorbed bytes
+ * that have not been permuted, or not-yet-squeezed bytes.
+ * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128)
+ * - const uint8_t *m: pointer to input to be absorbed into s
+ * - size_t mlen: length of input in bytes
+ **************************************************/
+static void keccak_inc_absorb(uint64_t *s, uint32_t r, const uint8_t *m,
+ size_t mlen) {
+ uint64_t c = r - s[25];
+
+ if (s[25] && mlen >= c) {
+ (*Keccak_AddBytes_ptr)(s, m, (unsigned int)s[25], (unsigned int)c);
+ (*Keccak_Permute_ptr)(s);
+ mlen -= c;
+ m += c;
+ s[25] = 0;
+ }
+
+#ifdef KeccakF1600_FastLoop_supported
+ if (mlen >= r) {
+ c = (*Keccak_FastLoop_Absorb_ptr)(s, r / 8, m, mlen);
+ mlen -= c;
+ m += c;
+ }
+#else
+ while (mlen >= r) {
+ (*Keccak_AddBytes_ptr)(s, m, 0, r);
+ (*Keccak_Permute_ptr)(s);
+ mlen -= r;
+ m += r;
+ }
+#endif
+
+ (*Keccak_AddBytes_ptr)(s, m, (unsigned int)s[25], (unsigned int)mlen);
+ s[25] += mlen;
+}
+
+/*************************************************
+ * Name: keccak_inc_finalize
+ *
+ * Description: Finalizes Keccak absorb phase, prepares for squeezing
+ *
+ * Arguments: - uint64_t *s: pointer to input/output incremental state
+ * First 25 values represent Keccak state.
+ * 26th value represents either the number of absorbed bytes
+ * that have not been permuted, or not-yet-squeezed bytes.
+ * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128)
+ * - uint8_t p: domain-separation byte for different
+ * Keccak-derived functions
+ **************************************************/
+static void keccak_inc_finalize(uint64_t *s, uint32_t r, uint8_t p) {
+ /* After keccak_inc_absorb, we are guaranteed that s[25] < r,
+ so we can always use one more byte for p in the current state. */
+ (*Keccak_AddByte_ptr)(s, p, (unsigned int)s[25]);
+ (*Keccak_AddByte_ptr)(s, 0x80, (unsigned int)(r - 1));
+ s[25] = 0;
+}
+
+/*************************************************
+ * Name: keccak_inc_squeeze
+ *
+ * Description: Incremental Keccak squeeze; can be called on byte-level
+ *
+ * Arguments: - uint8_t *h: pointer to output bytes
+ * - size_t outlen: number of bytes to be squeezed
+ * - uint64_t *s: pointer to input/output incremental state
+ * First 25 values represent Keccak state.
+ * 26th value represents either the number of absorbed bytes
+ * that have not been permuted, or not-yet-squeezed bytes.
+ * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128)
+ **************************************************/
+static void keccak_inc_squeeze(uint8_t *h, size_t outlen,
+ uint64_t *s, uint32_t r) {
+ while (outlen > s[25]) {
+ (*Keccak_ExtractBytes_ptr)(s, h, (unsigned int)(r - s[25]), (unsigned int)s[25]);
+ (*Keccak_Permute_ptr)(s);
+ h += s[25];
+ outlen -= s[25];
+ s[25] = r;
+ }
+ (*Keccak_ExtractBytes_ptr)(s, h, (unsigned int)(r - s[25]), (unsigned int)outlen);
+ s[25] -= outlen;
+}
+
+/* SHA3-256 */
+
+void OQS_SHA3_sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) {
+ OQS_SHA3_sha3_256_inc_ctx s;
+ OQS_SHA3_sha3_256_inc_init(&s);
+ OQS_SHA3_sha3_256_inc_absorb(&s, input, inlen);
+ OQS_SHA3_sha3_256_inc_finalize(output, &s);
+ OQS_SHA3_sha3_256_inc_ctx_release(&s);
+}
+
+void OQS_SHA3_sha3_256_inc_init(OQS_SHA3_sha3_256_inc_ctx *state) {
+ state->ctx = OQS_MEM_aligned_alloc(KECCAK_CTX_ALIGNMENT, KECCAK_CTX_BYTES);
+ if (state->ctx == NULL) {
+ exit(111);
+ }
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+void OQS_SHA3_sha3_256_inc_absorb(OQS_SHA3_sha3_256_inc_ctx *state, const uint8_t *input, size_t inlen) {
+ keccak_inc_absorb((uint64_t *)state->ctx, OQS_SHA3_SHA3_256_RATE, input, inlen);
+}
+
+void OQS_SHA3_sha3_256_inc_finalize(uint8_t *output, OQS_SHA3_sha3_256_inc_ctx *state) {
+ keccak_inc_finalize((uint64_t *)state->ctx, OQS_SHA3_SHA3_256_RATE, 0x06);
+ keccak_inc_squeeze(output, 32, (uint64_t *)state->ctx, OQS_SHA3_SHA3_256_RATE);
+}
+
+void OQS_SHA3_sha3_256_inc_ctx_release(OQS_SHA3_sha3_256_inc_ctx *state) {
+ OQS_MEM_aligned_free(state->ctx);
+}
+
+void OQS_SHA3_sha3_256_inc_ctx_clone(OQS_SHA3_sha3_256_inc_ctx *dest, const OQS_SHA3_sha3_256_inc_ctx *src) {
+ memcpy(dest->ctx, src->ctx, KECCAK_CTX_BYTES);
+}
+
+void OQS_SHA3_sha3_256_inc_ctx_reset(OQS_SHA3_sha3_256_inc_ctx *state) {
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+/* SHA3-384 */
+
+void OQS_SHA3_sha3_384(uint8_t *output, const uint8_t *input, size_t inlen) {
+ OQS_SHA3_sha3_384_inc_ctx s;
+ OQS_SHA3_sha3_384_inc_init(&s);
+ OQS_SHA3_sha3_384_inc_absorb(&s, input, inlen);
+ OQS_SHA3_sha3_384_inc_finalize(output, &s);
+ OQS_SHA3_sha3_384_inc_ctx_release(&s);
+}
+
+void OQS_SHA3_sha3_384_inc_init(OQS_SHA3_sha3_384_inc_ctx *state) {
+ state->ctx = OQS_MEM_aligned_alloc(KECCAK_CTX_ALIGNMENT, KECCAK_CTX_BYTES);
+ if (state->ctx == NULL) {
+ exit(111);
+ }
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+void OQS_SHA3_sha3_384_inc_absorb(OQS_SHA3_sha3_384_inc_ctx *state, const uint8_t *input, size_t inlen) {
+ keccak_inc_absorb((uint64_t *)state->ctx, OQS_SHA3_SHA3_384_RATE, input, inlen);
+}
+
+void OQS_SHA3_sha3_384_inc_finalize(uint8_t *output, OQS_SHA3_sha3_384_inc_ctx *state) {
+ keccak_inc_finalize((uint64_t *)state->ctx, OQS_SHA3_SHA3_384_RATE, 0x06);
+ keccak_inc_squeeze(output, 48, (uint64_t *)state->ctx, OQS_SHA3_SHA3_384_RATE);
+}
+
+void OQS_SHA3_sha3_384_inc_ctx_release(OQS_SHA3_sha3_384_inc_ctx *state) {
+ OQS_MEM_aligned_free(state->ctx);
+}
+
+void OQS_SHA3_sha3_384_inc_ctx_clone(OQS_SHA3_sha3_384_inc_ctx *dest, const OQS_SHA3_sha3_384_inc_ctx *src) {
+ memcpy(dest->ctx, src->ctx, KECCAK_CTX_BYTES);
+}
+
+void OQS_SHA3_sha3_384_inc_ctx_reset(OQS_SHA3_sha3_384_inc_ctx *state) {
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+/* SHA3-512 */
+
+void OQS_SHA3_sha3_512(uint8_t *output, const uint8_t *input, size_t inlen) {
+ OQS_SHA3_sha3_512_inc_ctx s;
+ OQS_SHA3_sha3_512_inc_init(&s);
+ OQS_SHA3_sha3_512_inc_absorb(&s, input, inlen);
+ OQS_SHA3_sha3_512_inc_finalize(output, &s);
+ OQS_SHA3_sha3_512_inc_ctx_release(&s);
+}
+
+void OQS_SHA3_sha3_512_inc_init(OQS_SHA3_sha3_512_inc_ctx *state) {
+ state->ctx = OQS_MEM_aligned_alloc(KECCAK_CTX_ALIGNMENT, KECCAK_CTX_BYTES);
+ if (state->ctx == NULL) {
+ exit(111);
+ }
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+void OQS_SHA3_sha3_512_inc_absorb(OQS_SHA3_sha3_512_inc_ctx *state, const uint8_t *input, size_t inlen) {
+ keccak_inc_absorb((uint64_t *)state->ctx, OQS_SHA3_SHA3_512_RATE, input, inlen);
+}
+
+void OQS_SHA3_sha3_512_inc_finalize(uint8_t *output, OQS_SHA3_sha3_512_inc_ctx *state) {
+ keccak_inc_finalize((uint64_t *)state->ctx, OQS_SHA3_SHA3_512_RATE, 0x06);
+ keccak_inc_squeeze(output, 64, (uint64_t *)state->ctx, OQS_SHA3_SHA3_512_RATE);
+}
+
+void OQS_SHA3_sha3_512_inc_ctx_release(OQS_SHA3_sha3_512_inc_ctx *state) {
+ OQS_MEM_aligned_free(state->ctx);
+}
+
+void OQS_SHA3_sha3_512_inc_ctx_clone(OQS_SHA3_sha3_512_inc_ctx *dest, const OQS_SHA3_sha3_512_inc_ctx *src) {
+ memcpy(dest->ctx, src->ctx, KECCAK_CTX_BYTES);
+}
+
+void OQS_SHA3_sha3_512_inc_ctx_reset(OQS_SHA3_sha3_512_inc_ctx *state) {
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+/* SHAKE128 */
+
+void OQS_SHA3_shake128(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen) {
+ OQS_SHA3_shake128_inc_ctx s;
+ OQS_SHA3_shake128_inc_init(&s);
+ OQS_SHA3_shake128_inc_absorb(&s, input, inlen);
+ OQS_SHA3_shake128_inc_finalize(&s);
+ OQS_SHA3_shake128_inc_squeeze(output, outlen, &s);
+ OQS_SHA3_shake128_inc_ctx_release(&s);
+}
+
+/* SHAKE128 incremental */
+
+void OQS_SHA3_shake128_inc_init(OQS_SHA3_shake128_inc_ctx *state) {
+ state->ctx = OQS_MEM_aligned_alloc(KECCAK_CTX_ALIGNMENT, KECCAK_CTX_BYTES);
+ if (state->ctx == NULL) {
+ exit(111);
+ }
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+void OQS_SHA3_shake128_inc_absorb(OQS_SHA3_shake128_inc_ctx *state, const uint8_t *input, size_t inlen) {
+ keccak_inc_absorb((uint64_t *)state->ctx, OQS_SHA3_SHAKE128_RATE, input, inlen);
+}
+
+void OQS_SHA3_shake128_inc_finalize(OQS_SHA3_shake128_inc_ctx *state) {
+ keccak_inc_finalize((uint64_t *)state->ctx, OQS_SHA3_SHAKE128_RATE, 0x1F);
+}
+
+void OQS_SHA3_shake128_inc_squeeze(uint8_t *output, size_t outlen, OQS_SHA3_shake128_inc_ctx *state) {
+ keccak_inc_squeeze(output, outlen, (uint64_t *)state->ctx, OQS_SHA3_SHAKE128_RATE);
+}
+
+void OQS_SHA3_shake128_inc_ctx_clone(OQS_SHA3_shake128_inc_ctx *dest, const OQS_SHA3_shake128_inc_ctx *src) {
+ memcpy(dest->ctx, src->ctx, KECCAK_CTX_BYTES);
+}
+
+void OQS_SHA3_shake128_inc_ctx_release(OQS_SHA3_shake128_inc_ctx *state) {
+ OQS_MEM_aligned_free(state->ctx);
+}
+
+void OQS_SHA3_shake128_inc_ctx_reset(OQS_SHA3_shake128_inc_ctx *state) {
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+/* SHAKE256 */
+
+void OQS_SHA3_shake256(uint8_t *output, size_t outlen, const uint8_t *input, size_t inlen) {
+ OQS_SHA3_shake256_inc_ctx s;
+ OQS_SHA3_shake256_inc_init(&s);
+ OQS_SHA3_shake256_inc_absorb(&s, input, inlen);
+ OQS_SHA3_shake256_inc_finalize(&s);
+ OQS_SHA3_shake256_inc_squeeze(output, outlen, &s);
+ OQS_SHA3_shake256_inc_ctx_release(&s);
+}
+
+/* SHAKE256 incremental */
+
+void OQS_SHA3_shake256_inc_init(OQS_SHA3_shake256_inc_ctx *state) {
+ state->ctx = OQS_MEM_aligned_alloc(KECCAK_CTX_ALIGNMENT, KECCAK_CTX_BYTES);
+ if (state->ctx == NULL) {
+ exit(111);
+ }
+ keccak_inc_reset((uint64_t *)state->ctx);
+}
+
+void OQS_SHA3_shake256_inc_absorb(OQS_SHA3_shake256_inc_ctx *state, const uint8_t *input, size_t inlen) {
+ keccak_inc_absorb((uint64_t *)state->ctx, OQS_SHA3_SHAKE256_RATE, input, inlen);
+}
+
+void OQS_SHA3_shake256_inc_finalize(OQS_SHA3_shake256_inc_ctx *state) {
+ keccak_inc_finalize((uint64_t *)state->ctx, OQS_SHA3_SHAKE256_RATE, 0x1F);
+}
+
+void OQS_SHA3_shake256_inc_squeeze(uint8_t *output, size_t outlen, OQS_SHA3_shake256_inc_ctx *state) {
+ keccak_inc_squeeze(output, outlen, state->ctx, OQS_SHA3_SHAKE256_RATE);
+}
+
+void OQS_SHA3_shake256_inc_ctx_release(OQS_SHA3_shake256_inc_ctx *state) {
+ OQS_MEM_aligned_free(state->ctx);
+}
+
+void OQS_SHA3_shake256_inc_ctx_clone(OQS_SHA3_shake256_inc_ctx *dest, const OQS_SHA3_shake256_inc_ctx *src) {
+ memcpy(dest->ctx, src->ctx, KECCAK_CTX_BYTES);
+}
+
+void OQS_SHA3_shake256_inc_ctx_reset(OQS_SHA3_shake256_inc_ctx *state) {
+ keccak_inc_reset((uint64_t *)state->ctx);
+}