mirror of
https://github.com/henrydcase/pqc.git
synced 2024-11-22 23:48:58 +00:00
404 lines
11 KiB
C
404 lines
11 KiB
C
/* Jitter RNG: SHA-3 Implementation
|
|
*
|
|
* Copyright (C) 2021 - 2022, 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"
|
|
#include "jitterentropy.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;
|
|
}
|
|
|
|
int sha3_alloc(void **hash_state)
|
|
{
|
|
struct sha_ctx *tmp;
|
|
|
|
tmp = jent_zalloc(SHA_MAX_CTX_SIZE);
|
|
if (!tmp)
|
|
return 1;
|
|
|
|
*hash_state = tmp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sha3_dealloc(void *hash_state)
|
|
{
|
|
struct sha_ctx *ctx = (struct sha_ctx *)hash_state;
|
|
|
|
jent_zfree(ctx, SHA_MAX_CTX_SIZE);
|
|
}
|