diff options
-rw-r--r-- | c/sha3.c | 99 | ||||
-rw-r--r-- | c/sha3.h | 32 | ||||
-rw-r--r-- | c/sha3sum.c | 517 | ||||
-rw-r--r-- | java-c-jni/SHA3.java | 97 | ||||
l---------[-rw-r--r--] | java-c-jni/sha3sum.java | 273 | ||||
-rw-r--r-- | pure-java/SHA3.java | 4 | ||||
-rw-r--r-- | pure-java/sha3sum.java | 118 | ||||
-rwxr-xr-x | python3/sha3sum.py | 398 |
8 files changed, 1041 insertions, 497 deletions
@@ -611,10 +611,12 @@ extern void update(byte* msg, long msglen) /** * Absorb the last part of the message and squeeze the Keccak sponge * - * @param msg The rest of the message, may be {@code null} - * @param msglen The length of the partial message + * @param msg The rest of the message, may be {@code null} + * @param msglen The length of the partial message + * @param withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} + * @return The hash sum, or {@code null} if <tt>withReturn</tt> is {@code false} */ -extern byte* digest(byte* msg, long msglen) +extern byte* digest(byte* msg, long msglen, boolean withReturn) { byte* message; byte* rc; @@ -671,17 +673,98 @@ extern byte* digest(byte* msg, long msglen) /* Squeezing phase */ olen = n; - ni = min(25, rr); + if (withReturn) + { + ni = min(25, rr); + while (olen > 0) + { + i = 0; + while ((i < ni) && (j < nn)) + { + llong v = S[(i % 5) * 5 + i / 5]; + for (_ = 0; _ < ww; _++) + { + if (j < nn) + rc[ptr++] = (byte)v; + v >>= 8; + j += 1; + } + i += 1; + } + olen -= r; + if (olen > 0) + keccakF(S); + } + if ((n & 7)) + rc[n >> 3] &= (1 << (n & 7)) - 1; + + return rc; + } + while ((olen -= r) > 0) + keccakF(S); + return null; +} + + +/** + * Force some rounds of Keccak-f + * + * @param times The number of rounds + */ +extern void simpleSqueeze(long times) +{ + long i; + for (i = 0; i < times; i++) + keccakF(S); +} + + +/** + * Squeeze as much as is needed to get a digest a number of times + * + * @param times The number of digests + */ +extern void fastSqueeze(long times) +{ + long i, olen; + for (i = 0; i < times; i++) + { + keccakF(S); /* Last squeeze did not do a ending squeeze */ + olen = n; + while ((olen -= r) > 0) + keccakF(S); + } +} + + +/** + * Squeeze out another digest + * + * @return The hash sum + */ +extern byte* squeeze() +{ + long nn, ww, olen, i, j, ptr, ni; + byte* rc; + + keccakF(S); /* Last squeeze did not do a ending squeeze */ + + ww = w >> 3; + rc = (byte*)malloc(nn = (n + 7) >> 3); + olen = n; + j = ptr = 0; + ni = (25 < r >> 3) ? 25 : (r >> 3); + while (olen > 0) { i = 0; while ((i < ni) && (j < nn)) { - llong v = S[(i % 5) * 5 + i / 5]; + long _, v = S[(i % 5) * 5 + i / 5]; for (_ = 0; _ < ww; _++) { if (j < nn) - rc[ptr++] = (byte)v; + *(rc + ptr++) = (byte)v; v >>= 8; j += 1; } @@ -691,8 +774,8 @@ extern byte* digest(byte* msg, long msglen) if (olen > 0) keccakF(S); } - if ((n & 7)) - rc[n >> 3] &= (1 << (n & 7)) - 1; + if (n & 7) + rc[nn - 1] &= (1 << (n & 7)) - 1; return rc; } @@ -48,8 +48,34 @@ extern void update(char* msg, long msglen); /** * Absorb the last part of the message and squeeze the Keccak sponge * - * @param msg The rest of the message, may be {@code null} - * @param msglen The length of the partial message + * @param msg The rest of the message, may be {@code null} + * @param msglen The length of the partial message + * @param withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} + * @return The hash sum, or {@code null} if <tt>withReturn</tt> is {@code false} + */ +extern char* digest(char* msg, long msglen, long withReturn); + + +/** + * Force some rounds of Keccak-f + * + * @param times The number of rounds + */ +extern void simpleSqueeze(long times); + + +/** + * Squeeze as much as is needed to get a digest a number of times + * + * @param times The number of digests + */ +extern void fastSqueeze(long times); + + +/** + * Squeeze out another digest + * + * @return The hash sum */ -extern char* digest(char* msg, long msglen); +extern char* squeeze(); diff --git a/c/sha3sum.c b/c/sha3sum.c index b5d0c6a..d3657d7 100644 --- a/c/sha3sum.c +++ b/c/sha3sum.c @@ -26,10 +26,116 @@ #define true 1 #define null 0 +#define SET void** + #define HEXADECA "0123456789ABCDEF" /** + * Prints a number of bytes to stdout + * + * @param bytes The bytes to print + * @param n The number of bytes + */ +inline void putchars(char* bytes, long n) +{ + fwrite(bytes, 1, n, stdout); +} + + +/** + * Creates a new set + * + * @return The set + */ +SET set_new() +{ + return (void**)malloc(sizeof(void*) << 4); +} + + +/** + * Frees a set + * + * @param set The set + */ +void set_free(SET set) +{ + if (*(set + 0)) set_free((void**)*(set + 0)); + if (*(set + 1)) set_free((void**)*(set + 1)); + if (*(set + 2)) set_free((void**)*(set + 2)); + if (*(set + 3)) set_free((void**)*(set + 3)); + if (*(set + 4)) set_free((void**)*(set + 4)); + if (*(set + 5)) set_free((void**)*(set + 5)); + if (*(set + 6)) set_free((void**)*(set + 6)); + if (*(set + 7)) set_free((void**)*(set + 7)); + if (*(set + 8)) set_free((void**)*(set + 8)); + if (*(set + 9)) set_free((void**)*(set + 9)); + if (*(set + 10)) set_free((void**)*(set + 10)); + if (*(set + 11)) set_free((void**)*(set + 11)); + if (*(set + 12)) set_free((void**)*(set + 12)); + if (*(set + 13)) set_free((void**)*(set + 13)); + if (*(set + 14)) set_free((void**)*(set + 14)); + if (*(set + 15)) set_free((void**)*(set + 15)); + free(set); +} + + +/** + * Adds an item to a set + * + * @param set The set + * @param item The item + * @param n The length of the item + */ +void set_add(SET set, char* item, long n) +{ + long i; + void** at = set; + for (i = 0; i < n; i++) + { + long a = (long)((*(item + i)) & 15), b = (long)((*(item + i) >> 4) & 15); + if (*(at + a)) + at = (void**)*(at + a); + else + at = (void**)(*(at + a) = (void*)malloc(sizeof(void*) << 4)); + if (*(at + b)) + at = (void**)*(at + b); + else + at = (void**)(*(at + b) = (void*)malloc(sizeof(void*) << 4)); + } +} + + +/** + * Checks if a set contains an item + * + * @param set The set + * @param item The item + * @param n The length of the item + * @return Whether the set contains the item + */ +long set_contains(SET set, char* item, long n) +{ + long i; + void** at = set; + for (i = 0; i < n; i++) + { + long a = (long)((*(item + i)) & 15), b = (long)((*(item + i) >> 4) & 15); + if (*(at + a)) + at = (void**)*(at + a); + else + return false; + if (*(at + b)) + at = (void**)*(at + b); + else + return false; + } + return true; +} + + +/** * String equality comparator * * @param a First comparand @@ -70,8 +176,11 @@ long parseInt(char* str) int main(int argc, char** argv) { char* cmd = *argv; - long _o, o, _s, s, _r, r, _c, c, _w, w, _i, i; - long binary = false, dashed = false, fptr = 0, freelinger = true; + + long _o, o, _s, s, _r, r, _c, c, _w, w, _i, i, _j, j; + long _O, O, _S, S, _R, R, _C, C, _W, W, _I, I, _J, J; + long binary = false, hex = false, dashed = false, freelinger = true; + long multi = 0, fptr = 0, bn; char** files = (char**)malloc(argc * sizeof(char*)); char** linger = (char**)malloc(sizeof(char*) << 1); @@ -79,6 +188,11 @@ int main(int argc, char** argv) long a = 0, an = argc - 1; char** args = argv + 1; + + _O = _S = _R = _C = _W = _I = false; + O = S = R = C = W = I = J = 0; + o = s = r = c = w = i = j = 0; + *linger = 0; @@ -89,25 +203,26 @@ int main(int argc, char** argv) if (s >= 0) cmd += s + 1; - o = _o = 512; /* --outputsize */ + _o = 512; /* --outputsize */ if ((cmd[0] == 's') && (cmd[1] == 'h') && (cmd[2] == 'a') && (cmd[3] == '3') && (cmd[4] == '-')) if ((cmd[5] != 0) && (cmd[6] != 0) && (cmd[7] != 0)) if ((cmd[8] == 's') && (cmd[9] == 'u') && (cmd[10] == 'm') && (cmd[11] == 0)) { if ((cmd[5] == '2') && (cmd[6] == '2') && (cmd[7] == '4')) - o = _o = 224; + _o = 224; else if ((cmd[5] == '2') && (cmd[6] == '5') && (cmd[7] == '6')) - o = _o = 256; + _o = 256; else if ((cmd[5] == '3') && (cmd[6] == '8') && (cmd[7] == '4')) - o = _o = 384; + _o = 384; else if ((cmd[5] == '5') && (cmd[6] == '1') && (cmd[7] == '2')) - o = _o = 512; + _o = 512; } - s = _s = 1600; /* --statesize */ - r = _r = s - (o << 1); /* --bitrate */ - c = _c = s - r; /* --capacity */ - w = _w = s / 25; /* --wordsize */ - i = _i = 1; /* --iterations */ + _s = 1600; /* --statesize */ + _r = _s - (_o << 1); /* --bitrate */ + _c = _s - _r; /* --capacity */ + _w = _s / 25; /* --wordsize */ + _i = 1; /* --iterations */ + _j = 1; /* --squeezes */ for (; a <= an; a++) @@ -143,8 +258,17 @@ int main(int argc, char** argv) printf(" -i ITERATIONS\n"); printf(" --iterations The number of hash iterations to run. (default: %li)\n", _i); printf(" \n"); + printf(" -j SQUEEZES\n"); + printf(" --squeezes The number of hash squeezes to run. (default: %li)\n", _j); + printf(" \n"); + printf(" -h\n"); + printf(" --hex Read the input in hexadecimal, rather than binary.\n"); + printf(" \n"); printf(" -b\n"); printf(" --binary Print the checksum in binary, rather than hexadecimal.\n"); + printf(" \n"); + printf(" -m\n"); + printf(" --multi Print the chechsum at all iterations.\n"); printf("\n"); printf("\n"); printf("COPYRIGHT:\n"); @@ -180,17 +304,19 @@ int main(int argc, char** argv) arg = null; } if (eq(*linger, "-r") || eq(*linger, "--bitrate")) - o = (s - (r = parseInt(linger[1]))) >> 1; + _R = 1 | (R = parseInt(linger[1])); else if (eq(*linger, "-c") || eq(*linger, "--capacity")) - r = s - (c = parseInt(linger[1])); + _C = 1 | (C = parseInt(linger[1])); else if (eq(*linger, "-w") || eq(*linger, "--wordsize")) - s = (w = parseInt(linger[1])) * 25; + _W = 1 | (W = parseInt(linger[1])); else if (eq(*linger, "-o") || eq(*linger, "--outputsize")) - r = s - ((o = parseInt(linger[1])) << 1); + _O = 1 | (O = parseInt(linger[1])); else if (eq(*linger, "-s") || eq(*linger, "--statesize")) - r = (s = parseInt(linger[1])) - (o << 1); + _S = 1 | (S = parseInt(linger[1])); else if (eq(*linger, "-i") || eq(*linger, "--iterations")) - i = parseInt(linger[1]); + _I = 1 | (I = parseInt(linger[1])); + else if (eq(*linger, "-j") || eq(*linger, "--squeezes")) + _J = 1 | (J = parseInt(linger[1])); else { fprintf(stderr, "%s: unrecognised option: %s\n", cmd, *linger); @@ -237,6 +363,10 @@ int main(int argc, char** argv) else if (eq(arg, "--binary")) binary = true; + else if (eq(arg, "--multi")) + multi++; + else if (eq(arg, "--hex")) + hex = true; else { linger[0] = arg; @@ -252,6 +382,16 @@ int main(int argc, char** argv) binary = true; arg++; } + else if (*arg == 'm') + { + multi++; + arg++; + } + else if (*arg == 'h') + { + hex = true; + arg++; + } else { { @@ -274,22 +414,151 @@ int main(int argc, char** argv) free(linger); + i = _I ? I : _i; + j = _J ? J : _j; + + #define ERR(text) fprintf(stderr, "%s: " text "\n", cmd); fflush(stdout); fflush(stderr) + + if (_S) + { + s = S; + if ((s <= 0) || (s > 1600) || (s % 25)) + { + ERR("the state size must be a positive multiple of 25 and is limited to 1600."); + return 6; + } + } + + if (_W) + { + w = W; + if ((w <= 0) || (w > 64)) + { + ERR("the word size must be positive and is limited to 64."); + return 6; + } + if (_S && (s != w * 25)) + { + ERR("the state size must be 25 times of the word size."); + return 6; + } + else if (_S == null) + _S = 1 | (S = w * 25); + } + + if (_C) + { + c = C; + if ((c <= 0) || (c & 7)) + { + ERR("the capacity must be a positive multiple of 8."); + return 6; + } + } + + if (_R) + { + r = R; + if ((r <= 0) || (r & 7)) + { + ERR("the bitrate must be a positive multiple of 8."); + return 6; + } + } + + if (_O) + { + o = o; + if (o <= 0) + { + ERR("the output size must be positive."); + return 6; + } + } + + if ((_R & _C & _O) == null) /* s? */ + { + s = _S ? s : _s; + r = -((c = (o = (((s << 5) / 100 + 7) >> 3) << 3) << 1) - s); + o = o < 8 ? 8 : o; + } + else if ((_R & _C) == null) /* !o s? */ + { + r = _r; + c = _c; + s = _S ? s : (r + c); + } + else if (_R == null) /* !c o? s? */ + { + r = (s = _S ? s : _s) - c; + o = _O ? o : (c == 8 ? 8 : (c << 1)); + } + else if (_C == null) /* !r o? s? */ + { + c = (s = _S ? s : _s) - r; + o = _O ? o : (c == 8 ? 8 : (c << 1)); + } + else /* !r !c o? s? */ + { + s = _S ? s : (r + c); + o = _O ? o : (c == 8 ? 8 : (c << 1)); + } + + + if (r > s) + { + ERR("the bitrate must not be higher than the state size."); + return 6; + } + if (c > s) + { + ERR("the capacity must not be higher than the state size."); + return 6; + } + if (r + c != s) + { + ERR("the sum of the bitrate and the capacity must equal the state size."); + return 6; + } + + + fprintf(stderr, "Bitrate: %li", r); + fprintf(stderr, "Capacity: %li", c); + fprintf(stderr, "Word size: %li", w); + fprintf(stderr, "State size: %li", s); + fprintf(stderr, "Output Size: %li", o); + fprintf(stderr, "Iterations: %li", i); + fprintf(stderr, "Squeezes: %li", j); + + if (fptr == 0) files[fptr++] = null; if (i < 1) { - fprintf(stderr, "%s: sorry, I will only do at least one iteration!\n", cmd); - fflush(stdout); - fflush(stderr); + ERR("sorry, I will only do at least one hash iteration!"); free(files); return 3; } + if (j < 1) + { + ERR("sorry, I will only do at least one squeeze iteration!"); + free(files); + return 3; + } + + #undef ERR + bn = (o + 7) >> 3; { - char* stdin = null; + char* stdin; char* filename; char* fn; - long f, fail = false, _, bn; + long f, fail, _; + + char* out = binary ? null : (char*)malloc(bn * 2); + + fail = false; + stdin = null; for (f = 0; f < fptr; f++) { @@ -311,80 +580,176 @@ int main(int argc, char** argv) fail = true; continue; } - initialise(r, c, o); - blksize = 4096; /** XXX os.stat(os.path.realpath(fn)).st_size; **/ - chunk = (char*)malloc(blksize); - for (;;) + if ((filename != null) || (stdin == null)) { - long read = fread(chunk, 1, blksize, file); - if (read <= 0) - break; - update(chunk, read); - } - free(chunk); - bs = digest(null, 0); - dispose(); - bn = (o + 7) >> 3; - for (_ = 1; _ < i; _++) - { - char* _ = bs; initialise(r, c, o); - bs = digest(bs, bn); - free(_); + blksize = 4096; /** XXX os.stat(os.path.realpath(fn)).st_size; **/ + chunk = (char*)malloc(blksize); + for (;;) + { + long read = fread(chunk, 1, blksize, file); + if (read <= 0) + break; + if (hex == false) + update(chunk, read); + else + { + int n = read >> 1; + for (_ = 0; _ < n; _++) + { + char a = *(chunk + (_ << 1)), b = *(chunk + ((_ << 1) | 1)); + a = (a & 15) + (a <= '9' ? 0 : 9); + b = (b & 15) + (b <= '9' ? 0 : 9); + *(chunk + _) = (a << 4) | b; + } + update(chunk, n); + } + } + free(chunk); + bs = digest(null, 0, j == 1); + if (j > 2) + fastSqueeze(j - 2); + if (j > 1) + bs = squeeze(1); dispose(); - } - - if (binary) - { - long j; - for (j = 0; j < bn; j++) - putchar(*(bs + j)); + if (filename == null) { - stdin = bs; - bs = null; + stdin = (char*)malloc(bn * sizeof(char)); + for (_ = 0; _ < bn; _++) + *(stdin + _) = *(bs + _); } - fflush(stdout); - } + } else + bs = stdin; + + if (multi == 0) { - long flen = 0, rcptr = 0, b = 0; - char* rc; - if (filename != null) - while (*(filename + flen)) - flen++; - rc = malloc((bn << 1) + 3 + (filename == null ? 1 : 0) + flen); - for (b = 0; b < bn; b++) + for (_ = 1; _ < i; _++) { - char v = bs[b]; - *(rc + rcptr++) = HEXADECA[(v >> 4) & 15]; - *(rc + rcptr++) = HEXADECA[v & 15]; + char* _bs = bs; + initialise(r, c, o); + bs = digest(bs, bn, j == 1); + if (j > 2) + fastSqueeze(j - 2); + if (j > 1) + bs = squeeze(); + free(_bs); + dispose(); } - *(rc + rcptr++) = ' '; - if (filename == null) - *(rc + rcptr++) = '-'; + if (binary) + putchars(bs, bn); else { - flen = 0; - while (*(filename + flen)) - *(rc + rcptr++) = *(filename + flen++); + long b, outptr = 0; + for (b = 0; b < bn; b++) + { + char v = bs[b]; + *(out + outptr++) = HEXADECA[(v >> 4) & 15]; + *(out + outptr++) = HEXADECA[v & 15]; + } + printf("%s %s\n", out, filename ? filename : "-"); } - *(rc + rcptr++) = '\n'; - *(rc + rcptr++) = 0; - printf("%s", rc); - fflush(stdout); - if (filename == null) - stdin = rc; + } + else if (multi == 1) + { + long b; + if (binary) + putchars(bs, bn); else - free(rc); + { + for (b = 0; b < bn; b++) + { + char v = bs[b]; + out[b * 2 ] = HEXADECA[(v >> 4) & 15]; + out[b * 2 + 1] = HEXADECA[v & 15]; + } + printf("%s %s\n", out, filename ? filename : "-"); + } + for (_ = 1; _ < i; _++) + { + char* _bs = bs; + initialise(r, c, o); + bs = digest(bs, bn, j == 1); + if (j > 2) + fastSqueeze(j - 2); + if (j > 1) + bs = squeeze(); + free(_bs); + dispose(); + if (binary) + putchars(bs, bn); + else + { + for (b = 0; b < bn; b++) + { + char v = bs[b]; + out[b * 2 ] = HEXADECA[(v >> 4) & 15]; + out[b * 2 + 1] = HEXADECA[v & 15]; + } + printf("%s\n", out); + } + } + } + else + { + long b, loophere; + char* loop = null; + SET got = set_new(); + for (_ = 0; _ < i; _++) + { + if (_ > 0) + { + char* _bs = bs; + initialise(r, c, o); + bs = digest(bs, bn, j == 1); + if (j > 2) + fastSqueeze(j - 2); + if (j > 1) + bs = squeeze(); + free(_bs); + dispose(); + } + for (b = 0; b < bn; b++) + { + char v = bs[b]; + out[b * 2 ] = HEXADECA[(v >> 4) & 15]; + out[b * 2 + 1] = HEXADECA[v & 15]; + } + if (loop == null) + { + if (set_contains(got, bs, bn)) + { + loop = (char*)malloc(bn * 2); + for (b = 0; b < bn * 2; b++) + *(loop + b) = *(out + b); + } + else + set_add(got, out, bn); + } + loophere = loop && eq(loop, out); + if (loophere) + printf("\033[31m"); + putchars(out, bn * 2); + if (loophere) + printf("\033[00m"); + fflush(stdout); + } + if (loop) + { + fprintf(stderr, "\033[01;31mLoop found\033[00m\n"); + free(loop); + } + set_free(got); } - if (bs != null) free(bs); fclose(file); } + if (out != null) + free(out); if (stdin != null) free(stdin); diff --git a/java-c-jni/SHA3.java b/java-c-jni/SHA3.java index afcb942..05da74c 100644 --- a/java-c-jni/SHA3.java +++ b/java-c-jni/SHA3.java @@ -86,31 +86,116 @@ public class SHA3 /** * Squeeze the Keccak sponge + * + * @return The hash sum */ public static byte[] digest() { - return digest(null); + return digest(null, 0, true); + } + + + /** + * Squeeze the Keccak sponge + * + * @paran withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} + * @return The hash sum, or {@code null} if <tt>withReturn</tt> is {@code false} + */ + public static byte[] digest(boolean withReturn) + { + return digest(null, 0, withReturn); } /** * Absorb the last part of the message and squeeze the Keccak sponge * - * @param msg The rest of the message + * @param msg The rest of the message + * @return The hash sum */ public static byte[] digest(byte[] msg) { - return digest(msg, msg == null ? 0 : msg.length); + return digest(msg, msg == null ? 0 : msg.length, true); } /** * Absorb the last part of the message and squeeze the Keccak sponge * - * @param msg The rest of the message - * @param msglen The length of the partial message + * @param msg The rest of the message + * @paran withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} + * @return The hash sum, or {@code null} if <tt>withReturn</tt> is {@code false} + */ + public static byte[] digest(byte[] msg, boolean withReturn) + { + return digest(msg, msg == null ? 0 : msg.length, withReturn); + } + + + /** + * Absorb the last part of the message and squeeze the Keccak sponge + * + * @param msg The rest of the message + * @param msglen The length of the partial message + * @return The hash sum + */ + public static byte[] digest(byte[] msg, int msglen) + { + return digest(msg, msg == null ? 0 : msg.length, true); + } + + + /** + * Absorb the last part of the message and squeeze the Keccak sponge + * + * @param msg The rest of the message + * @param msglen The length of the partial message + * @param withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} + * @return The hash sum, or {@code null} if <tt>withReturn</tt> is {@code false} + */ + public static native byte[] digest(byte[] msg, int msglen, boolean withReturn); + + + /** + * Force a round of Keccak-f + */ + public static void simpleSqueeze() + { + simpleSqueeze(1); + } + + + /** + * Force some rounds of Keccak-f + * + * @param times The number of rounds + */ + public static native void simpleSqueeze(int times); + + + /** + * Squeeze as much as is needed to get a digest + */ + public static void fastSqueeze() + { + fastSqueeze(1); + } + + + /** + * Squeeze as much as is needed to get a digest a number of times + * + * @param times The number of digests + */ + public static native void fastSqueeze(int times); + + + /** + * Squeeze out another digest + * + * @return The hash sum */ - public static native byte[] digest(byte[] msg, int msglen); + public static native byte[] squeeze(); } diff --git a/java-c-jni/sha3sum.java b/java-c-jni/sha3sum.java index 080c4b6..27a2d3e 100644..120000 --- a/java-c-jni/sha3sum.java +++ b/java-c-jni/sha3sum.java @@ -1,272 +1 @@ -/** - * sha3sum – SHA-3 (Keccak) checksum calculator - * - * Copyright © 2013 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -import java.io.*; -import java.util.*; - - -/** - * SHA-3/Keccak checksum calculator - * - * @author Mattias Andrée <a href="mailto:maandree@member.fsf.org">maandree@member.fsf.org</a> - */ -public class sha3sum -{ - /** - * This is the main entry point of the program - * - * @param args Command line arguments - * @throws IOException On I/O error (such as broken pipes) - */ - public static void main(String[] args) throws IOException - { - run("sha3sum", args); - } - - - /** - * Run the program - * - * @param cmd The command - * @param argv Command line arguments - * @throws IOException On I/O error (such as broken pipes) - */ - public static void run(String cmd, String[] argv) throws IOException - { - if (cmd.indexOf('/') >= 0) - cmd = cmd.substring(cmd.lastIndexOf('/') + 1); - if (cmd.endsWith(".jar")) - cmd = cmd.substring(0, cmd.length() - 4); - cmd = cmd.intern(); - - int _o, o = _o = 512; /* --outputsize */ - if (cmd == "sha3-224sum") o = _o = 224; - else if (cmd == "sha3-256sum") o = _o = 256; - else if (cmd == "sha3-384sum") o = _o = 384; - else if (cmd == "sha3-512sum") o = _o = 512; - int _s, s = _s = 1600; /* --statesize */ - int _r, r = _r = s - (o << 1); /* --bitrate */ - int _c, c = _c = s - r; /* --capacity */ - int _w, w = _w = s / 25; /* --wordsize */ - int _i, i = _i = 1; /* --iterations */ - boolean binary = false; - - String[] files = new String[argv.length + 1]; - int fptr = 0; - boolean dashed = false; - String[] linger = null; - - String[] args = new String[argv.length + 1]; - System.arraycopy(argv, 0, args, 0, argv.length); - for (int a = 0, an = args.length; a < an; a++) - { String arg = args[a]; - arg = arg == null ? null : arg.intern(); - if (linger != null) - { - linger[0] = linger[0].intern(); - if ((linger[0] == "-h") || (linger[0] == "--help")) - { - System.out.println(""); - System.out.println("SHA-3/Keccak checksum calculator"); - System.out.println(""); - System.out.println("USAGE: sha3sum [option...] < file"); - System.out.println(" sha3sum [option...] file..."); - System.out.println(""); - System.out.println(""); - System.out.println("OPTIONS:"); - System.out.println(" -r BITRATE"); - System.out.println(" --bitrate The bitrate to use for SHA-3. (default: " + _r + ")"); - System.out.println(" "); - System.out.println(" -c CAPACITY"); - System.out.println(" --capacity The capacity to use for SHA-3. (default: " + _c + ")"); - System.out.println(" "); - System.out.println(" -w WORDSIZE"); - System.out.println(" --wordsize The word size to use for SHA-3. (default: " + _w + ")"); - System.out.println(" "); - System.out.println(" -o OUTPUTSIZE"); - System.out.println(" --outputsize The output size to use for SHA-3. (default: " + _o + ")"); - System.out.println(" "); - System.out.println(" -s STATESIZE"); - System.out.println(" --statesize The state size to use for SHA-3. (default: " + _s + ")"); - System.out.println(" "); - System.out.println(" -i ITERATIONS"); - System.out.println(" --iterations The number of hash iterations to run. (default: " + _i + ")"); - System.out.println(" "); - System.out.println(" -b"); - System.out.println(" --binary Print the checksum in binary, rather than hexadecimal."); - System.out.println(""); - System.out.println(""); - System.out.println("COPYRIGHT:"); - System.out.println(""); - System.out.println("Copyright © 2013 Mattias Andrée (maandree@member.fsf.org)"); - System.out.println(""); - System.out.println("This program is free software: you can redistribute it and/or modify"); - System.out.println("it under the terms of the GNU General Public License as published by"); - System.out.println("the Free Software Foundation, either version 3 of the License, or"); - System.out.println("(at your option) any later version."); - System.out.println(""); - System.out.println("This program is distributed in the hope that it will be useful,"); - System.out.println("but WITHOUT ANY WARRANTY; without even the implied warranty of"); - System.out.println("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"); - System.out.println("GNU General Public License for more details."); - System.out.println(""); - System.out.println("You should have received a copy of the GNU General Public License"); - System.out.println("along with this program. If not, see <http://www.gnu.org/licenses/>."); - System.out.println(""); - System.exit(2); - } - else - { - if (linger[1] == null) - { - linger[1] = arg; - arg = null; - } - if ((linger[0] == "-r") || (linger[0] == "--bitrate")) - o = (s - (r = Integer.parseInt(linger[1]))) >> 1; - else if ((linger[0] == "-c") || (linger[0] == "--capacity")) - r = s - (c = Integer.parseInt(linger[1])); - else if ((linger[0] == "-w") || (linger[0] == "--wordsize")) - s = (w = Integer.parseInt(linger[1])) * 25; - else if ((linger[0] == "-o") || (linger[0] == "--outputsize")) - r = s - ((o = Integer.parseInt(linger[1])) << 1); - else if ((linger[0] == "-s") || (linger[0] == "--statesize")) - r = (s = Integer.parseInt(linger[1])) - (o << 1); - else if ((linger[0] == "-i") || (linger[0] == "--iterations")) - i = Integer.parseInt(linger[1]); - else - { - System.err.println(cmd + ": unrecognised option: " + linger[0]); - System.exit(1); - } - } - linger = null; - if (arg == null) - continue; - } - if (arg == null) - continue; - if (dashed) - files[fptr++] = arg == "-" ? null : arg; - else if (arg == "--") - dashed = true; - else if (arg == "-") - files[fptr++] = null; - else if (arg.startsWith("--")) - if (arg.indexOf('=') >= 0) - linger = new String[] { arg.substring(0, arg.indexOf('=')), arg.substring(arg.indexOf('=') + 1) }; - else - if (arg == "--binary") - binary = true; - else - linger = new String[] { arg, null }; - else if (arg.startsWith("-")) - { - arg = arg.substring(1); - if (arg.charAt(0) == 'b') - { - binary = true; - arg = arg.substring(1); - } - else if (arg.length() == 1) - linger = new String[] { "-" + arg, null }; - else - linger = new String[] { "-" + arg.charAt(0), arg.substring(1) }; - } - else - files[fptr++] = arg; - } - - if (fptr == 0) - files[fptr++] = null; - if (i < 1) - { - System.err.println(cmd + ": sorry, I will only do at least one iteration!"); - System.exit(3); - } - - byte[] stdin = null; - boolean fail = false; - String filename; - - for (int f = 0; f < fptr; f++) - { if (((filename = files[f]) == null) && (stdin != null)) - { System.out.write(stdin); - continue; - } - String rc = ""; - String fn = filename == null ? "/dev/stdin" : filename; - InputStream file = null; - try - { - file = new FileInputStream(fn); - SHA3.initialise(r, c, o); - int blksize = 4096; /** XXX os.stat(os.path.realpath(fn)).st_size; **/ - byte[] chunk = new byte[blksize]; - for (;;) - { - int read = file.read(chunk, 0, blksize); - if (read <= 0) - break; - SHA3.update(chunk, read); - } - byte[] bs = SHA3.digest(); - for (int _ = 1; _ < i; _++) - { - SHA3.initialise(r, c, o); - bs = SHA3.digest(bs); - } - if (binary) - { if (filename == null) - stdin = bs; - System.out.write(bs); - System.out.flush(); - } - else - { for (int b = 0, bn = bs.length; b < bn; b++) - { rc += "0123456789ABCDEF".charAt((bs[b] >> 4) & 15); - rc += "0123456789ABCDEF".charAt(bs[b] & 15); - } - rc += " " + (filename == null ? "-" : filename) + "\n"; - if (filename == null) - stdin = rc.getBytes("UTF-8"); - System.out.print(rc); - System.out.flush(); - } - } - catch (final IOException err) - { System.err.println(cmd + ": cannot read file: " + filename + ": " + err); - fail = true; - } - finally - { if (file != null) - try - { file.close(); - } - catch (final Throwable ignore) - { //ignore - } } } - - System.out.flush(); - if (fail) - System.exit(5); - } - -} - +../pure-java/sha3sum.java
\ No newline at end of file diff --git a/pure-java/SHA3.java b/pure-java/SHA3.java index 084c8c1..5cacc5f 100644 --- a/pure-java/SHA3.java +++ b/pure-java/SHA3.java @@ -478,7 +478,7 @@ public class SHA3 /** * Squeeze the Keccak sponge * - * @paran withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} + * @param withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} * @return The hash sum, or {@code null} if <tt>withReturn</tt> is {@code false} */ public static byte[] digest(boolean withReturn) @@ -503,7 +503,7 @@ public class SHA3 * Absorb the last part of the message and squeeze the Keccak sponge * * @param msg The rest of the message - * @paran withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} + * @param withReturn Whether to return the hash instead of just do a quick squeeze phrase and return {@code null} * @return The hash sum, or {@code null} if <tt>withReturn</tt> is {@code false} */ public static byte[] digest(byte[] msg, boolean withReturn) diff --git a/pure-java/sha3sum.java b/pure-java/sha3sum.java index e24657e..3b4cec9 100644 --- a/pure-java/sha3sum.java +++ b/pure-java/sha3sum.java @@ -56,6 +56,10 @@ public class sha3sum cmd = cmd.intern(); Integer O = null; int _o = 512; /* --outputsize */ + if (cmd == "sha3-224sum") _o = 224; + else if (cmd == "sha3-256sum") _o = 256; + else if (cmd == "sha3-384sum") _o = 384; + else if (cmd == "sha3-512sum") _o = 512; Integer S = null; int _s = 1600; /* --statesize */ Integer R = null; int _r = _s - (_o << 1); /* --bitrate */ Integer C = null; int _c = _s - _r; /* --capacity */ @@ -64,10 +68,6 @@ public class sha3sum Integer J = null; int _j = 1; /* --squeezes */ int o = 0, s = 0, r = 0, c = 0, w = 0, i = 0, j = 0; - if (cmd == "sha3-224sum") o = _o = 224; - else if (cmd == "sha3-256sum") o = _o = 256; - else if (cmd == "sha3-384sum") o = _o = 384; - else if (cmd == "sha3-512sum") o = _o = 512; boolean binary = false, hex = false; int multi = 0; @@ -244,7 +244,7 @@ public class sha3sum System.exit(6); } else if (S == null) - s = new Integer(w * 25); + S = new Integer(w * 25); } if (C != null) @@ -312,6 +312,7 @@ public class sha3sum System.err.println("State size: " + s); System.err.println("Output size: " + o); System.err.println("Iterations: " + i); + System.err.println("Squeezes: " + j); if (fptr == 0) @@ -341,96 +342,95 @@ public class sha3sum InputStream file = null; try { - file = new FileInputStream(fn); - SHA3.initialise(r, c, o); - int blksize = 4096; /** XXX os.stat(os.path.realpath(fn)).st_size; **/ - byte[] chunk = new byte[blksize]; - for (;;) + byte[] bs; + if ((filename != null) || (stdin == null)) { - int read = file.read(chunk, 0, blksize); - if (read <= 0) - break; - if (hex == false) - SHA3.update(chunk, read); - else + file = new FileInputStream(fn); + SHA3.initialise(r, c, o); + int blksize = 4096; /** XXX os.stat(os.path.realpath(fn)).st_size; **/ + byte[] chunk = new byte[blksize]; + for (;;) { - int n = read << 1; - for (int _ = 0; _ < n; _++) + int read = file.read(chunk, 0, blksize); + if (read <= 0) + break; + if (hex == false) + SHA3.update(chunk, read); + else { - byte a = chunk[_ << 1], b = chunk[(_ << 1) | 1]; - chunk[_] = (byte)((((a & 15) + (a <= '9' ? 0 : 9)) << 4) | ((b & 15) + (b <= '9' ? 0 : 9))); + int n = read >> 1; + for (int _ = 0; _ < n; _++) + { byte a = chunk[_ << 1], b = chunk[(_ << 1) | 1]; + chunk[_] = (byte)((((a & 15) + (a <= '9' ? 0 : 9)) << 4) | ((b & 15) + (b <= '9' ? 0 : 9))); + } + SHA3.update(chunk, n); } - SHA3.update(chunk, n); } + bs = SHA3.digest(j == 1); + if (j > 2) + SHA3.fastSqueeze(j - 2); + if (j > 1) + bs = SHA3.squeeze(); + if (filename == null) + stdin = bs; } - byte[] bs = SHA3.digest(j > 1); - if (j > 2) - SHA3.fastSqueeze(j - 2); - if (j > 1) - bs = SHA3.squeeze(); + else + bs = stdin; if (multi == 0) { for (int _ = 1; _ < i; _++) { SHA3.initialise(r, c, o); - bs = SHA3.digest(bs, j > 1); + bs = SHA3.digest(bs, j == 1); if (j > 2) SHA3.fastSqueeze(j - 2); if (j > 1) bs = SHA3.squeeze(); } if (binary) - { if (filename == null) - stdin = bs; System.out.write(bs); - } else { for (int b = 0, bn = bs.length; b < bn; b++) { rc += "0123456789ABCDEF".charAt((bs[b] >> 4) & 15); rc += "0123456789ABCDEF".charAt(bs[b] & 15); } rc += " " + (filename == null ? "-" : filename) + "\n"; - if (filename == null) - stdin = rc.getBytes("UTF-8"); System.out.print(rc); } } - else if (binary) - { - System.out.write(bs); - for (int _ = 1; _ < i; _++) - { - SHA3.initialise(r, c, o); - bs = SHA3.digest(bs, j > 1); - if (j > 2) - SHA3.fastSqueeze(j - 2); - if (j > 1) - bs = SHA3.squeeze(); - System.out.write(bs); - } - } else if (multi == 1) { - byte[] out = new byte[(bs.length << 1) + 1]; - for (int b = 0, bn = bs.length; b < bn; b++) - { out[ b << 1 ] = (byte)("0123456789ABCDEF".charAt((bs[b] >> 4) & 15)); - out[(b << 1) | 1] = (byte)("0123456789ABCDEF".charAt(bs[b] & 15)); + byte[] out = null; + if (binary) + System.out.write(bs); + else + { + out = new byte[(bs.length << 1) + 1]; + for (int b = 0, bn = bs.length; b < bn; b++) + { out[ b << 1 ] = (byte)("0123456789ABCDEF".charAt((bs[b] >> 4) & 15)); + out[(b << 1) | 1] = (byte)("0123456789ABCDEF".charAt(bs[b] & 15)); + } + out[out.length - 1] = '\n'; + System.out.write(out); } - out[out.length - 1] = '\n'; - System.out.write(out); for (int _ = 1; _ < i; _++) { SHA3.initialise(r, c, o); - bs = SHA3.digest(bs, j > 1); + bs = SHA3.digest(bs, j == 1); if (j > 2) SHA3.fastSqueeze(j - 2); if (j > 1) bs = SHA3.squeeze(); - for (int b = 0, bn = bs.length; b < bn; b++) - { out[ b << 1 ] = (byte)("0123456789ABCDEF".charAt((bs[b] >> 4) & 15)); - out[(b << 1) | 1] = (byte)("0123456789ABCDEF".charAt(bs[b] & 15)); + if (binary) + System.out.write(bs); + else + { + for (int b = 0, bn = bs.length; b < bn; b++) + { out[ b << 1 ] = (byte)("0123456789ABCDEF".charAt((bs[b] >> 4) & 15)); + out[(b << 1) | 1] = (byte)("0123456789ABCDEF".charAt(bs[b] & 15)); + } + System.out.write(out); } - System.out.write(out); } } else @@ -442,7 +442,7 @@ public class sha3sum { if (_ > 0) { SHA3.initialise(r, c, o); - bs = SHA3.digest(bs, j > 1); + bs = SHA3.digest(bs, j == 1); if (j > 2) SHA3.fastSqueeze(j - 2); if (j > 1) @@ -463,7 +463,7 @@ public class sha3sum System.out.println(now); } if (loop != null) - System.out.println("\033[01;31mLoop found\033[00m"); + System.err.println("\033[01;31mLoop found\033[00m"); } System.out.flush(); } diff --git a/python3/sha3sum.py b/python3/sha3sum.py index ae863c2..32b09d1 100755 --- a/python3/sha3sum.py +++ b/python3/sha3sum.py @@ -23,6 +23,11 @@ import sys import os +def printerr(text, end = '\n'): + sys.stderr.buffer.write((text + end).encode('utf-8')) + sys.stderr.buffer.flush() + + class SHA3: ''' SHA-3/Keccak hash algorithm implementation @@ -372,12 +377,16 @@ class SHA3: @staticmethod - def update(msg): + def update(msg, msglen = None): ''' Absorb the more of the message message to the Keccak sponge - @param msg:bytes The partial message + @param msg:bytes The partial message + @param msglen:int The length of the partial message ''' + if msglen is not None: + msg = msg[:msglen] + rr = SHA3.r >> 3 ww = SHA3.w >> 3 @@ -449,19 +458,24 @@ class SHA3: @staticmethod - def digest(msg = None): + def digest(msg = None, msglen = None, withReturn = None): ''' Absorb the last part of the message and squeeze the Keccak sponge - @param msg:bytes The rest of the message + @param msg:bytes? The rest of the message + @param msglen:int The length of the partial message + @param withReturn:bool Whether to return the hash instead of just do a quick squeeze phrase and return `None` + @return :bytes? The hash sum, or `None` if `withReturn` is `False` ''' + if (msglen is not None) and isinstance(msglen, bool): + (msglen, withReturn) = (withReturn, msglen) if msg is None: msg = bytes([]) + elif msglen is not None: + msg = msg[:msglen] message = SHA3.pad10star1(SHA3.M + msg, SHA3.r) SHA3.M = None nnn = len(message) - rc = [0] * ((SHA3.n + 7) >> 3) - ptr = 0 rr = SHA3.r >> 3 nn = (SHA3.n + 7) >> 3 @@ -528,16 +542,86 @@ class SHA3: SHA3.keccakF(SHA3.S) # Squeezing phase + if withReturn: + rc = [0] * ((SHA3.n + 7) >> 3) + ptr = 0 + + olen = SHA3.n + j = 0 + ni = min(25, rr) + while olen > 0: + i = 0 + while (i < ni) and (j < nn): + v = SHA3.S[(i % 5) * 5 + i // 5] + for _ in range(ww): + if j < nn: + rc[ptr] = v & 255 + ptr += 1 + v >>= 8 + j += 1 + i += 1 + olen -= SHA3.r + if olen > 0: + SHA3.keccakF(SHA3.S) + if (SHA3.n & 7) != 0: + rc[len(rc) - 1] &= (1 << (SHA3.n & 7)) - 1 + + return bytes(rc) + + olen = SHA3.n + while olen > SHA3.r: + olen -= SHA3.r + SHA3.keccakF(SHA3.S) + return None + + + def simpleSqueeze(times = 1): + ''' + Force some rounds of Keccak-f + + @param times:int The number of rounds + ''' + for i in range(times): + SHA3.keccakF(SHA3.S) + + + def fastSqueeze(times = 1): + ''' + Squeeze as much as is needed to get a digest a number of times + + @param times:int The number of digests + ''' + for i in range(times): + SHA3.keccakF(SHA3.S) # Last squeeze did not do a ending squeeze + int olen = SHA3.n + while olen > SHA3.r: + olen -= SHA3.r + SHA3.keccakF(SHA3.S) + + + def squeeze(): + ''' + Squeeze out another digest + + @return :bytes The hash sum + ''' + SHA3.keccakF(SHA3.S) # Last squeeze did not do a ending squeeze + + nn = (SHA3.n + 7) >> 3 + ww = SHA3.w >> 3 + rc = [0] * nn olen = SHA3.n j = 0 - ni = min(25, rr) - while (olen > 0): + ptr = 0 + ni = min(25, SHA3.r >> 3) + + while olen > 0: i = 0 while (i < ni) and (j < nn): v = SHA3.S[(i % 5) * 5 + i // 5] for _ in range(ww): - if (j < nn): - rc[ptr] = v & 255 + if j < nn: + rc[ptr] = v ptr += 1 v >>= 8 j += 1 @@ -545,11 +629,12 @@ class SHA3: olen -= SHA3.r if olen > 0: SHA3.keccakF(SHA3.S) + if (SHA3.n & 7) != 0: rc[len(rc) - 1] &= (1 << (SHA3.n & 7)) - 1 return bytes(rc) - + if __name__ == '__main__': @@ -560,19 +645,20 @@ if __name__ == '__main__': if cmd.endswith('.py'): cmd = cmd[:-3] - o = 512 # --outputsize - if cmd == 'sha3-224sum': o = 224 - elif cmd == 'sha3-256sum': o = 256 - elif cmd == 'sha3-384sum': o = 384 - elif cmd == 'sha3-512sum': o = 512 - s = 1600 # --statesize - r = s - (o << 1) # --bitrate - c = s - r # --capacity - w = s // 25 # --wordsize - i = 1 # --iterations - binary = False - - (_r, _c, _w, _o, _s, _i) = (r, c, w, o, s, i) + (O, S, R, C, W, I, J) = (None, None, None, None, None, None, None) + (o, s, r, c, w, i, j) = (0, 0, 0, 0, 0, 0, 0) + _o = 512 # --outputsize + if cmd == 'sha3-224sum': _o = 224 + elif cmd == 'sha3-256sum': _o = 256 + elif cmd == 'sha3-384sum': _o = 384 + elif cmd == 'sha3-512sum': _o = 512 + _s = 1600 # --statesize + _r = _s - (_o << 1) # --bitrate + _c = _s - _r # --capacity + _w = _s / 25 # --wordsize + _i = 1 # --iterations + _j = 1 # --squeezes + (binary, hex, multi) = (False, False, 0) files = [] dashed = False @@ -606,9 +692,18 @@ OPTIONS: -i ITERATIONS --iterations The number of hash iterations to run. (default: %d) - + + -j SQUEEZES + --squeezes The number of hash squeezes to run. (default: %d) + + -h + --hex Read the input in hexadecimal, rather than binary. + -b --binary Print the checksum in binary, rather than hexadecimal. + + -m + --multi Print the chechsum at all iterations. COPYRIGHT: @@ -628,7 +723,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. -''' % (_r, _c, _w, _o, _s, _i)).encode('utf-8')) +''' % (_r, _c, _w, _o, _s, _i, _j)).encode('utf-8')) sys.stderr.buffer.flush() exit(2) else: @@ -636,26 +731,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. linger[1] = arg arg = None if linger[0] in ('-r', '--bitrate'): - r = int(linger[1]) - o = (s - r) >> 1 + R = int(linger[1]) elif linger[0] in ('-c', '--capacity'): - c = int(linger[1]) - r = s - c + C = int(linger[1]) elif linger[0] in ('-w', '--wordsize'): - w = int(linger[1]) - s = w * 25 + W = int(linger[1]) elif linger[0] in ('-o', '--outputsize'): - o = int(linger[1]) - r = s - (o << 1) + O = int(linger[1]) elif linger[0] in ('-s', '--statesize'): - s = int(linger[1]) - r = s - (o << 1) + S = int(linger[1]) elif linger[0] in ('-i', '--iterations'): - i = int(linger[1]) + I = int(linger[1]) + elif linger[0] in ('-j', '--squeezes'): + J = int(linger[1]) else: - sys.stderr.buffer.write((sys.argv[0] + ': unrecognised option: ' + linger[0] + '\n').encode('utf-8')) - sys.stdout.buffer.flush() - exit(1) + printerr(sys.argv[0] + ': unrecognised option: ' + linger[0]) + sys.exit(1) linger = None if arg is None: continue @@ -673,6 +764,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. else: if arg == '--binary': binary = True + elif arg == '--multi': + multi += 1 + elif arg == '--hex': + hex = True else: linger = [arg, None] elif arg.startswith('-'): @@ -680,6 +775,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. if arg[0] == 'b': binary = True arg = arg[1:] + elif arg[0] == 'b': + multi += 1 + arg = arg[1:] + elif arg[0] == 'h': + hex = True + arg = arg[1:] elif len(arg) == 1: linger = ['-' + arg, None] else: @@ -687,12 +788,95 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. else: files.append(arg) + + i = _i if I is None else I + j = _j if J is None else J + + + if S is not None: + s = S + if ((s <= 0) or (s > 1600) or (s % 25 != 0)): + printerr(cmd + ': the state size must be a positive multiple of 25 and is limited to 1600.') + sys.exit(6) + + if W is not None: + w = W + if (w <= 0) or (w > 64): + printerr(cmd + ': the word size must be positive and is limited to 64.') + sys.exit(6) + if (S is not None) and (s != w * 25): + printerr(cmd + ': the state size must be 25 times of the word size.') + sys.exit(6) + elif S is None: + S = w * 25 + + if C is not None: + c = C + if (c <= 0) or ((c & 7) != 0): + printerr(cmd + ': the capacity must be a positive multiple of 8.') + sys.exit(6); + + if R is not None: + r = R + if (r <= 0) or ((r & 7) != 0): + printerr(cmd + ': the bitrate must be a positive multiple of 8.') + sys.exit(6); + + if O is not None: + o = O + if o <= 0: + printerr(cmd + ': the output size must be positive.') + sys.exit(6); + + + if (R is None) and (C is None) and (O is None): ## s? + r = -((c = (o = ((((s = S is None ? _s : s) << 5) / 100 + 7) >> 3) << 3) << 1) - s); + o = 8 if o < 8 else o + elif (R is None) and (C is None): ## !o s? + r = _r + c = _c + s = (r + c) if S is None else s + elif R is None: ## !c o? s? + s = _s if S is None else s + r = s - c; + o = (8 if c == 8 else (c << 1)) if O is None else o; + elif C is None: ## !r o? s? + s = _s if S is None else s + c = s - r; + o = (8 if c == 8 else (c << 1)) if O is None else o; + else: ## !r !c o? s? + s = (r + c) if S is None else s + o = (8 if c == 8 else (c << 1)) if O is None else o + + + if r > s: + printerr(cmd + ': the bitrate must not be higher than the state size.'); + sys.exit(6); + if c > s: + printerr(cmd + ': the capacity must not be higher than the state size.'); + sys.exit(6); + if r + c != s: + printerr(cmd + ': the sum of the bitrate and the capacity must equal the state size.'); + sys.exit(6); + + + printerr('Bitrate: ' % r) + printerr('Capacity: ' % c) + printerr('Word size: ' % w) + printerr('State size: ' % s) + printerr('Output size: ' % o) + printerr('Iterations: ' % i) + printerr('Squeezes: ' % j) + + if len(files) == 0: files.append(None) if i < 1: - sys.stdout.buffer.write((sys.argv[0] + ': sorry, I will only do at least one iteration!\n').encode('utf-8')) - sys.stdout.buffer.flush() - exit(3) + printerr(cmd + ': sorry, I will only do at least one hash iteration!\n') + sys.exit(3) + if j < 1: + printerr(cmd + ': sorry, I will only do at least one squeeze iteration!\n') + sys.exit(3) stdin = None for filename in files: if (filename is None) and (stdin is not None): @@ -700,35 +884,107 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. continue rc = '' fn = '/dev/stdin' if filename is None else filename + fail = False with open(fn, 'rb') as file: - SHA3.initialise(r, c, o) - blksize = (o + 7) >> 3 try: - blksize = os.stat(os.path.realpath(fn)).st_blksize - except: - pass - while True: - chunk = file.read(blksize) - if len(chunk) == 0: - break - SHA3.update(chunk) - bs = SHA3.digest(file.read()) - for _ in range(1, i): - SHA3.initialise(r, c, o) - bs = SHA3.digest(bs) - if binary: - if filename is None: - stdin = bs - sys.stdout.buffer.write(bs) - sys.stdout.buffer.flush() - else: - for b in bs: - rc += "0123456789ABCDEF"[b >> 4] - rc += "0123456789ABCDEF"[b & 15] - rc += ' ' + ('-' if filename is None else filename) + '\n' - if filename is None: - stdin = rc - sys.stdout.buffer.write(rc.encode('UTF-8')) + if (filename is not None) or (stdin is None): + SHA3.initialise(r, c, o) + blksize = 4096 + try: + blksize = os.stat(os.path.realpath(fn)).st_blksize + except: + pass + while True: + chunk = file.read(blksize) + if len(chunk) == 0: + break + if not hex: + SHA3.update(chunk) + else: + chunk = list(chunk) + n = len(chunk) >> 1 + for _ in range(n): + (a, b) = (chunk[_ << 1], chunk[(_ << 1 | 1)]) + a = ((a & 15) + (0 if a <= '9' else 9)) << 4 + b = (b & 15) + (0 if b <= '9' else 0) + chunk[_] = a | b + SHA3.update(chunk, n) + bs = SHA3.digest(j == 1) + if j > 2: + SHA3.fastSqueeze(j - 2) + if j > 1: + bs = SHA3.squeeze(); + if filename is None: + stdin = bs + else: + bs = stdin + if multi == 0: + for _ in range(n - 1): + SHA3.initialise(r, c, o) + bs = SHA3.digest(bs, j == 1) + if j > 2: + SHA3.fastSqueeze(j - 2) + if j > 1: + bs = SHA3.squeeze(); + if binary: + sys.stdout.buffer.write(bs) + else: + for b in bs: + rc += "0123456789ABCDEF"[b >> 4] + rc += "0123456789ABCDEF"[b & 15] + rc += ' ' + ('-' if filename is None else filename) + '\n' + sys.stdout.buffer.write(rc.encode('utf-8')) + elif multi == 1: + if binary: + sys.stdout.buffer.write(bs) + else: + for b in bs: + rc += "0123456789ABCDEF"[b >> 4] + rc += "0123456789ABCDEF"[b & 15] + rc += '\n' + sys.stdout.buffer.write(rc.encode('UTF-8')) + for _ in range(i - 1): + SHA3.initialise(r, c, o) + bs = SHA3.digest(bs, j == 1) + if j > 2: + SHA3.fastSqueeze(j - 2) + if j > 1: + bs = SHA3.squeeze(); + if binary: + sys.stdout.buffer.write(bs); + else: + rc = '' + for b in bs: + rc += "0123456789ABCDEF"[b >> 4] + rc += "0123456789ABCDEF"[b & 15] + rc += '\n' + sys.stdout.buffer.write(rc.encode('UTF-8')) + else: + got = set() + loop = None + for _ in range(i): + if _ > 0: + pass + rc = '' + for b in bs: + rc += "0123456789ABCDEF"[b >> 4] + rc += "0123456789ABCDEF"[b & 15] + if loop is None: + if rc in got: + loop = rc + else: + got.add(rc) + if loop == rc: + rc = '\033[31m%s\033[00m' % rc; + sys.stdout.buffer.write(rc.encode('utf-8')) + sys.stdout.buffer.flush() + if loop is not None: + printerr('\033[01;31mLoop found\033[00m') sys.stdout.buffer.flush() - + except Exception as err: + printerr(cmd + ': connot read file: ' + filename + ': ' + str(err)) + fail = True + sys.stdout.buffer.flush() + if fail: + sys.exit(5) |