From: Marko Kreen Date: Mon, 29 Oct 2012 17:14:40 +0000 (+0200) Subject: crypto: Add Keccak (SHA3) algorithm X-Git-Url: http://git.postgresql.org/gitweb/delmail?a=commitdiff_plain;h=92b72f912e3a51cd8c4178d50ef861fd092cd00d;p=libusual.git crypto: Add Keccak (SHA3) algorithm It is based on Keccak reference implementation, but cleaned up for SHA3-only usage. --- diff --git a/Makefile b/Makefile index 20f3385..737e5d2 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ libusual_la_SOURCES = usual/config.h.in \ usual/crc32.h usual/crc32.c \ usual/crypto/digest.h usual/crypto/digest.c \ usual/crypto/hmac.h usual/crypto/hmac.c \ + usual/crypto/keccak.h usual/crypto/keccak.c \ usual/crypto/md5.h usual/crypto/md5.c \ usual/crypto/sha1.h usual/crypto/sha1.c \ usual/crypto/sha256.h usual/crypto/sha256.c \ diff --git a/doc/mainpage.dox b/doc/mainpage.dox index a65f1ed..31ac12b 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -69,6 +69,7 @@ * SHA1 hash * SHA256/224 hashes * SHA512/384 hashes + * Keccak/SHA3 hashes * Memory Allocation * Context Allocator framework * Extra allocators diff --git a/test/test_crypto.c b/test/test_crypto.c index dc3936a..041fa8a 100644 --- a/test/test_crypto.c +++ b/test/test_crypto.c @@ -11,12 +11,13 @@ #include #include #include +#include #include #include static const char *mkhex(const uint8_t *src, int len) { - static char buf[128]; + static char buf[1024 + 1]; static const char hextbl[] = "0123456789abcdef"; int i; for (i = 0; i < len; i++) { @@ -27,13 +28,61 @@ static const char *mkhex(const uint8_t *src, int len) return buf; } -static const char *run_hash(const char *str, const struct DigestInfo *impl) +static int hexval(char v) +{ + if (v >= '0' && v <= '9') + return v - '0'; + if (v >= 'a' && v <= 'f') + return v - 'a' + 10; + if (v >= 'A' && v <= 'F') + return v - 'A' + 10; + return -1; +} + +static uint8_t *fromhex(const char *input, int len) +{ + uint8_t *res; + const char *s = input; + int i, b, b1, b2; + + res = malloc(len+1); + if (!res) + return NULL; + + for (i = 0; i < len; i++) { + if (*s == '\0') + s = input; + b1 = hexval(*s++); + b2 = hexval(*s++); + b = (b1 << 4) | b2; + if (b < 0) { + free(res); + return NULL; + } + res[i] = b; + } + + return res; +} + +static const char *run_hash(const char *str, const char *hexstr, const struct DigestInfo *impl) { struct DigestContext *ctx; uint8_t res[512]; uint8_t res2[512]; - int i, len = strlen(str), step; + int i, len, step; int reslen; + uint8_t *buf = NULL; + + if (hexstr) { + len = strlen(hexstr) / 2; + buf = fromhex(hexstr, len); + if (!buf) + return "NOMEM"; + str = (char *)buf; + } else { + len = strlen(str); + } ctx = digest_new(impl, USUAL_ALLOC); if (!ctx) @@ -52,6 +101,9 @@ static const char *run_hash(const char *str, const struct DigestInfo *impl) digest_free(ctx); + if (buf) + free(buf); + if (memcmp(res, res2, reslen) != 0) return "FAIL"; @@ -64,7 +116,7 @@ static const char *run_hash(const char *str, const struct DigestInfo *impl) static const char *run_md5(const char *str) { - return run_hash(str, digest_MD5()); + return run_hash(str, NULL, digest_MD5()); } static void test_md5(void *ptr) @@ -85,7 +137,7 @@ end:; static const char *run_sha1(const char *str) { - return run_hash(str, digest_SHA1()); + return run_hash(str, NULL, digest_SHA1()); } static void test_sha1(void *ptr) @@ -106,7 +158,7 @@ end:; static const char *run_sha224(const char *str) { - return run_hash(str, digest_SHA224()); + return run_hash(str, NULL, digest_SHA224()); } static void test_sha224(void *ptr) @@ -125,7 +177,7 @@ end:; static const char *run_sha256(const char *str) { - return run_hash(str, digest_SHA256()); + return run_hash(str, NULL, digest_SHA256()); } static void test_sha256(void *ptr) @@ -144,7 +196,7 @@ end:; static const char *run_sha384(const char *str) { - return run_hash(str, digest_SHA384()); + return run_hash(str, NULL, digest_SHA384()); } static void test_sha384(void *ptr) @@ -167,7 +219,7 @@ end:; static const char *run_sha512(const char *str) { - return run_hash(str, digest_SHA512()); + return run_hash(str, NULL, digest_SHA512()); } static void test_sha512(void *ptr) @@ -184,6 +236,168 @@ static void test_sha512(void *ptr) end:; } +/* + * Keccak-224 + */ + +static const char *run_keccak224(const char *hex) +{ + return run_hash(NULL, hex, digest_KECCAK224()); +} + +static void test_keccak224(void *ptr) +{ + str_check(run_keccak224(""), "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd"); + str_check(run_keccak224("CC"), "a9cab59eb40a10b246290f2d6086e32e3689faf1d26b470c899f2802"); + str_check(run_keccak224("41FB"), "615ba367afdc35aac397bc7eb5d58d106a734b24986d5d978fefd62c"); + str_check(run_keccak224("1F877C"), "6f9d2898efd096baaaaab2e97482ddb6389b8e6caa964b7a0e347e13"); + str_check(run_keccak224("C1ECFDFC"), "e405869da1464a705700a3cbce131aabeeba9c8d2fe6576b21bcbe16"); + str_check(run_keccak224("21F134AC57"), "5573da2b02216a860389a581f6e9fb8d805e9e02f6fa911701eee298"); + str_check(run_keccak224("C6F50BB74E29"), "163c9060163aa66b8b7c0cfaa65d934bff219bcbc267187caba0042f"); + str_check(run_keccak224("119713CC83EEEF"), "cfc04c6f8463ddab24cdf8b8652bd11df23dd1b95f118328dd01580e"); + str_check(run_keccak224("4A4F202484512526"), "7a5c2cb3f999dd00eff7399963314ca647dd0e5ae1bddec611f8338d"); + str_check(run_keccak224("B32D95B0B9AAD2A8816DE6D06D1F86008505BD8C14124F6E9A163B5A2ADE55F835D0EC3880EF50700D3B25E42CC0AF050CCD1BE5E555B23087E04D7BF9813622780C7313A1954F8740B6EE2D3F71F768DD417F520482BD3A08D4F222B4EE9DBD015447B33507DD50F3AB4247C5DE9A8ABD62A8DECEA01E3B87C8B927F5B08BEB37674C6F8E380C04"), + "42275c296937745758ff2b7bee9a897191ae87e42bd10198d9466c19"); + str_check(run_keccak224("04410E31082A47584B406F051398A6ABE74E4DA59BB6F85E6B49E8A1F7F2CA00DFBA5462C2CD2BFDE8B64FB21D70C083F11318B56A52D03B81CAC5EEC29EB31BD0078B6156786DA3D6D8C33098C5C47BB67AC64DB14165AF65B44544D806DDE5F487D5373C7F9792C299E9686B7E5821E7C8E2458315B996B5677D926DAC57B3F22DA873C601016A0D"), + "143f9055eb1f736729c77721fb65ed5ee142f6e969132fb22989c11f"); + str_check(run_keccak224("3A3A819C48EFDE2AD914FBF00E18AB6BC4F14513AB27D0C178A188B61431E7F5623CB66B23346775D386B50E982C493ADBBFC54B9A3CD383382336A1A0B2150A15358F336D03AE18F666C7573D55C4FD181C29E6CCFDE63EA35F0ADF5885CFC0A3D84A2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AADC66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B6183639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1"), + "5af56987ea9cf11fcd0eac5ebc14b037365e9b1123e31cb2dfc7929a"); +end:; +} + +/* + * Keccak-256 + */ + +static const char *run_keccak256(const char *hex) +{ + return run_hash(NULL, hex, digest_KECCAK256()); +} + +static void test_keccak256(void *ptr) +{ + str_check(run_keccak256(""), "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + str_check(run_keccak256("CC"), "eead6dbfc7340a56caedc044696a168870549a6a7f6f56961e84a54bd9970b8a"); + str_check(run_keccak256("41FB"), "a8eaceda4d47b3281a795ad9e1ea2122b407baf9aabcb9e18b5717b7873537d2"); + str_check(run_keccak256("1F877C"), "627d7bc1491b2ab127282827b8de2d276b13d7d70fb4c5957fdf20655bc7ac30"); + str_check(run_keccak256("C1ECFDFC"), "b149e766d7612eaf7d55f74e1a4fdd63709a8115b14f61fcd22aa4abc8b8e122"); + str_check(run_keccak256("21F134AC57"), "67f05544dbe97d5d6417c1b1ea9bc0e3a99a541381d1cd9b08a9765687eb5bb4"); + str_check(run_keccak256("C6F50BB74E29"), "923062c4e6f057597220d182dbb10e81cd25f60b54005b2a75dd33d6dac518d0"); + str_check(run_keccak256("119713CC83EEEF"), "feb8405dcd315d48c6cbf7a3504996de8e25cc22566efec67433712eda99894f"); + str_check(run_keccak256("4A4F202484512526"), "e620d8f2982b24fedaaa3baa9b46c3f9ce204ee356666553ecb35e15c3ff9bf9"); + str_check(run_keccak256("B32D95B0B9AAD2A8816DE6D06D1F86008505BD8C14124F6E9A163B5A2ADE55F835D0EC3880EF50700D3B25E42CC0AF050CCD1BE5E555B23087E04D7BF9813622780C7313A1954F8740B6EE2D3F71F768DD417F520482BD3A08D4F222B4EE9DBD015447B33507DD50F3AB4247C5DE9A8ABD62A8DECEA01E3B87C8B927F5B08BEB37674C6F8E380C04"), + "e717a7769448abbe5fef8187954a88ac56ded1d22e63940ab80d029585a21921"); + str_check(run_keccak256("04410E31082A47584B406F051398A6ABE74E4DA59BB6F85E6B49E8A1F7F2CA00DFBA5462C2CD2BFDE8B64FB21D70C083F11318B56A52D03B81CAC5EEC29EB31BD0078B6156786DA3D6D8C33098C5C47BB67AC64DB14165AF65B44544D806DDE5F487D5373C7F9792C299E9686B7E5821E7C8E2458315B996B5677D926DAC57B3F22DA873C601016A0D"), + "a95d50b50b4545f0947441df74a1e9d74622eb3baa49c1bbfc3a0cce6619c1aa"); + str_check(run_keccak256("3A3A819C48EFDE2AD914FBF00E18AB6BC4F14513AB27D0C178A188B61431E7F5623CB66B23346775D386B50E982C493ADBBFC54B9A3CD383382336A1A0B2150A15358F336D03AE18F666C7573D55C4FD181C29E6CCFDE63EA35F0ADF5885CFC0A3D84A2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AADC66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B6183639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1"), + "348fb774adc970a16b1105669442625e6adaa8257a89effdb5a802f161b862ea"); +end:; +} + +/* + * Keccak-384 + */ + +static const char *run_keccak384(const char *hex) +{ + return run_hash(NULL, hex, digest_KECCAK384()); +} + +static void test_keccak384(void *ptr) +{ + str_check(run_keccak384(""), "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff"); + str_check(run_keccak384("CC"), "1b84e62a46e5a201861754af5dc95c4a1a69caf4a796ae405680161e29572641f5fa1e8641d7958336ee7b11c58f73e9"); + str_check(run_keccak384("41FB"), "495cce2714cd72c8c53c3363d22c58b55960fe26be0bf3bbc7a3316dd563ad1db8410e75eefea655e39d4670ec0b1792"); + str_check(run_keccak384("1F877C"), "b0665c345f45e6de145b0190335ef5d5aa59e0b49fc1425d5eae7355ea442284cb8a2152d565ebdf2810eccab15af04f"); + str_check(run_keccak384("C1ECFDFC"), "f1850b2abb24f3fd683c701582789d9e92b6a45f9c345f9dae7f7997c8c910e88003e592e59281cf92c92d6b51a1afd1"); + str_check(run_keccak384("21F134AC57"), "68d437327f158287c304bbaf36f782f497da2c480a1fbb268682362218641f9070a014919ad7331c49beefccb437fe9a"); + str_check(run_keccak384("C6F50BB74E29"), "03566ec003ff55184f0c85beebc6d1ecf5e5d082d8d40137246f8fd42bce097c09418845ef60286fdd894a00fd2d6589"); + str_check(run_keccak384("119713CC83EEEF"), "790d700fa34d6a835be311b639474780148a2f087ac2fa86e8a1a433ec7a04fcbfc5284a3e188b7d91c6d094eafbeecb"); + str_check(run_keccak384("4A4F202484512526"), "638e65758a297cb09ded1ac5b9e8f779802000ab791f67f33c60be36443793adcc8a4a58e98688157a41784f02a4bcb2"); + str_check(run_keccak384("B32D95B0B9AAD2A8816DE6D06D1F86008505BD8C14124F6E9A163B5A2ADE55F835D0EC3880EF50700D3B25E42CC0AF050CCD1BE5E555B23087E04D7BF9813622780C7313A1954F8740B6EE2D3F71F768DD417F520482BD3A08D4F222B4EE9DBD015447B33507DD50F3AB4247C5DE9A8ABD62A8DECEA01E3B87C8B927F5B08BEB37674C6F8E380C04"), + "278e83cff1ff6cc4b3ac41f3879da87ae63b535b43815e273687a4cc519855b452cb6af0198bb9fd0f3e43739bc0cdd7"); + str_check(run_keccak384("04410E31082A47584B406F051398A6ABE74E4DA59BB6F85E6B49E8A1F7F2CA00DFBA5462C2CD2BFDE8B64FB21D70C083F11318B56A52D03B81CAC5EEC29EB31BD0078B6156786DA3D6D8C33098C5C47BB67AC64DB14165AF65B44544D806DDE5F487D5373C7F9792C299E9686B7E5821E7C8E2458315B996B5677D926DAC57B3F22DA873C601016A0D"), + "aa4b5a5fb94fe19578f33323ba1eefc5b6ed70b34bc70193f386c99f73863611af20581b4b1b3ed776df9e235d3d4e45"); + str_check(run_keccak384("3A3A819C48EFDE2AD914FBF00E18AB6BC4F14513AB27D0C178A188B61431E7F5623CB66B23346775D386B50E982C493ADBBFC54B9A3CD383382336A1A0B2150A15358F336D03AE18F666C7573D55C4FD181C29E6CCFDE63EA35F0ADF5885CFC0A3D84A2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AADC66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B6183639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1"), + "6bff1c8405a3fe594e360e3bccea1ebcd509310dc79b9e45c263783d7a5dd662c6789b18bd567dbdda1554f5bee6a860"); +end:; +} + +/* + * Keccak-512 + */ + +static const char *run_keccak512(const char *hex) +{ + return run_hash(NULL, hex, digest_KECCAK512()); +} + +static void test_keccak512(void *ptr) +{ + str_check(run_keccak512(""), "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e"); + str_check(run_keccak512("CC"), "8630c13cbd066ea74bbe7fe468fec1dee10edc1254fb4c1b7c5fd69b646e44160b8ce01d05a0908ca790dfb080f4b513bc3b6225ece7a810371441a5ac666eb9"); + str_check(run_keccak512("41FB"), "551da6236f8b96fce9f97f1190e901324f0b45e06dbbb5cdb8355d6ed1dc34b3f0eae7dcb68622ff232fa3cece0d4616cdeb3931f93803662a28df1cd535b731"); + str_check(run_keccak512("1F877C"), "eb7f2a98e00af37d964f7d8c44c1fb6e114d8ee21a7b976ae736539efdc1e3fe43becef5015171e6da30168cae99a82c53fa99042774ef982c01626a540f08c0"); + str_check(run_keccak512("C1ECFDFC"), "952d4c0a6f0ef5ce438c52e3edd345ea00f91cf5da8097c1168a16069e958fc05bad90a0c5fb4dd9ec28e84b226b94a847d6bb89235692ef4c9712f0c7030fae"); + str_check(run_keccak512("21F134AC57"), "2e76d93affd62b92fc4f29cb83efbe4ba21d88426aa7f075bfc20960ea258787898172e17045af43ab1fe445532be0185fbea84d9be788b05f14dbf4856a5254"); + str_check(run_keccak512("C6F50BB74E29"), "40fa8074e1e509b206448fbe757d9494b9b51e8d6e674a67f53c11ef92e96c3ea08b95ebd4172b020010cd6cf29539a34d6bfa002a2042787aa8d879a0f5b54c"); + str_check(run_keccak512("119713CC83EEEF"), "d1116786a3c1ea46a8f22d82abb4c5d06dc0691b2e747ac9726d0b290e6959f7b23428519a656b237695e56403855ec4c98db0cf87f31b6ceabf2b9b8589b713"); + str_check(run_keccak512("4A4F202484512526"), "f326c7c126ddc277922760feef77c9bab6fb5d3430f652593703d7c5e30135cd0b0575257509a624184330d6ab1f508a666391b5d4690426b4e05301891df897"); + str_check(run_keccak512("B32D95B0B9AAD2A8816DE6D06D1F86008505BD8C14124F6E9A163B5A2ADE55F835D0EC3880EF50700D3B25E42CC0AF050CCD1BE5E555B23087E04D7BF9813622780C7313A1954F8740B6EE2D3F71F768DD417F520482BD3A08D4F222B4EE9DBD015447B33507DD50F3AB4247C5DE9A8ABD62A8DECEA01E3B87C8B927F5B08BEB37674C6F8E380C04"), + "a6054ffc3d81591be964c4b004a3a21142365b59ee98b2873d488293f93a8d7154bf72100012c60d3c9418f6af8ea66372cb4703f5f6381de6d4b9b98cff1e90"); + str_check(run_keccak512("04410E31082A47584B406F051398A6ABE74E4DA59BB6F85E6B49E8A1F7F2CA00DFBA5462C2CD2BFDE8B64FB21D70C083F11318B56A52D03B81CAC5EEC29EB31BD0078B6156786DA3D6D8C33098C5C47BB67AC64DB14165AF65B44544D806DDE5F487D5373C7F9792C299E9686B7E5821E7C8E2458315B996B5677D926DAC57B3F22DA873C601016A0D"), + "b0e54a12fdba0738898f1bbf0ba81f81de77648d8d14c20bdd5d90f300d382e069f5dba7eec6b23168b008b9f39c2b93fd742a5902a5e02728f57712d6a61d4e"); + str_check(run_keccak512("3A3A819C48EFDE2AD914FBF00E18AB6BC4F14513AB27D0C178A188B61431E7F5623CB66B23346775D386B50E982C493ADBBFC54B9A3CD383382336A1A0B2150A15358F336D03AE18F666C7573D55C4FD181C29E6CCFDE63EA35F0ADF5885CFC0A3D84A2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AADC66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B6183639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1"), + "81950e7096d31d4f22e3db71cac725bf59e81af54c7ca9e6aeee71c010fc5467466312a01aa5c137cfb140646941556796f612c9351268737c7e9a2b9631d1fa"); +end:; +} + +/* + * Keccak-Stream + */ + +static const char *run_keccakS(const char *hex) +{ + struct DigestContext *ctx; + uint8_t res[512]; + int len; + unsigned reslen; + uint8_t *buf = NULL; + + len = strlen(hex) / 2; + buf = fromhex(hex, len); + + ctx = digest_new(digest_KECCAK_STREAM(), USUAL_ALLOC); + if (!ctx) + return "NOMEM"; + digest_update(ctx, buf, len); + free(buf); + + reslen = 0; + while (reslen < sizeof(res)) { + digest_final(ctx, res + reslen); + reslen += digest_result_len(ctx); + } + + return mkhex(res, reslen); +} + +static void test_keccak_stream(void *ptr) +{ + str_check(run_keccakS(""), + "6753e3380c09e385d0339eb6b050a68f66cfd60a73476e6fd6adeb72f5edd7c6f04a5d017a19cbe291935855b4860f69df04c98aa78b407a9ba9826f7266ef14ba6d3f90c4fe154d27c2858ea6db8c117411a1bc5c499410c391b298f37bf636b0f5c31dbd6487a7d3d8cf2a97b619697e66d894299b8b4d80e0498538e18544c3a2fa33f0bfb1cfef8da7875c4967f332c7fc93c050e81fb404f9a91503d6010ee16f50b4ed0bc563ba8431668b003d7e2e6f226cb7fa93bb2e132c861fdc2141457589a63ecf05481126a7c2de941a2fdec71cb70de81887b9014223865e79c4ffe82dae83c1fc484b9a07a7e52b135f4ae3a0e09247ea4e2625e9349b0ac73f24cb418df6dcb49ca37860298ada18aa23595b5096ef789de3edf3826817fff4f71102a01e1d2599f2958d5c186f5b11f5feedb61bb732dbb42d18b1e77258a8f211bf95c9f47f19603ec419ff879aea41a4811344d016bbc4f9496741c469cca425c5be73543219af40796c0b9ff14aeaa70c5e22e4bb1346a3ddfedd8a559104e4704f1227d42918ae3f7404fbf3c6340a486e776aabcc34190f87da4bd954b83386255a0e34df05ca2e781faf6fe66475852481fce20798a56629abfac408760ce64606008a3b568c88aba1c6df3381e0765567ea84b2ce4b441cf1eefaa32125d5139361a632b3008566a2e8af1055cb06ae462b6bf87b34a9770618e6"); + str_check(run_keccakS("CC"), + "56b97029b479ff5dd15f17d12983e3b835bb0531d9b8d49b103b025ca53f991741298e961d1fad00fc365c7761bfb278ae473980d612c1629e075a3fdbae7f82b0f0af54df187f358852e19ea4347cf5ceea676a1dce3a47447e237fd74204f9a4b7f7c9cc7cc8b865b1d554e2f5f4a8ee17dbdde7267894558a20972c9eb6cf5f62ce9151437718ed4aff08fa76d803806e6ce47d229aae839369e31888b26429e27bc3756021cb51498bcf2527d4bb04838bc1ceed9985a2a66ff8cb8c2d58b7099304e7f9622c583b093024a5fcde2be781474c159df24d77d328c298f5766a8a0dbf7ae790a509ccf59e0cacd0abf21492e0095a87ecdb55990093917aaa96d7f68b7b859b8094aec0ddb6fb352a6cc1f007fa988ed764f5d6f21f9d8ade9ce7aca4de6570da39d9acceb46d2582fa4c4231de0b736fb341041d24cfae6c0761f43a2cf7383f38742579218afcab53d2e6816640de05644d877558e965b1a28406999f31ccc43ac0b02bc5448b66ad3b6f8de04c0e25845c8671b6f0594909a057f17fd06031707c8b4599889c994a35c193dbf84a7a0919cd054f67ceb7965f420d02da3477efc8b55413c241adcf71cb10fe7e3e720b8c1736837b06e4b27461b71c6cac892437530bbfe05cf426272f80f11709b9db964f5dedab9e757c2f7a972b6a4c2443b03ad787ab1e243660bced739157a434800696841acea4"); + str_check(run_keccakS("41FB"), + "cbe96338dd8f04c0694299637aab223b6d60560c6bed7f69923aebb24fc61b84702403d39e7d081f7f7b714e3ba6e6221fe840f57a1e9bd775b90d59c9853695c2b11cd06f1054210d7d8155b908ff4ee14fdf859b6d5aa6bf76903be0af4a2ffd52b2b149da32c8e372f51826d4ca7dcd6516d167a0621aa88986d19a524dd352b9ca08f341d2267671f45e05892e1a5c604bb721bc8952dac20d559dc183656501cc34bc91e2aea930716b20539131ac5f9ae0a630e3691abe6e76935d21f99e3f2e531526360405004bd730388236a1197fe3715315e8ca40b4e5e6a07cab434264515c26451a7c1387d776bc225b851e9f7807c24a23f42fb47eb29697f6cd80cdbfb79a39675092ab582c5a6bb3284cd72a889601dc2745153fac80ff81c6648cb99facfe51862edc8b03c2c3ba5b83eb1d40d3937caf3d8e511485051d3e5431a19c1571b52e796cf032162292ecf2b490cd97c3e2fc2ca339021533cd1aa1c5e8b3f803767ae7585999a2b7d70c7b34324b36399a87c3c73866741cbef9355c1570309544697df9a82da28b6c5ce35556c5bef4e0a24e62f95e543cd3fad6d2ddeea3950e72867d67a8dcd4b338fd8341583fe0e04fff2d6ecdfcd4b41eb8434ee0e31f812b220494202fab9fcba09a9dd26b36637df5607c6d7cbede04868a2d512d11a16c24c4b8d566ce63932b85e7e1a8648f58857629bdc2ee92"); + str_check(run_keccakS("C1ECFDFC"), + "968a76720a2fff1ac9629cac7752c0958b6e19bc79fa31f210244d486645798b55f52581855da53a14139dd78e15f54c66bde1bcc5674f46de6164a86933b2cc99682f7118af25b9034cddac018e6d02f3890fa581c79cad5c6c2380a890ea470876e7bede8e8b78aa6f0cb271f54252dd018c7c9d393a06d60a78be8a5014b89eaa282dfec4e737e43a61cfaade58f9bdde9c6125daf34350b2b4e320f35b62dd0675c0515b943630e3f63880423864dbd70814cc9373c521e8f29bb4138388c92c4b6437a65469902e706ccce3777991a47c0ee9701217fb44cb02e674c7539e473d20352a7a875d6cf3a038e655d3d1a75852fc1859835cc181ef0c58b888a6673bb8275cfb9797f5e146a962d8deb535fc7b166af4fc95209a2dd4c515a0c04ddadfb77ba6b8da76c9ae9cce13538608603ed3550c685bacdc0a059f92dad364f8a72dfaf52faf43011c33b6a6235d9ac6611f346d955e1701f37713bb6f98a05337b1943556d497a4a686645fc359375408702ec45617c949d1209824e4627741cf2760e6ae84e0e1d395da4da5748d042bff19351ff20092df201aeab4d6c603693e6ab01dabaf009a1c8a93e713dacd4a0d93695a2f6ef4e59ab9a140a100766b25b86cbb3632aa73fb16f47b9839e4d0e8736a0b81cdd923f0be79c4c7ab1f7e1be0ed5f079f6e04b979a567e81bc0c1a236e3daa2754f195ff76261"); + str_check(run_keccakS("2B6DB7CED8665EBE9DEB080295218426BDAA7C6DA9ADD2088932CDFFBAA1C14129BCCDD70F369EFB149285858D2B1D155D14DE2FDB680A8B027284055182A0CAE275234CC9C92863C1B4AB66F304CF0621CD54565F5BFF461D3B461BD40DF28198E3732501B4860EADD503D26D6E69338F4E0456E9E9BAF3D827AE685FB1D817"), + "dcac84568f15cac076854ea692de95e473768a99df9ac2328ee423d02eeb8ee8e1d1706213c4415dc7aafa66476d8ebdddd8bf39e1de05ca76c36e7e975629331f3a33c3ca4091c82004e5891b7e276d4642ea61bde021871c9b5c8cfa82144b7a4144b44ebe6093e95c59305fd36a8741c4f2df65cb0b59f803cfdcf2ce4b8b54857a7f8ad8477a22cffc07f4a5ef76996837c9b3f8ff25375e669e68faebed8ac79673860f45fd6e7ee7ed630cb8582785eed432af1f4ca22f4fd4488dc3882de5268ee4c47be4eaa2e77692880d218a69578fb090ed8426c29217b72070be2a4bf0d7bcb480ff262d2dc3bfa9c9d88ff6f5284d240e988e4f9b956aaa36e804bb38ce1f5aa65e73624940c28cf816f4c4f00751bcc6cdc79131e96294d95d6bc98f58a2a687ea7b0769a6dd4f4988b2381631ec1967ef4fcc9efb7a7519783a33787850a8c752f36a4b3abf7e460d5689009a232bef1c33fb3d99069b0157764e4477e2ad68b3a99a05bd2d38288ddd416ee784bdc99e157dfdec61ecb0c49763f187e947c54a4ecbf5eeb76af5feeb222b0844cc1bb9f69cf3b291671bbe98c89ef5d656dfc77375c39cbc2a7ff6413b3ca99834d1845499a09bc111c8582f567d187147c5bbade2194871126dda67daf170079a618a77b8f06193e06f87d441687d1de6e5cda9c791728f837c945f2eb20327802b37fc6d9c2b125f4067"); + str_check(run_keccakS("3A3A819C48EFDE2AD914FBF00E18AB6BC4F14513AB27D0C178A188B61431E7F5623CB66B23346775D386B50E982C493ADBBFC54B9A3CD383382336A1A0B2150A15358F336D03AE18F666C7573D55C4FD181C29E6CCFDE63EA35F0ADF5885CFC0A3D84A2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AADC66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B6183639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1"), + "9435fc671dfcfcdac149277e2caaa80ed3d4a2359300db892b8093dffa9442bb5c08f242f2fc2cb5f8388032299f1df47a57489a4fc0d66d88e483092320a471897fb6ade67897e5138c45f19174a4b1ae0e510fa390825d17568989c3659fc57b9345d7d93ee588cb2629c5770808195257bbf42b069576d94011989dc6ebc43cfc7cd27b6f9853904f3eb3842bbb37d2bd807f05468f5057f78373b6f34462095a1205c1fca0d15fbcf890ee78ab6f94cb778b5d6f3620e6e6d6ee688eecc619e22e25e0bb5e143a53472e4f1d1f91a8e625087b0f608770c4b9909749ab50ddcdac59bb3c975aba4dceb2b3a2c436ed103ed6d9c62cd63a69a0bdd2baabfbfd63eef34507637f5e8a16a4fcb33d66141781e10bc6262833ec6e2953cedd5f652b76fa042ec0d34ba20f5657e28c08b6b61dfa8da78cf997127e17a35d75ab35542fe6bb9ce5bd06119da6b497ac1ae12947b0c214de28ed5dda7815fb6d5def81025934c877cb91e923191581b508bbabdfe4bb2dd5af6af414bfa28830e4380355bdf2483cabd01b046956b85d5a34f46849ba1cc869f5babd1b41ec775fcb4b5fbad79661daf47dbe7bc6380bc5034bfe626526f3305abe270bbbf29280e58b71db269cf7962d9dc1731bd10d5633b1b10e76791c0fcfddf1c8263f17f8b68b1a0589fe5c9403d272fa133442980588bc1f385c3af240d8f195ab1a3400"); +end:; +} /* * HMAC @@ -247,6 +461,11 @@ struct testcase_t crypto_tests[] = { { "sha256", test_sha256 }, { "sha384", test_sha384 }, { "sha512", test_sha512 }, + { "keccak224", test_keccak224 }, + { "keccak256", test_keccak256 }, + { "keccak384", test_keccak384 }, + { "keccak512", test_keccak512 }, + { "keccakStream", test_keccak_stream }, { "hmac", test_hmac }, END_OF_TESTCASES }; diff --git a/usual/crypto/digest.h b/usual/crypto/digest.h index 3fc8c90..ee2ef8d 100644 --- a/usual/crypto/digest.h +++ b/usual/crypto/digest.h @@ -106,5 +106,20 @@ const struct DigestInfo *digest_SHA384(void); /** SHA512 message digest */ const struct DigestInfo *digest_SHA512(void); +/** Keccak-224 message digest */ +const struct DigestInfo *digest_KECCAK224(void); + +/** Keccak-256 message digest */ +const struct DigestInfo *digest_KECCAK256(void); + +/** Keccak-384 message digest */ +const struct DigestInfo *digest_KECCAK384(void); + +/** Keccak-512 message digest */ +const struct DigestInfo *digest_KECCAK512(void); + +/** Keccak in arbitrary output length mode */ +const struct DigestInfo *digest_KECCAK_STREAM(void); + #endif diff --git a/usual/crypto/keccak.c b/usual/crypto/keccak.c new file mode 100644 index 0000000..e405cc3 --- /dev/null +++ b/usual/crypto/keccak.c @@ -0,0 +1,1298 @@ +/* + * Keccak implementation for SHA3 parameters. + * + * Copyright (c) 2012 Marko Kreen + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Based on public-domain Keccak-inplace.c and Keccak-inplace32BI.c + * implementations from Keccak reference code: + * + * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, + * Michaël Peeters and Gilles Van Assche. For more information, feedback or + * questions, please refer to our website: http://keccak.noekeon.org/ + * + * Implementation by Ronny Van Keer and the designers, + * hereby denoted as "the implementer". + * + * To the extent possible under law, the implementer has waived all copyright + * and related or neighboring rights to the source code in this file. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * 32-bit word interlacing algorithm: + * + * Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 + */ + +#include +#include +#include +#include +#include +#include + +//#define KECCAK_64BIT + +/* + * Decide whether to use 64- or 32-bit implementation. + */ +#if !defined(KECCAK_64BIT) && !defined(KECCAK_32BIT) +/* If neither is defined, try to autodetect */ +#if (LONG_MAX > 0xFFFFFFFF) || (UINTPTR_MAX > 0xFFFFFFFF) +/* use 64-bit implementation if 'long' or 'uintptr_t' is 64-bit */ +#define KECCAK_64BIT +#else +/* otherwise, use 32-bit implementation */ +#define KECCAK_32BIT +#endif +#endif + +/* For SHA3 variant of Keccak */ +#define KECCAK_ROUNDS 24 + + +#ifdef KECCAK_64BIT + +/* + * 64-bit implementation - one lane is one 64-bit word. + */ + +/* round constants */ +static const uint64_t RoundConstants64[KECCAK_ROUNDS] = { + UINT64_C(0x0000000000000001), UINT64_C(0x0000000000008082), + UINT64_C(0x800000000000808A), UINT64_C(0x8000000080008000), + UINT64_C(0x000000000000808B), UINT64_C(0x0000000080000001), + UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008009), + UINT64_C(0x000000000000008A), UINT64_C(0x0000000000000088), + UINT64_C(0x0000000080008009), UINT64_C(0x000000008000000A), + UINT64_C(0x000000008000808B), UINT64_C(0x800000000000008B), + UINT64_C(0x8000000000008089), UINT64_C(0x8000000000008003), + UINT64_C(0x8000000000008002), UINT64_C(0x8000000000000080), + UINT64_C(0x000000000000800A), UINT64_C(0x800000008000000A), + UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008080), + UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008008), +}; + +static void keccak_f(struct KeccakContext *ctx) +{ + uint64_t *state = ctx->u.state64; + uint64_t Ba, Be, Bi, Bo, Bu; + uint64_t Ca, Ce, Ci, Co, Cu; + uint64_t Da, De, Di, Do, Du; + int i; + +#define Aba state[ 0] +#define Abe state[ 1] +#define Abi state[ 2] +#define Abo state[ 3] +#define Abu state[ 4] +#define Aga state[ 5] +#define Age state[ 6] +#define Agi state[ 7] +#define Ago state[ 8] +#define Agu state[ 9] +#define Aka state[10] +#define Ake state[11] +#define Aki state[12] +#define Ako state[13] +#define Aku state[14] +#define Ama state[15] +#define Ame state[16] +#define Ami state[17] +#define Amo state[18] +#define Amu state[19] +#define Asa state[20] +#define Ase state[21] +#define Asi state[22] +#define Aso state[23] +#define Asu state[24] + + for (i = 0; i < KECCAK_ROUNDS; i += 4) { + /* Code for 4 rounds */ + Ca = Aba^Aga^Aka^Ama^Asa; + Ce = Abe^Age^Ake^Ame^Ase; + Ci = Abi^Agi^Aki^Ami^Asi; + Co = Abo^Ago^Ako^Amo^Aso; + Cu = Abu^Agu^Aku^Amu^Asu; + Da = Cu^rol64(Ce, 1); + De = Ca^rol64(Ci, 1); + Di = Ce^rol64(Co, 1); + Do = Ci^rol64(Cu, 1); + Du = Co^rol64(Ca, 1); + + Ba = (Aba^Da); + Be = rol64((Age^De), 44); + Bi = rol64((Aki^Di), 43); + Bo = rol64((Amo^Do), 21); + Bu = rol64((Asu^Du), 14); + Aba = Ba ^((~Be)& Bi ); + Aba ^= RoundConstants64[i+0]; + Age = Be ^((~Bi)& Bo ); + Aki = Bi ^((~Bo)& Bu ); + Amo = Bo ^((~Bu)& Ba ); + Asu = Bu ^((~Ba)& Be ); + + Bi = rol64((Aka^Da), 3); + Bo = rol64((Ame^De), 45); + Bu = rol64((Asi^Di), 61); + Ba = rol64((Abo^Do), 28); + Be = rol64((Agu^Du), 20); + Aka = Ba ^((~Be)& Bi ); + Ame = Be ^((~Bi)& Bo ); + Asi = Bi ^((~Bo)& Bu ); + Abo = Bo ^((~Bu)& Ba ); + Agu = Bu ^((~Ba)& Be ); + + Bu = rol64((Asa^Da), 18); + Ba = rol64((Abe^De), 1); + Be = rol64((Agi^Di), 6); + Bi = rol64((Ako^Do), 25); + Bo = rol64((Amu^Du), 8); + Asa = Ba ^((~Be)& Bi ); + Abe = Be ^((~Bi)& Bo ); + Agi = Bi ^((~Bo)& Bu ); + Ako = Bo ^((~Bu)& Ba ); + Amu = Bu ^((~Ba)& Be ); + + Be = rol64((Aga^Da), 36); + Bi = rol64((Ake^De), 10); + Bo = rol64((Ami^Di), 15); + Bu = rol64((Aso^Do), 56); + Ba = rol64((Abu^Du), 27); + Aga = Ba ^((~Be)& Bi ); + Ake = Be ^((~Bi)& Bo ); + Ami = Bi ^((~Bo)& Bu ); + Aso = Bo ^((~Bu)& Ba ); + Abu = Bu ^((~Ba)& Be ); + + Bo = rol64((Ama^Da), 41); + Bu = rol64((Ase^De), 2); + Ba = rol64((Abi^Di), 62); + Be = rol64((Ago^Do), 55); + Bi = rol64((Aku^Du), 39); + Ama = Ba ^((~Be)& Bi ); + Ase = Be ^((~Bi)& Bo ); + Abi = Bi ^((~Bo)& Bu ); + Ago = Bo ^((~Bu)& Ba ); + Aku = Bu ^((~Ba)& Be ); + + Ca = Aba^Aka^Asa^Aga^Ama; + Ce = Age^Ame^Abe^Ake^Ase; + Ci = Aki^Asi^Agi^Ami^Abi; + Co = Amo^Abo^Ako^Aso^Ago; + Cu = Asu^Agu^Amu^Abu^Aku; + Da = Cu^rol64(Ce, 1); + De = Ca^rol64(Ci, 1); + Di = Ce^rol64(Co, 1); + Do = Ci^rol64(Cu, 1); + Du = Co^rol64(Ca, 1); + + Ba = (Aba^Da); + Be = rol64((Ame^De), 44); + Bi = rol64((Agi^Di), 43); + Bo = rol64((Aso^Do), 21); + Bu = rol64((Aku^Du), 14); + Aba = Ba ^((~Be)& Bi ); + Aba ^= RoundConstants64[i+1]; + Ame = Be ^((~Bi)& Bo ); + Agi = Bi ^((~Bo)& Bu ); + Aso = Bo ^((~Bu)& Ba ); + Aku = Bu ^((~Ba)& Be ); + + Bi = rol64((Asa^Da), 3); + Bo = rol64((Ake^De), 45); + Bu = rol64((Abi^Di), 61); + Ba = rol64((Amo^Do), 28); + Be = rol64((Agu^Du), 20); + Asa = Ba ^((~Be)& Bi ); + Ake = Be ^((~Bi)& Bo ); + Abi = Bi ^((~Bo)& Bu ); + Amo = Bo ^((~Bu)& Ba ); + Agu = Bu ^((~Ba)& Be ); + + Bu = rol64((Ama^Da), 18); + Ba = rol64((Age^De), 1); + Be = rol64((Asi^Di), 6); + Bi = rol64((Ako^Do), 25); + Bo = rol64((Abu^Du), 8); + Ama = Ba ^((~Be)& Bi ); + Age = Be ^((~Bi)& Bo ); + Asi = Bi ^((~Bo)& Bu ); + Ako = Bo ^((~Bu)& Ba ); + Abu = Bu ^((~Ba)& Be ); + + Be = rol64((Aka^Da), 36); + Bi = rol64((Abe^De), 10); + Bo = rol64((Ami^Di), 15); + Bu = rol64((Ago^Do), 56); + Ba = rol64((Asu^Du), 27); + Aka = Ba ^((~Be)& Bi ); + Abe = Be ^((~Bi)& Bo ); + Ami = Bi ^((~Bo)& Bu ); + Ago = Bo ^((~Bu)& Ba ); + Asu = Bu ^((~Ba)& Be ); + + Bo = rol64((Aga^Da), 41); + Bu = rol64((Ase^De), 2); + Ba = rol64((Aki^Di), 62); + Be = rol64((Abo^Do), 55); + Bi = rol64((Amu^Du), 39); + Aga = Ba ^((~Be)& Bi ); + Ase = Be ^((~Bi)& Bo ); + Aki = Bi ^((~Bo)& Bu ); + Abo = Bo ^((~Bu)& Ba ); + Amu = Bu ^((~Ba)& Be ); + + Ca = Aba^Asa^Ama^Aka^Aga; + Ce = Ame^Ake^Age^Abe^Ase; + Ci = Agi^Abi^Asi^Ami^Aki; + Co = Aso^Amo^Ako^Ago^Abo; + Cu = Aku^Agu^Abu^Asu^Amu; + Da = Cu^rol64(Ce, 1); + De = Ca^rol64(Ci, 1); + Di = Ce^rol64(Co, 1); + Do = Ci^rol64(Cu, 1); + Du = Co^rol64(Ca, 1); + + Ba = (Aba^Da); + Be = rol64((Ake^De), 44); + Bi = rol64((Asi^Di), 43); + Bo = rol64((Ago^Do), 21); + Bu = rol64((Amu^Du), 14); + Aba = Ba ^((~Be)& Bi ); + Aba ^= RoundConstants64[i+2]; + Ake = Be ^((~Bi)& Bo ); + Asi = Bi ^((~Bo)& Bu ); + Ago = Bo ^((~Bu)& Ba ); + Amu = Bu ^((~Ba)& Be ); + + Bi = rol64((Ama^Da), 3); + Bo = rol64((Abe^De), 45); + Bu = rol64((Aki^Di), 61); + Ba = rol64((Aso^Do), 28); + Be = rol64((Agu^Du), 20); + Ama = Ba ^((~Be)& Bi ); + Abe = Be ^((~Bi)& Bo ); + Aki = Bi ^((~Bo)& Bu ); + Aso = Bo ^((~Bu)& Ba ); + Agu = Bu ^((~Ba)& Be ); + + Bu = rol64((Aga^Da), 18); + Ba = rol64((Ame^De), 1); + Be = rol64((Abi^Di), 6); + Bi = rol64((Ako^Do), 25); + Bo = rol64((Asu^Du), 8); + Aga = Ba ^((~Be)& Bi ); + Ame = Be ^((~Bi)& Bo ); + Abi = Bi ^((~Bo)& Bu ); + Ako = Bo ^((~Bu)& Ba ); + Asu = Bu ^((~Ba)& Be ); + + Be = rol64((Asa^Da), 36); + Bi = rol64((Age^De), 10); + Bo = rol64((Ami^Di), 15); + Bu = rol64((Abo^Do), 56); + Ba = rol64((Aku^Du), 27); + Asa = Ba ^((~Be)& Bi ); + Age = Be ^((~Bi)& Bo ); + Ami = Bi ^((~Bo)& Bu ); + Abo = Bo ^((~Bu)& Ba ); + Aku = Bu ^((~Ba)& Be ); + + Bo = rol64((Aka^Da), 41); + Bu = rol64((Ase^De), 2); + Ba = rol64((Agi^Di), 62); + Be = rol64((Amo^Do), 55); + Bi = rol64((Abu^Du), 39); + Aka = Ba ^((~Be)& Bi ); + Ase = Be ^((~Bi)& Bo ); + Agi = Bi ^((~Bo)& Bu ); + Amo = Bo ^((~Bu)& Ba ); + Abu = Bu ^((~Ba)& Be ); + + Ca = Aba^Ama^Aga^Asa^Aka; + Ce = Ake^Abe^Ame^Age^Ase; + Ci = Asi^Aki^Abi^Ami^Agi; + Co = Ago^Aso^Ako^Abo^Amo; + Cu = Amu^Agu^Asu^Aku^Abu; + Da = Cu^rol64(Ce, 1); + De = Ca^rol64(Ci, 1); + Di = Ce^rol64(Co, 1); + Do = Ci^rol64(Cu, 1); + Du = Co^rol64(Ca, 1); + + Ba = (Aba^Da); + Be = rol64((Abe^De), 44); + Bi = rol64((Abi^Di), 43); + Bo = rol64((Abo^Do), 21); + Bu = rol64((Abu^Du), 14); + Aba = Ba ^((~Be)& Bi ); + Aba ^= RoundConstants64[i+3]; + Abe = Be ^((~Bi)& Bo ); + Abi = Bi ^((~Bo)& Bu ); + Abo = Bo ^((~Bu)& Ba ); + Abu = Bu ^((~Ba)& Be ); + + Bi = rol64((Aga^Da), 3); + Bo = rol64((Age^De), 45); + Bu = rol64((Agi^Di), 61); + Ba = rol64((Ago^Do), 28); + Be = rol64((Agu^Du), 20); + Aga = Ba ^((~Be)& Bi ); + Age = Be ^((~Bi)& Bo ); + Agi = Bi ^((~Bo)& Bu ); + Ago = Bo ^((~Bu)& Ba ); + Agu = Bu ^((~Ba)& Be ); + + Bu = rol64((Aka^Da), 18); + Ba = rol64((Ake^De), 1); + Be = rol64((Aki^Di), 6); + Bi = rol64((Ako^Do), 25); + Bo = rol64((Aku^Du), 8); + Aka = Ba ^((~Be)& Bi ); + Ake = Be ^((~Bi)& Bo ); + Aki = Bi ^((~Bo)& Bu ); + Ako = Bo ^((~Bu)& Ba ); + Aku = Bu ^((~Ba)& Be ); + + Be = rol64((Ama^Da), 36); + Bi = rol64((Ame^De), 10); + Bo = rol64((Ami^Di), 15); + Bu = rol64((Amo^Do), 56); + Ba = rol64((Amu^Du), 27); + Ama = Ba ^((~Be)& Bi ); + Ame = Be ^((~Bi)& Bo ); + Ami = Bi ^((~Bo)& Bu ); + Amo = Bo ^((~Bu)& Ba ); + Amu = Bu ^((~Ba)& Be ); + + Bo = rol64((Asa^Da), 41); + Bu = rol64((Ase^De), 2); + Ba = rol64((Asi^Di), 62); + Be = rol64((Aso^Do), 55); + Bi = rol64((Asu^Du), 39); + Asa = Ba ^((~Be)& Bi ); + Ase = Be ^((~Bi)& Bo ); + Asi = Bi ^((~Bo)& Bu ); + Aso = Bo ^((~Bu)& Ba ); + Asu = Bu ^((~Ba)& Be ); + } +} + +static inline void xor_lane(struct KeccakContext *ctx, int lane, uint64_t val) +{ + ctx->u.state64[lane] ^= val; +} + +static void extract(uint8_t *dst, const struct KeccakContext *ctx, int laneCount) +{ + const uint64_t *src = ctx->u.state64; + + while (laneCount--) { + le64enc(dst, *src++); + dst += 8; + } +} + + +#else /* KECCAK_32BIT */ + + +/* + * 32-bit implementation - one 64-bit lane is mapped + * to two interleaved 32-bit words. + */ + +static const uint32_t RoundConstants32[2*KECCAK_ROUNDS] = { + 0x00000001, 0x00000000, 0x00000000, 0x00000089, + 0x00000000, 0x8000008b, 0x00000000, 0x80008080, + 0x00000001, 0x0000008b, 0x00000001, 0x00008000, + 0x00000001, 0x80008088, 0x00000001, 0x80000082, + 0x00000000, 0x0000000b, 0x00000000, 0x0000000a, + 0x00000001, 0x00008082, 0x00000000, 0x00008003, + 0x00000001, 0x0000808b, 0x00000001, 0x8000000b, + 0x00000001, 0x8000008a, 0x00000001, 0x80000081, + 0x00000000, 0x80000081, 0x00000000, 0x80000008, + 0x00000000, 0x00000083, 0x00000000, 0x80008003, + 0x00000001, 0x80008088, 0x00000000, 0x80000088, + 0x00000001, 0x00008000, 0x00000000, 0x80008082, +}; + +#define KeccakAtoD_round0() \ + Cx = Abu0^Agu0^Aku0^Amu0^Asu0; \ + Du1 = Abe1^Age1^Ake1^Ame1^Ase1; \ + Da0 = Cx^rol32(Du1, 1); \ + Cz = Abu1^Agu1^Aku1^Amu1^Asu1; \ + Du0 = Abe0^Age0^Ake0^Ame0^Ase0; \ + Da1 = Cz^Du0; \ + \ + Cw = Abi0^Agi0^Aki0^Ami0^Asi0; \ + Do0 = Cw^rol32(Cz, 1); \ + Cy = Abi1^Agi1^Aki1^Ami1^Asi1; \ + Do1 = Cy^Cx; \ + \ + Cx = Aba0^Aga0^Aka0^Ama0^Asa0; \ + De0 = Cx^rol32(Cy, 1); \ + Cz = Aba1^Aga1^Aka1^Ama1^Asa1; \ + De1 = Cz^Cw; \ + \ + Cy = Abo1^Ago1^Ako1^Amo1^Aso1; \ + Di0 = Du0^rol32(Cy, 1); \ + Cw = Abo0^Ago0^Ako0^Amo0^Aso0; \ + Di1 = Du1^Cw; \ + \ + Du0 = Cw^rol32(Cz, 1); \ + Du1 = Cy^Cx; + +#define KeccakAtoD_round1() \ + Cx = Asu0^Agu0^Amu0^Abu1^Aku1; \ + Du1 = Age1^Ame0^Abe0^Ake1^Ase1; \ + Da0 = Cx^rol32(Du1, 1); \ + Cz = Asu1^Agu1^Amu1^Abu0^Aku0; \ + Du0 = Age0^Ame1^Abe1^Ake0^Ase0; \ + Da1 = Cz^Du0; \ + \ + Cw = Aki1^Asi1^Agi0^Ami1^Abi0; \ + Do0 = Cw^rol32(Cz, 1); \ + Cy = Aki0^Asi0^Agi1^Ami0^Abi1; \ + Do1 = Cy^Cx; \ + \ + Cx = Aba0^Aka1^Asa0^Aga0^Ama1; \ + De0 = Cx^rol32(Cy, 1); \ + Cz = Aba1^Aka0^Asa1^Aga1^Ama0; \ + De1 = Cz^Cw; \ + \ + Cy = Amo0^Abo1^Ako0^Aso1^Ago0; \ + Di0 = Du0^rol32(Cy, 1); \ + Cw = Amo1^Abo0^Ako1^Aso0^Ago1; \ + Di1 = Du1^Cw; \ + \ + Du0 = Cw^rol32(Cz, 1); \ + Du1 = Cy^Cx; + +#define KeccakAtoD_round2() \ + Cx = Aku1^Agu0^Abu1^Asu1^Amu1; \ + Du1 = Ame0^Ake0^Age0^Abe0^Ase1; \ + Da0 = Cx^rol32(Du1, 1); \ + Cz = Aku0^Agu1^Abu0^Asu0^Amu0; \ + Du0 = Ame1^Ake1^Age1^Abe1^Ase0; \ + Da1 = Cz^Du0; \ + \ + Cw = Agi1^Abi1^Asi1^Ami0^Aki1; \ + Do0 = Cw^rol32(Cz, 1); \ + Cy = Agi0^Abi0^Asi0^Ami1^Aki0; \ + Do1 = Cy^Cx; \ + \ + Cx = Aba0^Asa1^Ama1^Aka1^Aga1; \ + De0 = Cx^rol32(Cy, 1); \ + Cz = Aba1^Asa0^Ama0^Aka0^Aga0; \ + De1 = Cz^Cw; \ + \ + Cy = Aso0^Amo0^Ako1^Ago0^Abo0; \ + Di0 = Du0^rol32(Cy, 1); \ + Cw = Aso1^Amo1^Ako0^Ago1^Abo1; \ + Di1 = Du1^Cw; \ + \ + Du0 = Cw^rol32(Cz, 1); \ + Du1 = Cy^Cx; + +#define KeccakAtoD_round3() \ + Cx = Amu1^Agu0^Asu1^Aku0^Abu0; \ + Du1 = Ake0^Abe1^Ame1^Age0^Ase1; \ + Da0 = Cx^rol32(Du1, 1); \ + Cz = Amu0^Agu1^Asu0^Aku1^Abu1; \ + Du0 = Ake1^Abe0^Ame0^Age1^Ase0; \ + Da1 = Cz^Du0; \ + \ + Cw = Asi0^Aki0^Abi1^Ami1^Agi1; \ + Do0 = Cw^rol32(Cz, 1); \ + Cy = Asi1^Aki1^Abi0^Ami0^Agi0; \ + Do1 = Cy^Cx; \ + \ + Cx = Aba0^Ama0^Aga1^Asa1^Aka0; \ + De0 = Cx^rol32(Cy, 1); \ + Cz = Aba1^Ama1^Aga0^Asa0^Aka1; \ + De1 = Cz^Cw; \ + \ + Cy = Ago1^Aso0^Ako0^Abo0^Amo1; \ + Di0 = Du0^rol32(Cy, 1); \ + Cw = Ago0^Aso1^Ako1^Abo1^Amo0; \ + Di1 = Du1^Cw; \ + \ + Du0 = Cw^rol32(Cz, 1); \ + Du1 = Cy^Cx; + +static void keccak_f(struct KeccakContext *ctx) +{ + uint32_t *state = ctx->u.state32; + uint32_t Da0, De0, Di0, Do0, Du0; + uint32_t Da1, De1, Di1, Do1, Du1; + uint32_t Ca0, Ce0, Ci0, Co0, Cu0; + uint32_t Cx, Cy, Cz, Cw; + int i; + +#define Ba Ca0 +#define Be Ce0 +#define Bi Ci0 +#define Bo Co0 +#define Bu Cu0 + +#define Aba0 state[ 0] +#define Aba1 state[ 1] +#define Abe0 state[ 2] +#define Abe1 state[ 3] +#define Abi0 state[ 4] +#define Abi1 state[ 5] +#define Abo0 state[ 6] +#define Abo1 state[ 7] +#define Abu0 state[ 8] +#define Abu1 state[ 9] +#define Aga0 state[10] +#define Aga1 state[11] +#define Age0 state[12] +#define Age1 state[13] +#define Agi0 state[14] +#define Agi1 state[15] +#define Ago0 state[16] +#define Ago1 state[17] +#define Agu0 state[18] +#define Agu1 state[19] +#define Aka0 state[20] +#define Aka1 state[21] +#define Ake0 state[22] +#define Ake1 state[23] +#define Aki0 state[24] +#define Aki1 state[25] +#define Ako0 state[26] +#define Ako1 state[27] +#define Aku0 state[28] +#define Aku1 state[29] +#define Ama0 state[30] +#define Ama1 state[31] +#define Ame0 state[32] +#define Ame1 state[33] +#define Ami0 state[34] +#define Ami1 state[35] +#define Amo0 state[36] +#define Amo1 state[37] +#define Amu0 state[38] +#define Amu1 state[39] +#define Asa0 state[40] +#define Asa1 state[41] +#define Ase0 state[42] +#define Ase1 state[43] +#define Asi0 state[44] +#define Asi1 state[45] +#define Aso0 state[46] +#define Aso1 state[47] +#define Asu0 state[48] +#define Asu1 state[49] + + for (i = 0; i < KECCAK_ROUNDS*2; i += 8) { + /* Code for 4 rounds */ + KeccakAtoD_round0(); + + Ba = (Aba0^Da0); + Be = rol32((Age0^De0), 22); + Bi = rol32((Aki1^Di1), 22); + Bo = rol32((Amo1^Do1), 11); + Bu = rol32((Asu0^Du0), 7); + Aba0 = Ba ^((~Be)& Bi ); + Aba0 ^= RoundConstants32[i+0]; + Age0 = Be ^((~Bi)& Bo ); + Aki1 = Bi ^((~Bo)& Bu ); + Amo1 = Bo ^((~Bu)& Ba ); + Asu0 = Bu ^((~Ba)& Be ); + + Ba = (Aba1^Da1); + Be = rol32((Age1^De1), 22); + Bi = rol32((Aki0^Di0), 21); + Bo = rol32((Amo0^Do0), 10); + Bu = rol32((Asu1^Du1), 7); + Aba1 = Ba ^((~Be)& Bi ); + Aba1 ^= RoundConstants32[i+1]; + Age1 = Be ^((~Bi)& Bo ); + Aki0 = Bi ^((~Bo)& Bu ); + Amo0 = Bo ^((~Bu)& Ba ); + Asu1 = Bu ^((~Ba)& Be ); + + Bi = rol32((Aka1^Da1), 2); + Bo = rol32((Ame1^De1), 23); + Bu = rol32((Asi1^Di1), 31); + Ba = rol32((Abo0^Do0), 14); + Be = rol32((Agu0^Du0), 10); + Aka1 = Ba ^((~Be)& Bi ); + Ame1 = Be ^((~Bi)& Bo ); + Asi1 = Bi ^((~Bo)& Bu ); + Abo0 = Bo ^((~Bu)& Ba ); + Agu0 = Bu ^((~Ba)& Be ); + + Bi = rol32((Aka0^Da0), 1); + Bo = rol32((Ame0^De0), 22); + Bu = rol32((Asi0^Di0), 30); + Ba = rol32((Abo1^Do1), 14); + Be = rol32((Agu1^Du1), 10); + Aka0 = Ba ^((~Be)& Bi ); + Ame0 = Be ^((~Bi)& Bo ); + Asi0 = Bi ^((~Bo)& Bu ); + Abo1 = Bo ^((~Bu)& Ba ); + Agu1 = Bu ^((~Ba)& Be ); + + Bu = rol32((Asa0^Da0), 9); + Ba = rol32((Abe1^De1), 1); + Be = rol32((Agi0^Di0), 3); + Bi = rol32((Ako1^Do1), 13); + Bo = rol32((Amu0^Du0), 4); + Asa0 = Ba ^((~Be)& Bi ); + Abe1 = Be ^((~Bi)& Bo ); + Agi0 = Bi ^((~Bo)& Bu ); + Ako1 = Bo ^((~Bu)& Ba ); + Amu0 = Bu ^((~Ba)& Be ); + + Bu = rol32((Asa1^Da1), 9); + Ba = (Abe0^De0); + Be = rol32((Agi1^Di1), 3); + Bi = rol32((Ako0^Do0), 12); + Bo = rol32((Amu1^Du1), 4); + Asa1 = Ba ^((~Be)& Bi ); + Abe0 = Be ^((~Bi)& Bo ); + Agi1 = Bi ^((~Bo)& Bu ); + Ako0 = Bo ^((~Bu)& Ba ); + Amu1 = Bu ^((~Ba)& Be ); + + Be = rol32((Aga0^Da0), 18); + Bi = rol32((Ake0^De0), 5); + Bo = rol32((Ami1^Di1), 8); + Bu = rol32((Aso0^Do0), 28); + Ba = rol32((Abu1^Du1), 14); + Aga0 = Ba ^((~Be)& Bi ); + Ake0 = Be ^((~Bi)& Bo ); + Ami1 = Bi ^((~Bo)& Bu ); + Aso0 = Bo ^((~Bu)& Ba ); + Abu1 = Bu ^((~Ba)& Be ); + + Be = rol32((Aga1^Da1), 18); + Bi = rol32((Ake1^De1), 5); + Bo = rol32((Ami0^Di0), 7); + Bu = rol32((Aso1^Do1), 28); + Ba = rol32((Abu0^Du0), 13); + Aga1 = Ba ^((~Be)& Bi ); + Ake1 = Be ^((~Bi)& Bo ); + Ami0 = Bi ^((~Bo)& Bu ); + Aso1 = Bo ^((~Bu)& Ba ); + Abu0 = Bu ^((~Ba)& Be ); + + Bo = rol32((Ama1^Da1), 21); + Bu = rol32((Ase0^De0), 1); + Ba = rol32((Abi0^Di0), 31); + Be = rol32((Ago1^Do1), 28); + Bi = rol32((Aku1^Du1), 20); + Ama1 = Ba ^((~Be)& Bi ); + Ase0 = Be ^((~Bi)& Bo ); + Abi0 = Bi ^((~Bo)& Bu ); + Ago1 = Bo ^((~Bu)& Ba ); + Aku1 = Bu ^((~Ba)& Be ); + + Bo = rol32((Ama0^Da0), 20); + Bu = rol32((Ase1^De1), 1); + Ba = rol32((Abi1^Di1), 31); + Be = rol32((Ago0^Do0), 27); + Bi = rol32((Aku0^Du0), 19); + Ama0 = Ba ^((~Be)& Bi ); + Ase1 = Be ^((~Bi)& Bo ); + Abi1 = Bi ^((~Bo)& Bu ); + Ago0 = Bo ^((~Bu)& Ba ); + Aku0 = Bu ^((~Ba)& Be ); + + KeccakAtoD_round1(); + + Ba = (Aba0^Da0); + Be = rol32((Ame1^De0), 22); + Bi = rol32((Agi1^Di1), 22); + Bo = rol32((Aso1^Do1), 11); + Bu = rol32((Aku1^Du0), 7); + Aba0 = Ba ^((~Be)& Bi ); + Aba0 ^= RoundConstants32[i+2]; + Ame1 = Be ^((~Bi)& Bo ); + Agi1 = Bi ^((~Bo)& Bu ); + Aso1 = Bo ^((~Bu)& Ba ); + Aku1 = Bu ^((~Ba)& Be ); + + Ba = (Aba1^Da1); + Be = rol32((Ame0^De1), 22); + Bi = rol32((Agi0^Di0), 21); + Bo = rol32((Aso0^Do0), 10); + Bu = rol32((Aku0^Du1), 7); + Aba1 = Ba ^((~Be)& Bi ); + Aba1 ^= RoundConstants32[i+3]; + Ame0 = Be ^((~Bi)& Bo ); + Agi0 = Bi ^((~Bo)& Bu ); + Aso0 = Bo ^((~Bu)& Ba ); + Aku0 = Bu ^((~Ba)& Be ); + + Bi = rol32((Asa1^Da1), 2); + Bo = rol32((Ake1^De1), 23); + Bu = rol32((Abi1^Di1), 31); + Ba = rol32((Amo1^Do0), 14); + Be = rol32((Agu0^Du0), 10); + Asa1 = Ba ^((~Be)& Bi ); + Ake1 = Be ^((~Bi)& Bo ); + Abi1 = Bi ^((~Bo)& Bu ); + Amo1 = Bo ^((~Bu)& Ba ); + Agu0 = Bu ^((~Ba)& Be ); + + Bi = rol32((Asa0^Da0), 1); + Bo = rol32((Ake0^De0), 22); + Bu = rol32((Abi0^Di0), 30); + Ba = rol32((Amo0^Do1), 14); + Be = rol32((Agu1^Du1), 10); + Asa0 = Ba ^((~Be)& Bi ); + Ake0 = Be ^((~Bi)& Bo ); + Abi0 = Bi ^((~Bo)& Bu ); + Amo0 = Bo ^((~Bu)& Ba ); + Agu1 = Bu ^((~Ba)& Be ); + + Bu = rol32((Ama1^Da0), 9); + Ba = rol32((Age1^De1), 1); + Be = rol32((Asi1^Di0), 3); + Bi = rol32((Ako0^Do1), 13); + Bo = rol32((Abu1^Du0), 4); + Ama1 = Ba ^((~Be)& Bi ); + Age1 = Be ^((~Bi)& Bo ); + Asi1 = Bi ^((~Bo)& Bu ); + Ako0 = Bo ^((~Bu)& Ba ); + Abu1 = Bu ^((~Ba)& Be ); + + Bu = rol32((Ama0^Da1), 9); + Ba = (Age0^De0); + Be = rol32((Asi0^Di1), 3); + Bi = rol32((Ako1^Do0), 12); + Bo = rol32((Abu0^Du1), 4); + Ama0 = Ba ^((~Be)& Bi ); + Age0 = Be ^((~Bi)& Bo ); + Asi0 = Bi ^((~Bo)& Bu ); + Ako1 = Bo ^((~Bu)& Ba ); + Abu0 = Bu ^((~Ba)& Be ); + + Be = rol32((Aka1^Da0), 18); + Bi = rol32((Abe1^De0), 5); + Bo = rol32((Ami0^Di1), 8); + Bu = rol32((Ago1^Do0), 28); + Ba = rol32((Asu1^Du1), 14); + Aka1 = Ba ^((~Be)& Bi ); + Abe1 = Be ^((~Bi)& Bo ); + Ami0 = Bi ^((~Bo)& Bu ); + Ago1 = Bo ^((~Bu)& Ba ); + Asu1 = Bu ^((~Ba)& Be ); + + Be = rol32((Aka0^Da1), 18); + Bi = rol32((Abe0^De1), 5); + Bo = rol32((Ami1^Di0), 7); + Bu = rol32((Ago0^Do1), 28); + Ba = rol32((Asu0^Du0), 13); + Aka0 = Ba ^((~Be)& Bi ); + Abe0 = Be ^((~Bi)& Bo ); + Ami1 = Bi ^((~Bo)& Bu ); + Ago0 = Bo ^((~Bu)& Ba ); + Asu0 = Bu ^((~Ba)& Be ); + + Bo = rol32((Aga1^Da1), 21); + Bu = rol32((Ase0^De0), 1); + Ba = rol32((Aki1^Di0), 31); + Be = rol32((Abo1^Do1), 28); + Bi = rol32((Amu1^Du1), 20); + Aga1 = Ba ^((~Be)& Bi ); + Ase0 = Be ^((~Bi)& Bo ); + Aki1 = Bi ^((~Bo)& Bu ); + Abo1 = Bo ^((~Bu)& Ba ); + Amu1 = Bu ^((~Ba)& Be ); + + Bo = rol32((Aga0^Da0), 20); + Bu = rol32((Ase1^De1), 1); + Ba = rol32((Aki0^Di1), 31); + Be = rol32((Abo0^Do0), 27); + Bi = rol32((Amu0^Du0), 19); + Aga0 = Ba ^((~Be)& Bi ); + Ase1 = Be ^((~Bi)& Bo ); + Aki0 = Bi ^((~Bo)& Bu ); + Abo0 = Bo ^((~Bu)& Ba ); + Amu0 = Bu ^((~Ba)& Be ); + + KeccakAtoD_round2(); + + Ba = (Aba0^Da0); + Be = rol32((Ake1^De0), 22); + Bi = rol32((Asi0^Di1), 22); + Bo = rol32((Ago0^Do1), 11); + Bu = rol32((Amu1^Du0), 7); + Aba0 = Ba ^((~Be)& Bi ); + Aba0 ^= RoundConstants32[i+4]; + Ake1 = Be ^((~Bi)& Bo ); + Asi0 = Bi ^((~Bo)& Bu ); + Ago0 = Bo ^((~Bu)& Ba ); + Amu1 = Bu ^((~Ba)& Be ); + + Ba = (Aba1^Da1); + Be = rol32((Ake0^De1), 22); + Bi = rol32((Asi1^Di0), 21); + Bo = rol32((Ago1^Do0), 10); + Bu = rol32((Amu0^Du1), 7); + Aba1 = Ba ^((~Be)& Bi ); + Aba1 ^= RoundConstants32[i+5]; + Ake0 = Be ^((~Bi)& Bo ); + Asi1 = Bi ^((~Bo)& Bu ); + Ago1 = Bo ^((~Bu)& Ba ); + Amu0 = Bu ^((~Ba)& Be ); + + Bi = rol32((Ama0^Da1), 2); + Bo = rol32((Abe0^De1), 23); + Bu = rol32((Aki0^Di1), 31); + Ba = rol32((Aso1^Do0), 14); + Be = rol32((Agu0^Du0), 10); + Ama0 = Ba ^((~Be)& Bi ); + Abe0 = Be ^((~Bi)& Bo ); + Aki0 = Bi ^((~Bo)& Bu ); + Aso1 = Bo ^((~Bu)& Ba ); + Agu0 = Bu ^((~Ba)& Be ); + + Bi = rol32((Ama1^Da0), 1); + Bo = rol32((Abe1^De0), 22); + Bu = rol32((Aki1^Di0), 30); + Ba = rol32((Aso0^Do1), 14); + Be = rol32((Agu1^Du1), 10); + Ama1 = Ba ^((~Be)& Bi ); + Abe1 = Be ^((~Bi)& Bo ); + Aki1 = Bi ^((~Bo)& Bu ); + Aso0 = Bo ^((~Bu)& Ba ); + Agu1 = Bu ^((~Ba)& Be ); + + Bu = rol32((Aga1^Da0), 9); + Ba = rol32((Ame0^De1), 1); + Be = rol32((Abi1^Di0), 3); + Bi = rol32((Ako1^Do1), 13); + Bo = rol32((Asu1^Du0), 4); + Aga1 = Ba ^((~Be)& Bi ); + Ame0 = Be ^((~Bi)& Bo ); + Abi1 = Bi ^((~Bo)& Bu ); + Ako1 = Bo ^((~Bu)& Ba ); + Asu1 = Bu ^((~Ba)& Be ); + + Bu = rol32((Aga0^Da1), 9); + Ba = (Ame1^De0); + Be = rol32((Abi0^Di1), 3); + Bi = rol32((Ako0^Do0), 12); + Bo = rol32((Asu0^Du1), 4); + Aga0 = Ba ^((~Be)& Bi ); + Ame1 = Be ^((~Bi)& Bo ); + Abi0 = Bi ^((~Bo)& Bu ); + Ako0 = Bo ^((~Bu)& Ba ); + Asu0 = Bu ^((~Ba)& Be ); + + Be = rol32((Asa1^Da0), 18); + Bi = rol32((Age1^De0), 5); + Bo = rol32((Ami1^Di1), 8); + Bu = rol32((Abo1^Do0), 28); + Ba = rol32((Aku0^Du1), 14); + Asa1 = Ba ^((~Be)& Bi ); + Age1 = Be ^((~Bi)& Bo ); + Ami1 = Bi ^((~Bo)& Bu ); + Abo1 = Bo ^((~Bu)& Ba ); + Aku0 = Bu ^((~Ba)& Be ); + + Be = rol32((Asa0^Da1), 18); + Bi = rol32((Age0^De1), 5); + Bo = rol32((Ami0^Di0), 7); + Bu = rol32((Abo0^Do1), 28); + Ba = rol32((Aku1^Du0), 13); + Asa0 = Ba ^((~Be)& Bi ); + Age0 = Be ^((~Bi)& Bo ); + Ami0 = Bi ^((~Bo)& Bu ); + Abo0 = Bo ^((~Bu)& Ba ); + Aku1 = Bu ^((~Ba)& Be ); + + Bo = rol32((Aka0^Da1), 21); + Bu = rol32((Ase0^De0), 1); + Ba = rol32((Agi1^Di0), 31); + Be = rol32((Amo0^Do1), 28); + Bi = rol32((Abu0^Du1), 20); + Aka0 = Ba ^((~Be)& Bi ); + Ase0 = Be ^((~Bi)& Bo ); + Agi1 = Bi ^((~Bo)& Bu ); + Amo0 = Bo ^((~Bu)& Ba ); + Abu0 = Bu ^((~Ba)& Be ); + + Bo = rol32((Aka1^Da0), 20); + Bu = rol32((Ase1^De1), 1); + Ba = rol32((Agi0^Di1), 31); + Be = rol32((Amo1^Do0), 27); + Bi = rol32((Abu1^Du0), 19); + Aka1 = Ba ^((~Be)& Bi ); + Ase1 = Be ^((~Bi)& Bo ); + Agi0 = Bi ^((~Bo)& Bu ); + Amo1 = Bo ^((~Bu)& Ba ); + Abu1 = Bu ^((~Ba)& Be ); + + KeccakAtoD_round3(); + + Ba = (Aba0^Da0); + Be = rol32((Abe0^De0), 22); + Bi = rol32((Abi0^Di1), 22); + Bo = rol32((Abo0^Do1), 11); + Bu = rol32((Abu0^Du0), 7); + Aba0 = Ba ^((~Be)& Bi ); + Aba0 ^= RoundConstants32[i+6]; + Abe0 = Be ^((~Bi)& Bo ); + Abi0 = Bi ^((~Bo)& Bu ); + Abo0 = Bo ^((~Bu)& Ba ); + Abu0 = Bu ^((~Ba)& Be ); + + Ba = (Aba1^Da1); + Be = rol32((Abe1^De1), 22); + Bi = rol32((Abi1^Di0), 21); + Bo = rol32((Abo1^Do0), 10); + Bu = rol32((Abu1^Du1), 7); + Aba1 = Ba ^((~Be)& Bi ); + Aba1 ^= RoundConstants32[i+7]; + Abe1 = Be ^((~Bi)& Bo ); + Abi1 = Bi ^((~Bo)& Bu ); + Abo1 = Bo ^((~Bu)& Ba ); + Abu1 = Bu ^((~Ba)& Be ); + + Bi = rol32((Aga0^Da1), 2); + Bo = rol32((Age0^De1), 23); + Bu = rol32((Agi0^Di1), 31); + Ba = rol32((Ago0^Do0), 14); + Be = rol32((Agu0^Du0), 10); + Aga0 = Ba ^((~Be)& Bi ); + Age0 = Be ^((~Bi)& Bo ); + Agi0 = Bi ^((~Bo)& Bu ); + Ago0 = Bo ^((~Bu)& Ba ); + Agu0 = Bu ^((~Ba)& Be ); + + Bi = rol32((Aga1^Da0), 1); + Bo = rol32((Age1^De0), 22); + Bu = rol32((Agi1^Di0), 30); + Ba = rol32((Ago1^Do1), 14); + Be = rol32((Agu1^Du1), 10); + Aga1 = Ba ^((~Be)& Bi ); + Age1 = Be ^((~Bi)& Bo ); + Agi1 = Bi ^((~Bo)& Bu ); + Ago1 = Bo ^((~Bu)& Ba ); + Agu1 = Bu ^((~Ba)& Be ); + + Bu = rol32((Aka0^Da0), 9); + Ba = rol32((Ake0^De1), 1); + Be = rol32((Aki0^Di0), 3); + Bi = rol32((Ako0^Do1), 13); + Bo = rol32((Aku0^Du0), 4); + Aka0 = Ba ^((~Be)& Bi ); + Ake0 = Be ^((~Bi)& Bo ); + Aki0 = Bi ^((~Bo)& Bu ); + Ako0 = Bo ^((~Bu)& Ba ); + Aku0 = Bu ^((~Ba)& Be ); + + Bu = rol32((Aka1^Da1), 9); + Ba = (Ake1^De0); + Be = rol32((Aki1^Di1), 3); + Bi = rol32((Ako1^Do0), 12); + Bo = rol32((Aku1^Du1), 4); + Aka1 = Ba ^((~Be)& Bi ); + Ake1 = Be ^((~Bi)& Bo ); + Aki1 = Bi ^((~Bo)& Bu ); + Ako1 = Bo ^((~Bu)& Ba ); + Aku1 = Bu ^((~Ba)& Be ); + + Be = rol32((Ama0^Da0), 18); + Bi = rol32((Ame0^De0), 5); + Bo = rol32((Ami0^Di1), 8); + Bu = rol32((Amo0^Do0), 28); + Ba = rol32((Amu0^Du1), 14); + Ama0 = Ba ^((~Be)& Bi ); + Ame0 = Be ^((~Bi)& Bo ); + Ami0 = Bi ^((~Bo)& Bu ); + Amo0 = Bo ^((~Bu)& Ba ); + Amu0 = Bu ^((~Ba)& Be ); + + Be = rol32((Ama1^Da1), 18); + Bi = rol32((Ame1^De1), 5); + Bo = rol32((Ami1^Di0), 7); + Bu = rol32((Amo1^Do1), 28); + Ba = rol32((Amu1^Du0), 13); + Ama1 = Ba ^((~Be)& Bi ); + Ame1 = Be ^((~Bi)& Bo ); + Ami1 = Bi ^((~Bo)& Bu ); + Amo1 = Bo ^((~Bu)& Ba ); + Amu1 = Bu ^((~Ba)& Be ); + + Bo = rol32((Asa0^Da1), 21); + Bu = rol32((Ase0^De0), 1); + Ba = rol32((Asi0^Di0), 31); + Be = rol32((Aso0^Do1), 28); + Bi = rol32((Asu0^Du1), 20); + Asa0 = Ba ^((~Be)& Bi ); + Ase0 = Be ^((~Bi)& Bo ); + Asi0 = Bi ^((~Bo)& Bu ); + Aso0 = Bo ^((~Bu)& Ba ); + Asu0 = Bu ^((~Ba)& Be ); + + Bo = rol32((Asa1^Da0), 20); + Bu = rol32((Ase1^De1), 1); + Ba = rol32((Asi1^Di1), 31); + Be = rol32((Aso1^Do0), 27); + Bi = rol32((Asu1^Du0), 19); + Asa1 = Ba ^((~Be)& Bi ); + Ase1 = Be ^((~Bi)& Bo ); + Asi1 = Bi ^((~Bo)& Bu ); + Aso1 = Bo ^((~Bu)& Ba ); + Asu1 = Bu ^((~Ba)& Be ); + } +} + +static void xor_lane(struct KeccakContext *ctx, int lane, uint64_t val) +{ + uint32_t x0, x1, t; + uint32_t *dst = ctx->u.state32 + lane*2; + + x0 = val; + t = (x0 ^ (x0 >> 1)) & 0x22222222; x0 = x0 ^ t ^ (t << 1); + t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0C; x0 = x0 ^ t ^ (t << 2); + t = (x0 ^ (x0 >> 4)) & 0x00F000F0; x0 = x0 ^ t ^ (t << 4); + t = (x0 ^ (x0 >> 8)) & 0x0000FF00; x0 = x0 ^ t ^ (t << 8); + x1 = val >> 32; + t = (x1 ^ (x1 >> 1)) & 0x22222222; x1 = x1 ^ t ^ (t << 1); + t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0C; x1 = x1 ^ t ^ (t << 2); + t = (x1 ^ (x1 >> 4)) & 0x00F000F0; x1 = x1 ^ t ^ (t << 4); + t = (x1 ^ (x1 >> 8)) & 0x0000FF00; x1 = x1 ^ t ^ (t << 8); + dst[0] ^= (x0 & 0x0000FFFF) | (x1 << 16); + dst[1] ^= (x0 >> 16) | (x1 & 0xFFFF0000); +} + +static void extract(uint8_t *dst, const struct KeccakContext *ctx, int laneCount) +{ + const uint32_t *src = ctx->u.state32; + uint32_t t, x0, x1; + + while (laneCount--) { + x0 = *src++; + x1 = *src++; + t = (x0 & 0x0000FFFF) | (x1 << 16); + x1 = (x0 >> 16) | (x1 & 0xFFFF0000); + x0 = t; + t = (x0 ^ (x0 >> 8)) & 0x0000FF00; x0 = x0 ^ t ^ (t << 8); + t = (x0 ^ (x0 >> 4)) & 0x00F000F0; x0 = x0 ^ t ^ (t << 4); + t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0C; x0 = x0 ^ t ^ (t << 2); + t = (x0 ^ (x0 >> 1)) & 0x22222222; x0 = x0 ^ t ^ (t << 1); + t = (x1 ^ (x1 >> 8)) & 0x0000FF00; x1 = x1 ^ t ^ (t << 8); + t = (x1 ^ (x1 >> 4)) & 0x00F000F0; x1 = x1 ^ t ^ (t << 4); + t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0C; x1 = x1 ^ t ^ (t << 2); + t = (x1 ^ (x1 >> 1)) & 0x22222222; x1 = x1 ^ t ^ (t << 1); + le32enc(dst + 0, x0); + le32enc(dst + 4, x1); + dst += 8; + } +} + +#endif /* KECCAK_32BIT */ + + +/* + * Common code + */ + +static void xor_byte(struct KeccakContext *ctx, int nbyte, uint8_t val) +{ + int o = nbyte / 8; + int s = (nbyte % 8) * 8; + + xor_lane(ctx, o, (uint64_t)(val) << s); +} + +static void add_bytes(struct KeccakContext *ctx, const uint8_t *p, unsigned int len) +{ + uint64_t w; + unsigned int m = ctx->bytes % 8; + + /* partial word */ + if (m) { + m = 8 - m; + if (m > len) + m = len; + while (m--) { + xor_byte(ctx, ctx->bytes++, *p++); + len--; + } + } + + /* full words */ + while (len >= 8) { + w = le64dec(p); + xor_lane(ctx, ctx->bytes / 8, w); + ctx->bytes += 8; + p += 8; + len -= 8; + } + + /* partial word */ + while (len--) + xor_byte(ctx, ctx->bytes++, *p++); +} + +static void reset(struct KeccakContext *ctx, int rbytes, int obytes) +{ + memset(ctx, 0, sizeof(struct KeccakContext)); + ctx->rbytes = rbytes; + ctx->obytes = obytes; +} + +/* + * Public API + */ + +void keccak224_init(struct KeccakContext *ctx) +{ + reset(ctx, KECCAK224_BLOCK_SIZE, KECCAK224_DIGEST_LENGTH); +} + +void keccak256_init(struct KeccakContext *ctx) +{ + reset(ctx, KECCAK256_BLOCK_SIZE, KECCAK256_DIGEST_LENGTH); +} + +void keccak384_init(struct KeccakContext *ctx) +{ + reset(ctx, KECCAK384_BLOCK_SIZE, KECCAK384_DIGEST_LENGTH); +} + +void keccak512_init(struct KeccakContext *ctx) +{ + reset(ctx, KECCAK512_BLOCK_SIZE, KECCAK512_DIGEST_LENGTH); +} + +void keccak_stream_init(struct KeccakContext *ctx) +{ + reset(ctx, KECCAK_STREAM_BLOCK_SIZE, KECCAK_STREAM_DIGEST_LENGTH); +} + +void keccak_update(struct KeccakContext *ctx, const void *data, unsigned int len) +{ + unsigned int n; + const uint8_t *ptr = data; + + while (len > 0) { + n = ctx->rbytes - ctx->bytes; + if (n > len) + n = len; + add_bytes(ctx, ptr, n); + ptr += n; + len -= n; + + if (ctx->bytes == ctx->rbytes) { + keccak_f(ctx); + ctx->bytes = 0; + } + } +} + +void keccak_final(struct KeccakContext *ctx, uint8_t *dst) +{ + if (!ctx->padded) { + /* 2-bit padding, assumes bytes < rbytes */ + xor_byte(ctx, ctx->bytes, 0x01); + xor_byte(ctx, ctx->rbytes - 1, 0x80); + ctx->padded = 1; + } + + keccak_f(ctx); + + if (ctx->obytes == KECCAK224_DIGEST_LENGTH) { + /* 224-bit result uses partial words */ + uint8_t buf[KECCAK256_DIGEST_LENGTH]; + extract(buf, ctx, KECCAK256_DIGEST_LENGTH / 8); + memcpy(dst, buf, KECCAK224_DIGEST_LENGTH); + memset(buf, 0, sizeof(buf)); + } else { + extract(dst, ctx, ctx->obytes / 8); + } +} + +/* + * DigestInfo + */ + +const struct DigestInfo *digest_KECCAK224(void) +{ + static const struct DigestInfo info = { + (DigestInitFunc *)keccak224_init, + (DigestUpdateFunc *)keccak_update, + (DigestFinalFunc *)keccak_final, + sizeof(struct KeccakContext), + KECCAK224_DIGEST_LENGTH, + KECCAK224_BLOCK_SIZE + }; + return &info; +} + +const struct DigestInfo *digest_KECCAK256(void) +{ + static const struct DigestInfo info = { + (DigestInitFunc *)keccak256_init, + (DigestUpdateFunc *)keccak_update, + (DigestFinalFunc *)keccak_final, + sizeof(struct KeccakContext), + KECCAK256_DIGEST_LENGTH, + KECCAK256_BLOCK_SIZE + }; + return &info; +} + +const struct DigestInfo *digest_KECCAK384(void) +{ + static const struct DigestInfo info = { + (DigestInitFunc *)keccak384_init, + (DigestUpdateFunc *)keccak_update, + (DigestFinalFunc *)keccak_final, + sizeof(struct KeccakContext), + KECCAK384_DIGEST_LENGTH, + KECCAK384_BLOCK_SIZE + }; + return &info; +} + +const struct DigestInfo *digest_KECCAK512(void) +{ + static const struct DigestInfo info = { + (DigestInitFunc *)keccak512_init, + (DigestUpdateFunc *)keccak_update, + (DigestFinalFunc *)keccak_final, + sizeof(struct KeccakContext), + KECCAK512_DIGEST_LENGTH, + KECCAK512_BLOCK_SIZE + }; + return &info; +} + +const struct DigestInfo *digest_KECCAK_STREAM(void) +{ + static const struct DigestInfo info = { + (DigestInitFunc *)keccak_stream_init, + (DigestUpdateFunc *)keccak_update, + (DigestFinalFunc *)keccak_final, + sizeof(struct KeccakContext), + KECCAK_STREAM_DIGEST_LENGTH, + KECCAK_STREAM_BLOCK_SIZE + }; + return &info; +} + diff --git a/usual/crypto/keccak.h b/usual/crypto/keccak.h new file mode 100644 index 0000000..86c9951 --- /dev/null +++ b/usual/crypto/keccak.h @@ -0,0 +1,113 @@ +/* + * Keccak implementation for SHA3 parameters. + * + * Copyright (c) 2012 Marko Kreen + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** @file + * Keccak with SHA3 parameters. + */ + +#ifndef _USUAL_CRYPTO_KECCAK_H_ +#define _USUAL_CRYPTO_KECCAK_H_ + +#include + +/* + * SHA3 fixed-length output modes. + */ + +/** Output length for 224-bit mode (in bytes) */ +#define KECCAK224_DIGEST_LENGTH (224/8) +/** Output length for 256-bit mode (in bytes) */ +#define KECCAK256_DIGEST_LENGTH (256/8) +/** Output length for 384-bit mode (in bytes) */ +#define KECCAK384_DIGEST_LENGTH (384/8) +/** Output length for 512-bit mode (in bytes) */ +#define KECCAK512_DIGEST_LENGTH (512/8) + +/** Number of data bytes processed in one loop. */ +#define KECCAK224_BLOCK_SIZE (1152/8) +/** Number of data bytes processed in one loop. */ +#define KECCAK256_BLOCK_SIZE (1088/8) +/** Number of data bytes processed in one loop. */ +#define KECCAK384_BLOCK_SIZE (832/8) +/** Number of data bytes processed in one loop. */ +#define KECCAK512_BLOCK_SIZE (576/8) + +/** Number of data bytes processed in one go. */ +#define KECCAK_STREAM_BLOCK_SIZE (1024/8) + +/** + * Output length for stream mode (in bytes). + * + * This means output from single call to keccak_final(). + * It can be called repeatedly to get more output. + */ +#define KECCAK_STREAM_DIGEST_LENGTH KECCAK_STREAM_BLOCK_SIZE + +/** + * Keccak state structure for all modes. + */ +struct KeccakContext { + /* 5*5*64 bit state */ + union { + uint64_t state64[25]; + uint32_t state32[2*25]; + } u; + uint16_t bytes; /* current number of bytes in buffer */ + uint16_t rbytes; /* number of bytes in one step */ + uint16_t obytes; /* output bytes */ + uint16_t padded; /* is padding added? */ +}; + +/** SHA3 fixed length output mode. */ +void keccak224_init(struct KeccakContext *ctx); + +/** SHA3 fixed length output mode. */ +void keccak256_init(struct KeccakContext *ctx); + +/** SHA3 fixed length output mode. */ +void keccak384_init(struct KeccakContext *ctx); + +/** SHA3 fixed length output mode. */ +void keccak512_init(struct KeccakContext *ctx); + +/** + * SHA3 stream mode for Keccak. + * + * In stream mode, keccak_final() can be called repeatedly + * to get output stream of unlimited length. + * + * On each call it outputs next 128 bytes (1024 bits). + */ +void keccak_stream_init(struct KeccakContext *ctx); + +/** + * Hash additional data. + */ +void keccak_update(struct KeccakContext *ctx, const void *data, unsigned int len); + +/** + * Return final result. + * + * Output length depends on mode. See KECCAK*_DIGEST_LENGTH + * constants to get length for particular mode. + * + * In stream mode, this can be called repeatedly. + */ +void keccak_final(struct KeccakContext *ctx, uint8_t *dst); + +#endif