aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/keccak.c74
-rw-r--r--src/crypto/keccak.h14
2 files changed, 88 insertions, 0 deletions
diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c
index de8e2a5b3..8fcd2138e 100644
--- a/src/crypto/keccak.c
+++ b/src/crypto/keccak.c
@@ -132,3 +132,77 @@ void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md)
{
keccak(in, inlen, md, sizeof(state_t));
}
+
+#define KECCAK_FINALIZED 0x80000000
+#define KECCAK_BLOCKLEN 136
+#define KECCAK_WORDS 17
+#define KECCAK_DIGESTSIZE 32
+#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0)))
+#define KECCAK_PROCESS_BLOCK(st, block) { \
+ for (int i_ = 0; i_ < KECCAK_WORDS; i_++){ \
+ ((st))[i_] ^= ((block))[i_]; \
+ }; \
+ keccakf(st, KECCAK_ROUNDS); }
+
+
+void keccak_init(KECCAK_CTX * ctx){
+ memset(ctx, 0, sizeof(KECCAK_CTX));
+}
+
+void keccak_update(KECCAK_CTX * ctx, const uint8_t *in, size_t inlen){
+ if (ctx->rest & KECCAK_FINALIZED) {
+ local_abort("Bad keccak use");
+ }
+
+ const size_t idx = ctx->rest;
+ ctx->rest = (ctx->rest + inlen) % KECCAK_BLOCKLEN;
+
+ // fill partial block
+ if (idx) {
+ size_t left = KECCAK_BLOCKLEN - idx;
+ memcpy((char*)ctx->message + idx, in, (inlen < left ? inlen : left));
+ if (inlen < left) return;
+
+ KECCAK_PROCESS_BLOCK(ctx->hash, ctx->message);
+
+ in += left;
+ inlen -= left;
+ }
+
+ const bool is_aligned = IS_ALIGNED_64(in);
+ while (inlen >= KECCAK_BLOCKLEN) {
+ const uint64_t* aligned_message_block;
+ if (is_aligned) {
+ aligned_message_block = (uint64_t*)in;
+ } else {
+ memcpy(ctx->message, in, KECCAK_BLOCKLEN);
+ aligned_message_block = ctx->message;
+ }
+
+ KECCAK_PROCESS_BLOCK(ctx->hash, aligned_message_block);
+ in += KECCAK_BLOCKLEN;
+ inlen -= KECCAK_BLOCKLEN;
+ }
+ if (inlen) {
+ memcpy(ctx->message, in, inlen);
+ }
+}
+
+void keccak_finish(KECCAK_CTX * ctx, uint8_t *md){
+ if (!(ctx->rest & KECCAK_FINALIZED))
+ {
+ // clear the rest of the data queue
+ memset((char*)ctx->message + ctx->rest, 0, KECCAK_BLOCKLEN - ctx->rest);
+ ((char*)ctx->message)[ctx->rest] |= 0x01;
+ ((char*)ctx->message)[KECCAK_BLOCKLEN - 1] |= 0x80;
+
+ // process final block
+ KECCAK_PROCESS_BLOCK(ctx->hash, ctx->message);
+ ctx->rest = KECCAK_FINALIZED; // mark context as finalized
+ }
+
+ static_assert(KECCAK_BLOCKLEN > KECCAK_DIGESTSIZE, "");
+ if (md) {
+ memcpy(md, ctx->hash, KECCAK_DIGESTSIZE);
+ }
+}
diff --git a/src/crypto/keccak.h b/src/crypto/keccak.h
index fb9d8bd04..9123c7a3b 100644
--- a/src/crypto/keccak.h
+++ b/src/crypto/keccak.h
@@ -15,6 +15,17 @@
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif
+// SHA3 Algorithm context.
+typedef struct KECCAK_CTX
+{
+ // 1600 bits algorithm hashing state
+ uint64_t hash[25];
+ // 1088-bit buffer for leftovers, block size = 136 B for 256-bit keccak
+ uint64_t message[17];
+ // count of bytes in the message[] buffer
+ size_t rest;
+} KECCAK_CTX;
+
// compute a keccak hash (md) of given byte length from "in"
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen);
@@ -23,4 +34,7 @@ void keccakf(uint64_t st[25], int norounds);
void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md);
+void keccak_init(KECCAK_CTX * ctx);
+void keccak_update(KECCAK_CTX * ctx, const uint8_t *in, size_t inlen);
+void keccak_finish(KECCAK_CTX * ctx, uint8_t *md);
#endif