Repository: brainhub/SHA3IUF Branch: master Commit: fc8504750a5c Files: 52 Total size: 36.1 KB Directory structure: gitextract_5tj02dc8/ ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── fuzz/ │ ├── run.sh │ ├── seeds/ │ │ ├── 01ec548baccbe69625b54206ef7100f5ed03719f │ │ ├── 0a5dec3f2ed57a024ccba1041dc85e54e09f74d4 │ │ ├── 0bfb1ece6a9278c2fc475bb8901308f8a9cafbb4 │ │ ├── 13817dae42cce3b01da9435b035a8b8ea94d2df8 │ │ ├── 1511dc059ee7a55d9ac4d4a91b5bf8929f846d0f │ │ ├── 19852f1f4d08174b77ba2c88e0d8ec1455348b22 │ │ ├── 1f8cc307c05de3bf9d98f90dcfa11583d187d15a │ │ ├── 27c554131c35630341a2b84ecaab53072fbfe6ca │ │ ├── 28b9d530ca4a5765c6def1393d1252acb9f3de90 │ │ ├── 2daa36d007df33c974630657696ef4fbc665ca12 │ │ ├── 30f28e65f01f0af35a4b1b8dbc20dafa5cfb5584 │ │ ├── 355a748ff0b67ea9fa417f1ed773a3641ebd4929 │ │ ├── 363323cbf90a34023130dbba0777f6ddd3063d4f │ │ ├── 3c363836cf4e16666669a25da280a1865c2d2874 │ │ ├── 3d838f2ff09a1f5f0405fc46b63127f2ae00032e │ │ ├── 4c767fec38e38bc45cbe9f4c97b298944183ac15 │ │ ├── 520b1aab7fdbbdfaa160e777878116a119ff3200 │ │ ├── 5d7ecbb52e7818d4d2d5c68ebd26dd3b5ad67cc3 │ │ ├── 5e47ec79910a8df76747862af0aec850d7b3f29a │ │ ├── 6f7ca473e2aee8204381b00777801535151c58bd │ │ ├── 71853c6197a6a7f222db0f1978c7cb232b87c5ee │ │ ├── 744dd71fe66027d943e84151fda2555e9a67c0cb │ │ ├── 759e0d4e0d765166c3b1aa9e66ece0d146cb68e6 │ │ ├── 819c227c2780b372be25bbd8028fd806ab0cba35 │ │ ├── 8519208c0cb8cbb2c2731dae901752df10c2ab7e │ │ ├── 885f051ffcf79b45bee97b7b52d7f9087533f192 │ │ ├── 98fc3c55ad129219ed5ffa43cd36a83fd6c2248e │ │ ├── a03822c4ce67e2d8d243fc3b0f0d96338b6555d2 │ │ ├── a4bf6fc7ed78f9cdc178168a3a60070f3fae68ab │ │ ├── a60cbf05a3f86e96123bc6a87803f3fe0de1a272 │ │ ├── a979ef10cc6f6a36df6b8a323307ee3bb2e2db9c │ │ ├── b69e21c4d029acf5779df9a7167cb0b3d76b6a91 │ │ ├── b6dd110c53d944c083ae6e45383b73310ef11856 │ │ ├── bab01b936511366f8048d15679eeb875db818a1f │ │ ├── c63ae6dd4fc9f9dda66970e827d13f7c73fe841c │ │ ├── e0bb4ab56fc584ad6992e3b4de55e96d9f626b25 │ │ ├── e9c3d0af3f6d6b0897bb52bd597ecbee5559ec34 │ │ ├── f45250b51fd7511ea177e87492cfb303b73517b3 │ │ ├── f5424addd46d466b132717d8f9cf0dc2d7bbc5eb │ │ ├── f5c5efe3024d0f2e32d53036cd1954b99dff03d8 │ │ ├── f6183b6a7bbe75583b8061d8438db6f9ed47fba3 │ │ └── f6c3c3c3fc3d562e27461eda971ba56df05c22fd │ └── sha3fuzz.c ├── sha3.c ├── sha3.h ├── sha3sum.c └── sha3test.c ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /*.o /*.a /sha3sum /sha3test ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 brainhub Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ .POSIX: CC = c99 CFLAGS = -std=c99 -Wall -Wextra -Wpedantic -O2 -g LDFLAGS = LDLIBS = PREFIX = /usr/local all: libsha3.a sha3sum sha3test .SUFFIXES: .c .o .c.o: $(CC) -c $(CFLAGS) -o $@ $< libsha3.a: sha3.o ar rsv $@ sha3.o sha3sum: sha3.o sha3sum.o $(CC) $(LDFLAGS) -o $@ sha3.o sha3sum.o $(LDLIBS) sha3fuzz: sha3.c fuzz/sha3fuzz.c clang -g --std=c99 -fsanitize=fuzzer,address -O0 -I . -o $@ $^ sha3test: sha3.o sha3test.o $(CC) $(LDFLAGS) -o $@ sha3.o sha3test.o $(LDLIBS) check: sha3test ./sha3test clean: rm -f *.o libsha3.a sha3sum sha3test sha3fuzz install: mkdir -p $(DESTDIR)$(PREFIX)/include \ $(DESTDIR)$(PREFIX)/lib \ $(DESTDIR)$(PREFIX)/bin install sha3.h $(DESTDIR)$(PREFIX)/include install -m 755 libsha3.a $(DESTDIR)$(PREFIX)/lib install -m 755 sha3sum $(DESTDIR)$(PREFIX)/bin uninstall: rm -f \ $(DESTDIR)$(PREFIX)/include/sha3.h \ $(DESTDIR)$(PREFIX)/lib/libsha3.a \ $(DESTDIR)$(PREFIX)/bin/sha3sum .PHONY: all check clean install uninstall ================================================ FILE: README.md ================================================ # C implementation of SHA-3 and Keccak with Init/Update/Finalize API The purpose of this project is: * provide an API that hashes bytes, not bits * provide a simple reference implementation of a SHA-3 message digest algorithm, as defined in the [FIPS 202][fips202_standard] standard * assist developers in the [Ethereum](https://www.ethereum.org/) blockchain ecosystem by providing the Keccak function used there * implement the hashing API that employs the __IUF__ paradigm (or `Init`, `Update`, `Finalize` style) * answer the design questions, such as: * what does the state for IUF look like? * how small can the state be (224 bytes on a 64-bit system for a unified SHA-3 algorithm) * what is the incremental cost of adding e.g. SHA3-384 to a SHA3-256 implementation? The implementation is written in C and uses `uint64_t` types to manage the SHA-3 state. The code will compile and run on 64-bit and 32-bit architectures (`gcc` and `gcc -m32` on `x86_64` were tested). [fips202_standard]: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf "FIPS 202 standard" ## License, prior work This work is licensed with a standard [MIT license](LICENSE). I appreciate, but do not require, any attribution to this work if you used the code or ideas. I thank you for this in advance. This is a clean-room implementation of IUF API for SHA3. The `keccakf()` is based on the code from [keccak.noekeon.org](http://keccak.noekeon.org/). 1600-bit message hashing test vectors are [NIST test vectors](http://csrc.nist.gov/groups/ST/toolkit/examples.html). ## Overview of the API Let's hash 'abc' with SHA3-256 using two methods: single buffer (but using IUF paradigm), and using the IUF API. sha3_context c; uint8_t *hash; Single-buffer hashing: sha3_Init256(&c); sha3_Update(&c, "abc", 3); hash = sha3_Finalize(&c); // 'hash' points to a buffer inside 'c' // with the value of SHA3-256 Alternatively, IUF hashing: sha3_Init256(&c); sha3_Update(&c, "a", 1); sha3_Update(&c, "bc", 2); hash = sha3_Finalize(&c); // no free for 'c' is needed The `hash` points to the same `256/8=32` bytes in both cases. There is also a single-call hashing API: sha3_HashBuffer(256, SHA3_FLAGS_KECCAK, "abc", 3, out, sizeof(out)); // out contains 256 bits of Keccak256, or less if sizeof(out)<32 ## How to use Keccak version Call `sha3_SetFlags(&c, SHA3_FLAGS_KECCAK)` immediately after `sha3_InitX` or no later than `sha3_Finalize`. This change cannot be undone for the given hash context. ## Building $ make See `Makefile` for details. See also below for specific examples. ## Self-tests $ make test Keccak-256 tests passed OK SHA3-256, SHA3-384, SHA3-512 tests passed OK or $ make CFLAGS=-m32 LDFLAGS=-m32 test Keccak-256 tests passed OK SHA3-256, SHA3-384, SHA3-512 tests passed OK There is also `sha3sum` test program that takes following parameters: sha3sum 256|384|512 file_path or for Keccak version: sha3sum 256|384|512 -k file_path ### SHA-3 / Linux sha3sum example $ touch empty.txt $ gcc -Wall sha3.c sha3sum.c -o sha3sum && ./sha3sum 256 empty.txt a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a empty.txt Compare with Linux `sha3sum`: $ sha3sum -a 256 empty.txt a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a empty.txt ### Keccak256 / Solidity example $ echo -n "abc" > abc $ sha3sum 256 -k abc 4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 abc This corresponds to the result obtained in Solidity JavaScript test framework. console.log(web3.utils.sha3('abc')); // prints 0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 ## API * the same `sha3_context` object maintains the state for SHA3-256, SHA3-384, or SHA3-512 algorithm; * the hash algorithm used is determined by how the context was initialized with `sha3_InitX`, e.g. `sha3_Init256`, `sha3_Init384`, or `sha3_Init512` call; * `sha3_Update` and `sha3_Finalize` are the same for regardless the type of the algorithm (`X`); * the buffer returned by `sha3_Finalize` will have `X` bits of hash; * `sha3_InitX` also works as Reset (zeroization) of the hash context; no Free function is needed; See [`sha3.h`](sha3.h) for the exact interface. ## API fuzzing $ fuzz/run.sh The fuzzing script expects clang installed. ## Credits Thanks to @ralight for moving the test code into separate `sha3test.c` ## Notes SHA3-224 is not supported, but can easily be added. The code was written to work with the Microsoft Visual Studio compiler (under `_MSC_VER`), but this build target was not tested. This project was created to support [SHA3 in OpenPGP](https://tools.ietf.org/html/draft-jivsov-openpgp-sha3) work, but it applies to other protocols and formats, e.g. TLS. ================================================ FILE: fuzz/run.sh ================================================ #!/bin/sh THIS_SCRIPT=$(readlink -f $0) P=`dirname $THIS_SCRIPT` TOP=`dirname $P` cd $TOP make sha3fuzz && ./sha3fuzz $P/seeds -max_total_time=100 ================================================ FILE: fuzz/seeds/0a5dec3f2ed57a024ccba1041dc85e54e09f74d4 ================================================ + ================================================ FILE: fuzz/seeds/19852f1f4d08174b77ba2c88e0d8ec1455348b22 ================================================ 3  ================================================ FILE: fuzz/seeds/2daa36d007df33c974630657696ef4fbc665ca12 ================================================ dd ================================================ FILE: fuzz/seeds/3c363836cf4e16666669a25da280a1865c2d2874 ================================================ d ================================================ FILE: fuzz/seeds/71853c6197a6a7f222db0f1978c7cb232b87c5ee ================================================ ================================================ FILE: fuzz/seeds/98fc3c55ad129219ed5ffa43cd36a83fd6c2248e ================================================ ================================================ FILE: fuzz/seeds/a4bf6fc7ed78f9cdc178168a3a60070f3fae68ab ================================================ : ================================================ FILE: fuzz/seeds/a979ef10cc6f6a36df6b8a323307ee3bb2e2db9c ================================================ + ================================================ FILE: fuzz/seeds/b69e21c4d029acf5779df9a7167cb0b3d76b6a91 ================================================ vvvvv3  ================================================ FILE: fuzz/seeds/c63ae6dd4fc9f9dda66970e827d13f7c73fe841c ================================================ M ================================================ FILE: fuzz/seeds/f45250b51fd7511ea177e87492cfb303b73517b3 ================================================ ================================================ FILE: fuzz/sha3fuzz.c ================================================ #include #include #include #include "sha3.h" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { sha3_context c; const void *hash; uint8_t b; uint8_t buf[512/8]; unsigned is_keccak; if( Size < 1 ) return 0; b = Data[0]; Size --; Data ++; is_keccak = b & (1<<2); switch(b & 3) { case 0: sha3_Init256(&c); break; case 1: sha3_Init384(&c); break; case 2: sha3_Init512(&c); break; case 3: if(Size >= 2) sha3_HashBuffer((unsigned)Data[0] << 1, Data[1]/*SHA3_FLAGS_KECCAK or NONE*/, Data + 2, Size-2, buf, sizeof(buf)); return 0; } if( is_keccak ) sha3_SetFlags( &c, SHA3_FLAGS_KECCAK ); sha3_Update(&c, Data, Size); hash = sha3_Finalize(&c); return 0; } ================================================ FILE: sha3.c ================================================ /* ------------------------------------------------------------------------- * Works when compiled for either 32-bit or 64-bit targets, optimized for * 64 bit. * * Canonical implementation of Init/Update/Finalize for SHA-3 byte input. * * SHA3-256, SHA3-384, SHA-512 are implemented. SHA-224 can easily be added. * * Based on code from http://keccak.noekeon.org/ . * * I place the code that I wrote into public domain, free to use. * * I would appreciate if you give credits to this work if you used it to * write or test * your code. * * Aug 2015. Andrey Jivsov. crypto@brainhub.org * ---------------------------------------------------------------------- */ #include #include #include #include "sha3.h" #define SHA3_ASSERT( x ) #define SHA3_TRACE( format, ...) #define SHA3_TRACE_BUF(format, buf, l) /* * This flag is used to configure "pure" Keccak, as opposed to NIST SHA3. */ #define SHA3_USE_KECCAK_FLAG 0x80000000 #define SHA3_CW(x) ((x) & (~SHA3_USE_KECCAK_FLAG)) #if defined(_MSC_VER) #define SHA3_CONST(x) x #else #define SHA3_CONST(x) x##L #endif #ifndef SHA3_ROTL64 #define SHA3_ROTL64(x, y) \ (((x) << (y)) | ((x) >> ((sizeof(uint64_t)*8) - (y)))) #endif static const uint64_t keccakf_rndc[24] = { SHA3_CONST(0x0000000000000001UL), SHA3_CONST(0x0000000000008082UL), SHA3_CONST(0x800000000000808aUL), SHA3_CONST(0x8000000080008000UL), SHA3_CONST(0x000000000000808bUL), SHA3_CONST(0x0000000080000001UL), SHA3_CONST(0x8000000080008081UL), SHA3_CONST(0x8000000000008009UL), SHA3_CONST(0x000000000000008aUL), SHA3_CONST(0x0000000000000088UL), SHA3_CONST(0x0000000080008009UL), SHA3_CONST(0x000000008000000aUL), SHA3_CONST(0x000000008000808bUL), SHA3_CONST(0x800000000000008bUL), SHA3_CONST(0x8000000000008089UL), SHA3_CONST(0x8000000000008003UL), SHA3_CONST(0x8000000000008002UL), SHA3_CONST(0x8000000000000080UL), SHA3_CONST(0x000000000000800aUL), SHA3_CONST(0x800000008000000aUL), SHA3_CONST(0x8000000080008081UL), SHA3_CONST(0x8000000000008080UL), SHA3_CONST(0x0000000080000001UL), SHA3_CONST(0x8000000080008008UL) }; static const unsigned keccakf_rotc[24] = { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 }; static const unsigned keccakf_piln[24] = { 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 }; /* generally called after SHA3_KECCAK_SPONGE_WORDS-ctx->capacityWords words * are XORed into the state s */ static void keccakf(uint64_t s[25]) { int i, j, round; uint64_t t, bc[5]; #define KECCAK_ROUNDS 24 for(round = 0; round < KECCAK_ROUNDS; round++) { /* Theta */ for(i = 0; i < 5; i++) bc[i] = s[i] ^ s[i + 5] ^ s[i + 10] ^ s[i + 15] ^ s[i + 20]; for(i = 0; i < 5; i++) { t = bc[(i + 4) % 5] ^ SHA3_ROTL64(bc[(i + 1) % 5], 1); for(j = 0; j < 25; j += 5) s[j + i] ^= t; } /* Rho Pi */ t = s[1]; for(i = 0; i < 24; i++) { j = keccakf_piln[i]; bc[0] = s[j]; s[j] = SHA3_ROTL64(t, keccakf_rotc[i]); t = bc[0]; } /* Chi */ for(j = 0; j < 25; j += 5) { for(i = 0; i < 5; i++) bc[i] = s[j + i]; for(i = 0; i < 5; i++) s[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; } /* Iota */ s[0] ^= keccakf_rndc[round]; } } /* *************************** Public Inteface ************************ */ /* For Init or Reset call these: */ sha3_return_t sha3_Init(void *priv, unsigned bitSize) { sha3_context *ctx = (sha3_context *) priv; if( bitSize != 256 && bitSize != 384 && bitSize != 512 ) return SHA3_RETURN_BAD_PARAMS; memset(ctx, 0, sizeof(*ctx)); ctx->capacityWords = 2 * bitSize / (8 * sizeof(uint64_t)); return SHA3_RETURN_OK; } void sha3_Init256(void *priv) { sha3_Init(priv, 256); } void sha3_Init384(void *priv) { sha3_Init(priv, 384); } void sha3_Init512(void *priv) { sha3_Init(priv, 512); } enum SHA3_FLAGS sha3_SetFlags(void *priv, enum SHA3_FLAGS flags) { sha3_context *ctx = (sha3_context *) priv; flags &= SHA3_FLAGS_KECCAK; ctx->capacityWords |= (flags == SHA3_FLAGS_KECCAK ? SHA3_USE_KECCAK_FLAG : 0); return flags; } void sha3_Update(void *priv, void const *bufIn, size_t len) { sha3_context *ctx = (sha3_context *) priv; /* 0...7 -- how much is needed to have a word */ unsigned old_tail = (8 - ctx->byteIndex) & 7; size_t words; unsigned tail; size_t i; const uint8_t *buf = bufIn; SHA3_TRACE_BUF("called to update with:", buf, len); SHA3_ASSERT(ctx->byteIndex < 8); SHA3_ASSERT(ctx->wordIndex < sizeof(ctx->u.s) / sizeof(ctx->u.s[0])); if(len < old_tail) { /* have no complete word or haven't started * the word yet */ SHA3_TRACE("because %d<%d, store it and return", (unsigned)len, (unsigned)old_tail); /* endian-independent code follows: */ while (len--) ctx->saved |= (uint64_t) (*(buf++)) << ((ctx->byteIndex++) * 8); SHA3_ASSERT(ctx->byteIndex < 8); return; } if(old_tail) { /* will have one word to process */ SHA3_TRACE("completing one word with %d bytes", (unsigned)old_tail); /* endian-independent code follows: */ len -= old_tail; while (old_tail--) ctx->saved |= (uint64_t) (*(buf++)) << ((ctx->byteIndex++) * 8); /* now ready to add saved to the sponge */ ctx->u.s[ctx->wordIndex] ^= ctx->saved; SHA3_ASSERT(ctx->byteIndex == 8); ctx->byteIndex = 0; ctx->saved = 0; if(++ctx->wordIndex == (SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords))) { keccakf(ctx->u.s); ctx->wordIndex = 0; } } /* now work in full words directly from input */ SHA3_ASSERT(ctx->byteIndex == 0); words = len / sizeof(uint64_t); tail = len - words * sizeof(uint64_t); SHA3_TRACE("have %d full words to process", (unsigned)words); for(i = 0; i < words; i++, buf += sizeof(uint64_t)) { const uint64_t t = (uint64_t) (buf[0]) | ((uint64_t) (buf[1]) << 8 * 1) | ((uint64_t) (buf[2]) << 8 * 2) | ((uint64_t) (buf[3]) << 8 * 3) | ((uint64_t) (buf[4]) << 8 * 4) | ((uint64_t) (buf[5]) << 8 * 5) | ((uint64_t) (buf[6]) << 8 * 6) | ((uint64_t) (buf[7]) << 8 * 7); #if defined(__x86_64__ ) || defined(__i386__) SHA3_ASSERT(memcmp(&t, buf, 8) == 0); #endif ctx->u.s[ctx->wordIndex] ^= t; if(++ctx->wordIndex == (SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords))) { keccakf(ctx->u.s); ctx->wordIndex = 0; } } SHA3_TRACE("have %d bytes left to process, save them", (unsigned)tail); /* finally, save the partial word */ SHA3_ASSERT(ctx->byteIndex == 0 && tail < 8); while (tail--) { SHA3_TRACE("Store byte %02x '%c'", *buf, *buf); ctx->saved |= (uint64_t) (*(buf++)) << ((ctx->byteIndex++) * 8); } SHA3_ASSERT(ctx->byteIndex < 8); SHA3_TRACE("Have saved=0x%016" PRIx64 " at the end", ctx->saved); } /* This is simply the 'update' with the padding block. * The padding block is 0x01 || 0x00* || 0x80. First 0x01 and last 0x80 * bytes are always present, but they can be the same byte. */ void const * sha3_Finalize(void *priv) { sha3_context *ctx = (sha3_context *) priv; SHA3_TRACE("called with %d bytes in the buffer", ctx->byteIndex); /* Append 2-bit suffix 01, per SHA-3 spec. Instead of 1 for padding we * use 1<<2 below. The 0x02 below corresponds to the suffix 01. * Overall, we feed 0, then 1, and finally 1 to start padding. Without * M || 01, we would simply use 1 to start padding. */ uint64_t t; if( ctx->capacityWords & SHA3_USE_KECCAK_FLAG ) { /* Keccak version */ t = (uint64_t)(((uint64_t) 1) << (ctx->byteIndex * 8)); } else { /* SHA3 version */ t = (uint64_t)(((uint64_t)(0x02 | (1 << 2))) << ((ctx->byteIndex) * 8)); } ctx->u.s[ctx->wordIndex] ^= ctx->saved ^ t; ctx->u.s[SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords) - 1] ^= SHA3_CONST(0x8000000000000000UL); keccakf(ctx->u.s); /* Return first bytes of the ctx->s. This conversion is not needed for * little-endian platforms e.g. wrap with #if !defined(__BYTE_ORDER__) * || !defined(__ORDER_LITTLE_ENDIAN__) || __BYTE_ORDER__!=__ORDER_LITTLE_ENDIAN__ * ... the conversion below ... * #endif */ { unsigned i; for(i = 0; i < SHA3_KECCAK_SPONGE_WORDS; i++) { const unsigned t1 = (uint32_t) ctx->u.s[i]; const unsigned t2 = (uint32_t) ((ctx->u.s[i] >> 16) >> 16); ctx->u.sb[i * 8 + 0] = (uint8_t) (t1); ctx->u.sb[i * 8 + 1] = (uint8_t) (t1 >> 8); ctx->u.sb[i * 8 + 2] = (uint8_t) (t1 >> 16); ctx->u.sb[i * 8 + 3] = (uint8_t) (t1 >> 24); ctx->u.sb[i * 8 + 4] = (uint8_t) (t2); ctx->u.sb[i * 8 + 5] = (uint8_t) (t2 >> 8); ctx->u.sb[i * 8 + 6] = (uint8_t) (t2 >> 16); ctx->u.sb[i * 8 + 7] = (uint8_t) (t2 >> 24); } } SHA3_TRACE_BUF("Hash: (first 32 bytes)", ctx->u.sb, 256 / 8); return (ctx->u.sb); } sha3_return_t sha3_HashBuffer( unsigned bitSize, enum SHA3_FLAGS flags, const void *in, unsigned inBytes, void *out, unsigned outBytes ) { sha3_return_t err; sha3_context c; err = sha3_Init(&c, bitSize); if( err != SHA3_RETURN_OK ) return err; if( sha3_SetFlags(&c, flags) != flags ) { return SHA3_RETURN_BAD_PARAMS; } sha3_Update(&c, in, inBytes); const void *h = sha3_Finalize(&c); if(outBytes > bitSize/8) outBytes = bitSize/8; memcpy(out, h, outBytes); return SHA3_RETURN_OK; } ================================================ FILE: sha3.h ================================================ #ifndef SHA3_H #define SHA3_H #include /* ------------------------------------------------------------------------- * Works when compiled for either 32-bit or 64-bit targets, optimized for * 64 bit. * * Canonical implementation of Init/Update/Finalize for SHA-3 byte input. * * SHA3-256, SHA3-384, SHA-512 are implemented. SHA-224 can easily be added. * * Based on code from http://keccak.noekeon.org/ . * * I place the code that I wrote into public domain, free to use. * * I would appreciate if you give credits to this work if you used it to * write or test * your code. * * Aug 2015. Andrey Jivsov. crypto@brainhub.org * ---------------------------------------------------------------------- */ /* 'Words' here refers to uint64_t */ #define SHA3_KECCAK_SPONGE_WORDS \ (((1600)/8/*bits to byte*/)/sizeof(uint64_t)) typedef struct sha3_context_ { uint64_t saved; /* the portion of the input message that we * didn't consume yet */ union { /* Keccak's state */ uint64_t s[SHA3_KECCAK_SPONGE_WORDS]; uint8_t sb[SHA3_KECCAK_SPONGE_WORDS * 8]; } u; unsigned byteIndex; /* 0..7--the next byte after the set one * (starts from 0; 0--none are buffered) */ unsigned wordIndex; /* 0..24--the next word to integrate input * (starts from 0) */ unsigned capacityWords; /* the double size of the hash output in * words (e.g. 16 for Keccak 512) */ } sha3_context; enum SHA3_FLAGS { SHA3_FLAGS_NONE=0, SHA3_FLAGS_KECCAK=1 }; enum SHA3_RETURN { SHA3_RETURN_OK=0, SHA3_RETURN_BAD_PARAMS=1 }; typedef enum SHA3_RETURN sha3_return_t; /* For Init or Reset call these: */ sha3_return_t sha3_Init(void *priv, unsigned bitSize); void sha3_Init256(void *priv); void sha3_Init384(void *priv); void sha3_Init512(void *priv); enum SHA3_FLAGS sha3_SetFlags(void *priv, enum SHA3_FLAGS); void sha3_Update(void *priv, void const *bufIn, size_t len); void const *sha3_Finalize(void *priv); /* Single-call hashing */ sha3_return_t sha3_HashBuffer( unsigned bitSize, /* 256, 384, 512 */ enum SHA3_FLAGS flags, /* SHA3_FLAGS_NONE or SHA3_FLAGS_KECCAK */ const void *in, unsigned inBytes, void *out, unsigned outBytes ); /* up to bitSize/8; truncation OK */ #endif ================================================ FILE: sha3sum.c ================================================ /* ------------------------------------------------------------------------- * Run SHA-3 (NIST FIPS 202) on the given file. * * Call as * * sha3sum 256|384|512 file_path * * See sha3.c for additional details. * * Jun 2018. Andrey Jivsov. crypto@brainhub.org * ---------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include "sha3.h" static void help(const char *argv0) { printf("To call: %s 256|384|512 [-k] file_path.\n", argv0); } static void byte_to_hex(uint8_t b, char s[23]) { unsigned i=1; s[0] = s[1] = '0'; s[2] = '\0'; while(b) { unsigned t = b & 0x0f; if( t < 10 ) { s[i] = '0' + t; } else { s[i] = 'a' + t - 10; } i--; b >>= 4; } } int main(int argc, char *argv[]) { sha3_context c; const uint8_t *hash; unsigned image_size; const char *file_path; int fd; struct stat st; void *p; unsigned i; unsigned use_keccak = 0; if( argc != 3 && argc != 4 ) { help(argv[0]); return 1; } image_size = atoi(argv[1]); switch( image_size ) { case 256: case 384: case 512: break; default: help(argv[0]); return 1; } file_path = argv[2]; if( argc == 4 && file_path[0] == '-' && file_path[1] == 'k' ) { use_keccak = 1; file_path = argv[3]; } if( access(file_path, R_OK)!=0 ) { printf("Cannot read file '%s'", file_path); return 2; } fd = open(file_path, O_RDONLY); if( fd == -1 ) { printf("Cannot open file '%s' for reading", file_path); return 2; } i = fstat(fd, &st); if( i ) { close(fd); printf("Cannot determine the size of file '%s'", file_path); return 2; } p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if( p==NULL ) { printf("Cannot memory-map file '%s'", file_path); return 2; } switch(image_size) { case 256: sha3_Init256(&c); break; case 384: sha3_Init384(&c); break; case 512: sha3_Init512(&c); break; } if( use_keccak ) { enum SHA3_FLAGS flags2 = sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); if( flags2 != SHA3_FLAGS_KECCAK ) { printf("Failed to set Keccak mode"); return 2; } } sha3_Update(&c, p, st.st_size); hash = sha3_Finalize(&c); munmap(p, st.st_size); for(i=0; i #include #include #include "sha3.h" int main() { uint8_t buf[200]; sha3_context c; const void *hash; unsigned i; const uint8_t c1 = 0xa3; /* [FIPS 202] KAT follow */ static const uint8_t sha3_256_empty[256 / 8] = { 0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66, 0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61, 0xd6, 0x62, 0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa, 0x82, 0xd8, 0x0a, 0x4b, 0x80, 0xf8, 0x43, 0x4a }; static const uint8_t sha3_256_0xa3_200_times[256 / 8] = { 0x79, 0xf3, 0x8a, 0xde, 0xc5, 0xc2, 0x03, 0x07, 0xa9, 0x8e, 0xf7, 0x6e, 0x83, 0x24, 0xaf, 0xbf, 0xd4, 0x6c, 0xfd, 0x81, 0xb2, 0x2e, 0x39, 0x73, 0xc6, 0x5f, 0xa1, 0xbd, 0x9d, 0xe3, 0x17, 0x87 }; static const uint8_t sha3_384_0xa3_200_times[384 / 8] = { 0x18, 0x81, 0xde, 0x2c, 0xa7, 0xe4, 0x1e, 0xf9, 0x5d, 0xc4, 0x73, 0x2b, 0x8f, 0x5f, 0x00, 0x2b, 0x18, 0x9c, 0xc1, 0xe4, 0x2b, 0x74, 0x16, 0x8e, 0xd1, 0x73, 0x26, 0x49, 0xce, 0x1d, 0xbc, 0xdd, 0x76, 0x19, 0x7a, 0x31, 0xfd, 0x55, 0xee, 0x98, 0x9f, 0x2d, 0x70, 0x50, 0xdd, 0x47, 0x3e, 0x8f }; static const uint8_t sha3_512_0xa3_200_times[512 / 8] = { 0xe7, 0x6d, 0xfa, 0xd2, 0x20, 0x84, 0xa8, 0xb1, 0x46, 0x7f, 0xcf, 0x2f, 0xfa, 0x58, 0x36, 0x1b, 0xec, 0x76, 0x28, 0xed, 0xf5, 0xf3, 0xfd, 0xc0, 0xe4, 0x80, 0x5d, 0xc4, 0x8c, 0xae, 0xec, 0xa8, 0x1b, 0x7c, 0x13, 0xc3, 0x0a, 0xdf, 0x52, 0xa3, 0x65, 0x95, 0x84, 0x73, 0x9a, 0x2d, 0xf4, 0x6b, 0xe5, 0x89, 0xc5, 0x1c, 0xa1, 0xa4, 0xa8, 0x41, 0x6d, 0xf6, 0x54, 0x5a, 0x1c, 0xe8, 0xba, 0x00 }; /* ---- "pure" Keccak algorithm begins; from [Keccak] ----- */ sha3_HashBuffer(256, SHA3_FLAGS_KECCAK, "abc", 3, buf, sizeof(buf)); if(memcmp(buf, "\x4e\x03\x65\x7a\xea\x45\xa9\x4f" "\xc7\xd4\x7b\xa8\x26\xc8\xd6\x67" "\xc0\xd1\xe6\xe3\x3a\x64\xa0\x36" "\xec\x44\xf5\x8f\xa1\x2d\x6c\x45", 256 / 8) != 0) { printf("SHA3-256(abc) " "doesn't match known answer (single buffer)\n"); return 10; } sha3_Init256(&c); sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); sha3_Update(&c, "\xcc", 1); hash = sha3_Finalize(&c); if(memcmp(hash, "\xee\xad\x6d\xbf\xc7\x34\x0a\x56" "\xca\xed\xc0\x44\x69\x6a\x16\x88" "\x70\x54\x9a\x6a\x7f\x6f\x56\x96" "\x1e\x84\xa5\x4b\xd9\x97\x0b\x8a", 256 / 8) != 0) { printf("SHA3-256(cc) " "doesn't match known answer (single buffer)\n"); return 11; } sha3_Init256(&c); sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); sha3_Update(&c, "\x41\xfb", 2); hash = sha3_Finalize(&c); if(memcmp(hash, "\xa8\xea\xce\xda\x4d\x47\xb3\x28" "\x1a\x79\x5a\xd9\xe1\xea\x21\x22" "\xb4\x07\xba\xf9\xaa\xbc\xb9\xe1" "\x8b\x57\x17\xb7\x87\x35\x37\xd2", 256 / 8) != 0) { printf("SHA3-256(41fb) " "doesn't match known answer (single buffer)\n"); return 12; } sha3_Init256(&c); sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); sha3_Update(&c, "\x52\xa6\x08\xab\x21\xcc\xdd\x8a" "\x44\x57\xa5\x7e\xde\x78\x21\x76", 128 / 8); hash = sha3_Finalize(&c); if(memcmp(hash, "\x0e\x32\xde\xfa\x20\x71\xf0\xb5" "\xac\x0e\x6a\x10\x8b\x84\x2e\xd0" "\xf1\xd3\x24\x97\x12\xf5\x8e\xe0" "\xdd\xf9\x56\xfe\x33\x2a\x5f\x95", 256 / 8) != 0) { printf("SHA3-256(52a6...76) " "doesn't match known answer (single buffer)\n"); return 13; } sha3_Init256(&c); sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); sha3_Update(&c, "\x43\x3c\x53\x03\x13\x16\x24\xc0" "\x02\x1d\x86\x8a\x30\x82\x54\x75" "\xe8\xd0\xbd\x30\x52\xa0\x22\x18" "\x03\x98\xf4\xca\x44\x23\xb9\x82" "\x14\xb6\xbe\xaa\xc2\x1c\x88\x07" "\xa2\xc3\x3f\x8c\x93\xbd\x42\xb0" "\x92\xcc\x1b\x06\xce\xdf\x32\x24" "\xd5\xed\x1e\xc2\x97\x84\x44\x4f" "\x22\xe0\x8a\x55\xaa\x58\x54\x2b" "\x52\x4b\x02\xcd\x3d\x5d\x5f\x69" "\x07\xaf\xe7\x1c\x5d\x74\x62\x22" "\x4a\x3f\x9d\x9e\x53\xe7\xe0\x84" "\x6d\xcb\xb4\xce", 800 / 8); hash = sha3_Finalize(&c); if(memcmp(hash, "\xce\x87\xa5\x17\x3b\xff\xd9\x23" "\x99\x22\x16\x58\xf8\x01\xd4\x5c" "\x29\x4d\x90\x06\xee\x9f\x3f\x9d" "\x41\x9c\x8d\x42\x77\x48\xdc\x41", 256 / 8) != 0) { printf("SHA3-256(433C...CE) " "doesn't match known answer (single buffer)\n"); return 14; } /* SHA3-256 byte-by-byte: 16777216 steps. ExtremelyLongMsgKAT_256 * [Keccak] */ i = 16777216; sha3_Init256(&c); sha3_SetFlags(&c, SHA3_FLAGS_KECCAK); while (i--) { sha3_Update(&c, "abcdefghbcdefghicdefghijdefghijk" "efghijklfghijklmghijklmnhijklmno", 64); } hash = sha3_Finalize(&c); if(memcmp(hash, "\x5f\x31\x3c\x39\x96\x3d\xcf\x79" "\x2b\x54\x70\xd4\xad\xe9\xf3\xa3" "\x56\xa3\xe4\x02\x17\x48\x69\x0a" "\x95\x83\x72\xe2\xb0\x6f\x82\xa4", 256 / 8) != 0) { printf("SHA3-256( abcdefgh...[16777216 times] ) " "doesn't match known answer\n"); return 15; } printf("Keccak-256 tests passed OK\n"); /* ----- SHA3 testing begins ----- */ /* SHA-256 on an empty buffer */ sha3_Init256(&c); hash = sha3_Finalize(&c); if(memcmp(sha3_256_empty, hash, sizeof(sha3_256_empty)) != 0) { printf("SHA3-256() doesn't match known answer\n"); return 1; } sha3_HashBuffer(256, SHA3_FLAGS_NONE, "abc", 3, buf, sizeof(buf)); if(memcmp(buf, "\x3a\x98\x5d\xa7\x4f\xe2\x25\xb2" "\x04\x5c\x17\x2d\x6b\xd3\x90\xbd" "\x85\x5f\x08\x6e\x3e\x9d\x52\x5b" "\x46\xbf\xe2\x45\x11\x43\x15\x32", 256 / 8) != 0) { printf("SHA3-256(abc) " "doesn't match known answer (single buffer)\n"); return 10; } memset(buf, c1, sizeof(buf)); /* set to value c1 */ /* SHA3-256 as a single buffer. [FIPS 202] */ sha3_Init256(&c); sha3_Update(&c, buf, sizeof(buf)); hash = sha3_Finalize(&c); if(memcmp(sha3_256_0xa3_200_times, hash, sizeof(sha3_256_0xa3_200_times)) != 0) { printf("SHA3-256( 0xa3 ... [200 times] ) " "doesn't match known answer (1 buffer)\n"); return 1; } /* SHA3-256 in two steps. [FIPS 202] */ sha3_Init256(&c); sha3_Update(&c, buf, sizeof(buf) / 2); sha3_Update(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2); hash = sha3_Finalize(&c); if(memcmp(sha3_256_0xa3_200_times, hash, sizeof(sha3_256_0xa3_200_times)) != 0) { printf("SHA3-256( 0xa3 ... [200 times] ) " "doesn't match known answer (2 steps)\n"); return 2; } /* SHA3-256 byte-by-byte: 200 steps. [FIPS 202] */ i = 200; sha3_Init256(&c); while (i--) { sha3_Update(&c, &c1, 1); } hash = sha3_Finalize(&c); if(memcmp(sha3_256_0xa3_200_times, hash, sizeof(sha3_256_0xa3_200_times)) != 0) { printf("SHA3-256( 0xa3 ... [200 times] ) " "doesn't match known answer (200 steps)\n"); return 3; } /* SHA3-256 byte-by-byte: 135 bytes. Input from [Keccak]. Output * matched with sha3sum. */ sha3_Init256(&c); sha3_Update(&c, "\xb7\x71\xd5\xce\xf5\xd1\xa4\x1a" "\x93\xd1\x56\x43\xd7\x18\x1d\x2a" "\x2e\xf0\xa8\xe8\x4d\x91\x81\x2f" "\x20\xed\x21\xf1\x47\xbe\xf7\x32" "\xbf\x3a\x60\xef\x40\x67\xc3\x73" "\x4b\x85\xbc\x8c\xd4\x71\x78\x0f" "\x10\xdc\x9e\x82\x91\xb5\x83\x39" "\xa6\x77\xb9\x60\x21\x8f\x71\xe7" "\x93\xf2\x79\x7a\xea\x34\x94\x06" "\x51\x28\x29\x06\x5d\x37\xbb\x55" "\xea\x79\x6f\xa4\xf5\x6f\xd8\x89" "\x6b\x49\xb2\xcd\x19\xb4\x32\x15" "\xad\x96\x7c\x71\x2b\x24\xe5\x03" "\x2d\x06\x52\x32\xe0\x2c\x12\x74" "\x09\xd2\xed\x41\x46\xb9\xd7\x5d" "\x76\x3d\x52\xdb\x98\xd9\x49\xd3" "\xb0\xfe\xd6\xa8\x05\x2f\xbb", 1080 / 8); hash = sha3_Finalize(&c); if(memcmp(hash, "\xa1\x9e\xee\x92\xbb\x20\x97\xb6" "\x4e\x82\x3d\x59\x77\x98\xaa\x18" "\xbe\x9b\x7c\x73\x6b\x80\x59\xab" "\xfd\x67\x79\xac\x35\xac\x81\xb5", 256 / 8) != 0) { printf("SHA3-256( b771 ... ) doesn't match the known answer\n"); return 4; } /* SHA3-384 as a single buffer. [FIPS 202] */ sha3_Init384(&c); sha3_Update(&c, buf, sizeof(buf)); hash = sha3_Finalize(&c); if(memcmp(sha3_384_0xa3_200_times, hash, sizeof(sha3_384_0xa3_200_times)) != 0) { printf("SHA3-384( 0xa3 ... [200 times] ) " "doesn't match known answer (1 buffer)\n"); return 5; } /* SHA3-384 in two steps. [FIPS 202] */ sha3_Init384(&c); sha3_Update(&c, buf, sizeof(buf) / 2); sha3_Update(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2); hash = sha3_Finalize(&c); if(memcmp(sha3_384_0xa3_200_times, hash, sizeof(sha3_384_0xa3_200_times)) != 0) { printf("SHA3-384( 0xa3 ... [200 times] ) " "doesn't match known answer (2 steps)\n"); return 6; } /* SHA3-384 byte-by-byte: 200 steps. [FIPS 202] */ i = 200; sha3_Init384(&c); while (i--) { sha3_Update(&c, &c1, 1); } hash = sha3_Finalize(&c); if(memcmp(sha3_384_0xa3_200_times, hash, sizeof(sha3_384_0xa3_200_times)) != 0) { printf("SHA3-384( 0xa3 ... [200 times] ) " "doesn't match known answer (200 steps)\n"); return 7; } /* SHA3-512 as a single buffer. [FIPS 202] */ sha3_Init512(&c); sha3_Update(&c, buf, sizeof(buf)); hash = sha3_Finalize(&c); if(memcmp(sha3_512_0xa3_200_times, hash, sizeof(sha3_512_0xa3_200_times)) != 0) { printf("SHA3-512( 0xa3 ... [200 times] ) " "doesn't match known answer (1 buffer)\n"); return 8; } /* SHA3-512 in two steps. [FIPS 202] */ sha3_Init512(&c); sha3_Update(&c, buf, sizeof(buf) / 2); sha3_Update(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2); hash = sha3_Finalize(&c); if(memcmp(sha3_512_0xa3_200_times, hash, sizeof(sha3_512_0xa3_200_times)) != 0) { printf("SHA3-512( 0xa3 ... [200 times] ) " "doesn't match known answer (2 steps)\n"); return 9; } /* SHA3-512 byte-by-byte: 200 steps. [FIPS 202] */ i = 200; sha3_Init512(&c); while (i--) { sha3_Update(&c, &c1, 1); } hash = sha3_Finalize(&c); if(memcmp(sha3_512_0xa3_200_times, hash, sizeof(sha3_512_0xa3_200_times)) != 0) { printf("SHA3-512( 0xa3 ... [200 times] ) " "doesn't match known answer (200 steps)\n"); return 10; } printf("SHA3-256, SHA3-384, SHA3-512 tests passed OK\n"); return 0; }