summaryrefslogtreecommitdiff
path: root/random/jitterentropy-sha3.c
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2021-10-29 14:35:09 +0900
committerNIIBE Yutaka <gniibe@fsij.org>2021-11-17 14:29:40 +0900
commit3bacdac611b9eb3bd5ae8d78156b1110e77e9518 (patch)
tree1a9f8a33d21bdb80feae818f9df195664f34a027 /random/jitterentropy-sha3.c
parent5e0187d84fc16d9ff0fbb0ccd4348657fea90d36 (diff)
downloadlibgcrypt-3bacdac611b9eb3bd5ae8d78156b1110e77e9518.tar.gz
jitterentropy: Merge from jitterentropy-library-3.3.0.
* random/jitterentropy-base.h: New. * random/jitterentropy-gcd.c: New. * random/jitterentropy-gcd.h: New. * random/jitterentropy-health.c: New. * random/jitterentropy-health.h: New. * random/jitterentropy-noise.c: New. * random/jitterentropy-noise.h: New. * random/jitterentropy-sha3.c: New. * random/jitterentropy-sha3.h: New. * random/jitterentropy-timer.c: New. * random/jitterentropy-timer.h: New. * random/jitterentropy-base.c: Update. * random/jitterentropy.h: Update. * random/jitterentropy-base-user.h: Update, keeping ours mostly. -- Unicode characters are replaced or removed (quotation mark, minus, and BOM). Inconsistent Tabs are replaced by spaces. GnuPG-bug-id: 5523 Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'random/jitterentropy-sha3.c')
-rw-r--r--random/jitterentropy-sha3.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/random/jitterentropy-sha3.c b/random/jitterentropy-sha3.c
new file mode 100644
index 00000000..59fbb74f
--- /dev/null
+++ b/random/jitterentropy-sha3.c
@@ -0,0 +1,382 @@
+/* Jitter RNG: SHA-3 Implementation
+ *
+ * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de>
+ *
+ * License: see LICENSE file in root directory
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#include "jitterentropy-sha3.h"
+
+/***************************************************************************
+ * Message Digest Implementation
+ ***************************************************************************/
+
+/*
+ * Conversion of Little-Endian representations in byte streams - the data
+ * representation in the integer values is the host representation.
+ */
+static inline uint32_t ptr_to_le32(const uint8_t *p)
+{
+ return (uint32_t)p[0] | (uint32_t)p[1] << 8 |
+ (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24;
+}
+
+static inline uint64_t ptr_to_le64(const uint8_t *p)
+{
+ return (uint64_t)ptr_to_le32(p) | (uint64_t)ptr_to_le32(p + 4) << 32;
+}
+
+static inline void le32_to_ptr(uint8_t *p, const uint32_t value)
+{
+ p[0] = (uint8_t)(value);
+ p[1] = (uint8_t)(value >> 8);
+ p[2] = (uint8_t)(value >> 16);
+ p[3] = (uint8_t)(value >> 24);
+}
+
+static inline void le64_to_ptr(uint8_t *p, const uint64_t value)
+{
+ le32_to_ptr(p + 4, (uint32_t)(value >> 32));
+ le32_to_ptr(p, (uint32_t)(value));
+}
+
+/*********************************** Keccak ***********************************/
+/* state[x + y*5] */
+#define A(x, y) (x + 5 * y)
+
+static inline void keccakp_theta(uint64_t s[25])
+{
+ uint64_t C[5], D[5];
+
+ /* Step 1 */
+ C[0] = s[A(0, 0)] ^ s[A(0, 1)] ^ s[A(0, 2)] ^ s[A(0, 3)] ^ s[A(0, 4)];
+ C[1] = s[A(1, 0)] ^ s[A(1, 1)] ^ s[A(1, 2)] ^ s[A(1, 3)] ^ s[A(1, 4)];
+ C[2] = s[A(2, 0)] ^ s[A(2, 1)] ^ s[A(2, 2)] ^ s[A(2, 3)] ^ s[A(2, 4)];
+ C[3] = s[A(3, 0)] ^ s[A(3, 1)] ^ s[A(3, 2)] ^ s[A(3, 3)] ^ s[A(3, 4)];
+ C[4] = s[A(4, 0)] ^ s[A(4, 1)] ^ s[A(4, 2)] ^ s[A(4, 3)] ^ s[A(4, 4)];
+
+ /* Step 2 */
+ D[0] = C[4] ^ rol64(C[1], 1);
+ D[1] = C[0] ^ rol64(C[2], 1);
+ D[2] = C[1] ^ rol64(C[3], 1);
+ D[3] = C[2] ^ rol64(C[4], 1);
+ D[4] = C[3] ^ rol64(C[0], 1);
+
+ /* Step 3 */
+ s[A(0, 0)] ^= D[0];
+ s[A(1, 0)] ^= D[1];
+ s[A(2, 0)] ^= D[2];
+ s[A(3, 0)] ^= D[3];
+ s[A(4, 0)] ^= D[4];
+
+ s[A(0, 1)] ^= D[0];
+ s[A(1, 1)] ^= D[1];
+ s[A(2, 1)] ^= D[2];
+ s[A(3, 1)] ^= D[3];
+ s[A(4, 1)] ^= D[4];
+
+ s[A(0, 2)] ^= D[0];
+ s[A(1, 2)] ^= D[1];
+ s[A(2, 2)] ^= D[2];
+ s[A(3, 2)] ^= D[3];
+ s[A(4, 2)] ^= D[4];
+
+ s[A(0, 3)] ^= D[0];
+ s[A(1, 3)] ^= D[1];
+ s[A(2, 3)] ^= D[2];
+ s[A(3, 3)] ^= D[3];
+ s[A(4, 3)] ^= D[4];
+
+ s[A(0, 4)] ^= D[0];
+ s[A(1, 4)] ^= D[1];
+ s[A(2, 4)] ^= D[2];
+ s[A(3, 4)] ^= D[3];
+ s[A(4, 4)] ^= D[4];
+}
+
+static inline void keccakp_rho(uint64_t s[25])
+{
+ /* Step 1 */
+ /* s[A(0, 0)] = s[A(0, 0)]; */
+
+#define RHO_ROL(t) (((t + 1) * (t + 2) / 2) % 64)
+ /* Step 3 */
+ s[A(1, 0)] = rol64(s[A(1, 0)], RHO_ROL(0));
+ s[A(0, 2)] = rol64(s[A(0, 2)], RHO_ROL(1));
+ s[A(2, 1)] = rol64(s[A(2, 1)], RHO_ROL(2));
+ s[A(1, 2)] = rol64(s[A(1, 2)], RHO_ROL(3));
+ s[A(2, 3)] = rol64(s[A(2, 3)], RHO_ROL(4));
+ s[A(3, 3)] = rol64(s[A(3, 3)], RHO_ROL(5));
+ s[A(3, 0)] = rol64(s[A(3, 0)], RHO_ROL(6));
+ s[A(0, 1)] = rol64(s[A(0, 1)], RHO_ROL(7));
+ s[A(1, 3)] = rol64(s[A(1, 3)], RHO_ROL(8));
+ s[A(3, 1)] = rol64(s[A(3, 1)], RHO_ROL(9));
+ s[A(1, 4)] = rol64(s[A(1, 4)], RHO_ROL(10));
+ s[A(4, 4)] = rol64(s[A(4, 4)], RHO_ROL(11));
+ s[A(4, 0)] = rol64(s[A(4, 0)], RHO_ROL(12));
+ s[A(0, 3)] = rol64(s[A(0, 3)], RHO_ROL(13));
+ s[A(3, 4)] = rol64(s[A(3, 4)], RHO_ROL(14));
+ s[A(4, 3)] = rol64(s[A(4, 3)], RHO_ROL(15));
+ s[A(3, 2)] = rol64(s[A(3, 2)], RHO_ROL(16));
+ s[A(2, 2)] = rol64(s[A(2, 2)], RHO_ROL(17));
+ s[A(2, 0)] = rol64(s[A(2, 0)], RHO_ROL(18));
+ s[A(0, 4)] = rol64(s[A(0, 4)], RHO_ROL(19));
+ s[A(4, 2)] = rol64(s[A(4, 2)], RHO_ROL(20));
+ s[A(2, 4)] = rol64(s[A(2, 4)], RHO_ROL(21));
+ s[A(4, 1)] = rol64(s[A(4, 1)], RHO_ROL(22));
+ s[A(1, 1)] = rol64(s[A(1, 1)], RHO_ROL(23));
+}
+
+static inline void keccakp_pi(uint64_t s[25])
+{
+ uint64_t t = s[A(4, 4)];
+
+ /* Step 1 */
+ /* s[A(0, 0)] = s[A(0, 0)]; */
+ s[A(4, 4)] = s[A(1, 4)];
+ s[A(1, 4)] = s[A(3, 1)];
+ s[A(3, 1)] = s[A(1, 3)];
+ s[A(1, 3)] = s[A(0, 1)];
+ s[A(0, 1)] = s[A(3, 0)];
+ s[A(3, 0)] = s[A(3, 3)];
+ s[A(3, 3)] = s[A(2, 3)];
+ s[A(2, 3)] = s[A(1, 2)];
+ s[A(1, 2)] = s[A(2, 1)];
+ s[A(2, 1)] = s[A(0, 2)];
+ s[A(0, 2)] = s[A(1, 0)];
+ s[A(1, 0)] = s[A(1, 1)];
+ s[A(1, 1)] = s[A(4, 1)];
+ s[A(4, 1)] = s[A(2, 4)];
+ s[A(2, 4)] = s[A(4, 2)];
+ s[A(4, 2)] = s[A(0, 4)];
+ s[A(0, 4)] = s[A(2, 0)];
+ s[A(2, 0)] = s[A(2, 2)];
+ s[A(2, 2)] = s[A(3, 2)];
+ s[A(3, 2)] = s[A(4, 3)];
+ s[A(4, 3)] = s[A(3, 4)];
+ s[A(3, 4)] = s[A(0, 3)];
+ s[A(0, 3)] = s[A(4, 0)];
+ s[A(4, 0)] = t;
+}
+
+static inline void keccakp_chi(uint64_t s[25])
+{
+ uint64_t t0[5], t1[5];
+
+ t0[0] = s[A(0, 0)];
+ t0[1] = s[A(0, 1)];
+ t0[2] = s[A(0, 2)];
+ t0[3] = s[A(0, 3)];
+ t0[4] = s[A(0, 4)];
+
+ t1[0] = s[A(1, 0)];
+ t1[1] = s[A(1, 1)];
+ t1[2] = s[A(1, 2)];
+ t1[3] = s[A(1, 3)];
+ t1[4] = s[A(1, 4)];
+
+ s[A(0, 0)] ^= ~s[A(1, 0)] & s[A(2, 0)];
+ s[A(0, 1)] ^= ~s[A(1, 1)] & s[A(2, 1)];
+ s[A(0, 2)] ^= ~s[A(1, 2)] & s[A(2, 2)];
+ s[A(0, 3)] ^= ~s[A(1, 3)] & s[A(2, 3)];
+ s[A(0, 4)] ^= ~s[A(1, 4)] & s[A(2, 4)];
+
+ s[A(1, 0)] ^= ~s[A(2, 0)] & s[A(3, 0)];
+ s[A(1, 1)] ^= ~s[A(2, 1)] & s[A(3, 1)];
+ s[A(1, 2)] ^= ~s[A(2, 2)] & s[A(3, 2)];
+ s[A(1, 3)] ^= ~s[A(2, 3)] & s[A(3, 3)];
+ s[A(1, 4)] ^= ~s[A(2, 4)] & s[A(3, 4)];
+
+ s[A(2, 0)] ^= ~s[A(3, 0)] & s[A(4, 0)];
+ s[A(2, 1)] ^= ~s[A(3, 1)] & s[A(4, 1)];
+ s[A(2, 2)] ^= ~s[A(3, 2)] & s[A(4, 2)];
+ s[A(2, 3)] ^= ~s[A(3, 3)] & s[A(4, 3)];
+ s[A(2, 4)] ^= ~s[A(3, 4)] & s[A(4, 4)];
+
+ s[A(3, 0)] ^= ~s[A(4, 0)] & t0[0];
+ s[A(3, 1)] ^= ~s[A(4, 1)] & t0[1];
+ s[A(3, 2)] ^= ~s[A(4, 2)] & t0[2];
+ s[A(3, 3)] ^= ~s[A(4, 3)] & t0[3];
+ s[A(3, 4)] ^= ~s[A(4, 4)] & t0[4];
+
+ s[A(4, 0)] ^= ~t0[0] & t1[0];
+ s[A(4, 1)] ^= ~t0[1] & t1[1];
+ s[A(4, 2)] ^= ~t0[2] & t1[2];
+ s[A(4, 3)] ^= ~t0[3] & t1[3];
+ s[A(4, 4)] ^= ~t0[4] & t1[4];
+}
+
+static const uint64_t keccakp_iota_vals[] = {
+ 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
+ 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
+ 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
+ 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
+ 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
+ 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
+ 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
+ 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
+};
+
+static inline void keccakp_iota(uint64_t s[25], unsigned int round)
+{
+ s[0] ^= keccakp_iota_vals[round];
+}
+
+static inline void keccakp_1600(uint64_t s[25])
+{
+ unsigned int round;
+
+ for (round = 0; round < 24; round++) {
+ keccakp_theta(s);
+ keccakp_rho(s);
+ keccakp_pi(s);
+ keccakp_chi(s);
+ keccakp_iota(s, round);
+ }
+}
+
+/*********************************** SHA-3 ************************************/
+
+static inline void sha3_init(struct sha_ctx *ctx)
+{
+ unsigned int i;
+
+ for (i = 0; i < 25; i++)
+ ctx->state[i] = 0;
+ ctx->msg_len = 0;
+}
+
+void sha3_256_init(struct sha_ctx *ctx)
+{
+ sha3_init(ctx);
+ ctx->r = SHA3_256_SIZE_BLOCK;
+ ctx->rword = SHA3_256_SIZE_BLOCK / sizeof(uint64_t);
+ ctx->digestsize = SHA3_256_SIZE_DIGEST;
+}
+
+static inline void sha3_fill_state(struct sha_ctx *ctx, const uint8_t *in)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->rword; i++) {
+ ctx->state[i] ^= ptr_to_le64(in);
+ in += 8;
+ }
+}
+
+void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen)
+{
+ size_t partial = ctx->msg_len % ctx->r;
+
+ ctx->msg_len += inlen;
+
+ /* Sponge absorbing phase */
+
+ /* Check if we have a partial block stored */
+ if (partial) {
+ size_t todo = ctx->r - partial;
+
+ /*
+ * If the provided data is small enough to fit in the partial
+ * buffer, copy it and leave it unprocessed.
+ */
+ if (inlen < todo) {
+ memcpy(ctx->partial + partial, in, inlen);
+ return;
+ }
+
+ /*
+ * The input data is large enough to fill the entire partial
+ * block buffer. Thus, we fill it and transform it.
+ */
+ memcpy(ctx->partial + partial, in, todo);
+ inlen -= todo;
+ in += todo;
+
+ sha3_fill_state(ctx, ctx->partial);
+ keccakp_1600(ctx->state);
+ }
+
+ /* Perform a transformation of full block-size messages */
+ for (; inlen >= ctx->r; inlen -= ctx->r, in += ctx->r) {
+ sha3_fill_state(ctx, in);
+ keccakp_1600(ctx->state);
+ }
+
+ /* If we have data left, copy it into the partial block buffer */
+ memcpy(ctx->partial, in, inlen);
+}
+
+void sha3_final(struct sha_ctx *ctx, uint8_t *digest)
+{
+ size_t partial = ctx->msg_len % ctx->r;
+ unsigned int i;
+
+ /* Final round in sponge absorbing phase */
+
+ /* Fill the unused part of the partial buffer with zeros */
+ memset(ctx->partial + partial, 0, ctx->r - partial);
+
+ /*
+ * Add the leading and trailing bit as well as the 01 bits for the
+ * SHA-3 suffix.
+ */
+ ctx->partial[partial] = 0x06;
+ ctx->partial[ctx->r - 1] |= 0x80;
+
+ /* Final transformation */
+ sha3_fill_state(ctx, ctx->partial);
+ keccakp_1600(ctx->state);
+
+ /*
+ * Sponge squeeze phase - the digest size is always smaller as the
+ * state size r which implies we only have one squeeze round.
+ */
+ for (i = 0; i < ctx->digestsize / 8; i++, digest += 8)
+ le64_to_ptr(digest, ctx->state[i]);
+
+ /* Add remaining 4 bytes if we use SHA3-224 */
+ if (ctx->digestsize % 8)
+ le32_to_ptr(digest, (uint32_t)(ctx->state[i]));
+
+ memset(ctx->partial, 0, ctx->r);
+ sha3_init(ctx);
+}
+
+int sha3_tester(void)
+{
+ HASH_CTX_ON_STACK(ctx);
+ static const uint8_t msg_256[] = { 0x5E, 0x5E, 0xD6 };
+ static const uint8_t exp_256[] = { 0xF1, 0x6E, 0x66, 0xC0, 0x43, 0x72,
+ 0xB4, 0xA3, 0xE1, 0xE3, 0x2E, 0x07,
+ 0xC4, 0x1C, 0x03, 0x40, 0x8A, 0xD5,
+ 0x43, 0x86, 0x8C, 0xC4, 0x0E, 0xC5,
+ 0x5E, 0x00, 0xBB, 0xBB, 0xBD, 0xF5,
+ 0x91, 0x1E };
+ uint8_t act[SHA3_256_SIZE_DIGEST] = { 0 };
+ unsigned int i;
+
+ sha3_256_init(&ctx);
+ sha3_update(&ctx, msg_256, 3);
+ sha3_final(&ctx, act);
+
+ for (i = 0; i < SHA3_256_SIZE_DIGEST; i++) {
+ if (exp_256[i] != act[i])
+ return 1;
+ }
+
+ return 0;
+}