Projects : keksum : keksum_genesis

main.c

Dir - Raw

1/* Standalone KECCAK hashing utility
2 * J. Welsh, May 2019
3 */
4
5#include <fcntl.h>
6#include <signal.h>
7#include <unistd.h>
8#include "io.h"
9
10void sponge(unsigned capacity, size_t out_bits);
11
12#pragma GCC diagnostic ignored "-Woverlength-strings" /* wat. */
13
14static char const usage[] =
15"Usage: keksum [-c] [-sCAPACITY] [-nLENGTH] [-h] [--] [FILE]...\n"
16"Compute KECCAK checksums.\n"
17"\n"
18"With no FILE, act as a filter, reading from standard input then printing\n"
19"a single line containing the hex-encoded hash. Otherwise tabulate hash and\n"
20"name for each FILE.\n"
21"\n"
22"Options:\n"
23" -c read sums from FILEs and check them (TODO)\n"
24" -l set output length in bits (default 512)\n"
25" -s set sponge capacity in bits (default 256)\n"
26" -h print this help and exit\n"
27"\n"
28"Capacity and length both establish upper bounds on security level. Capacity\n"
29"strongly affects speed and hash by changing permutation frequency. Length\n"
30"acts as a truncation of an infinite output stream. (If you use large length\n"
31"with small capacity you will be deluding yourself in quite the same manner\n"
32"as a poorly seeded PRNG.) Both must be multiples of 8. The 1600-bit\n"
33"permutation is always used, thus capacity must be between 8 and 1592.\n";
34
35static void usage_err(char const *msg) {
36 write_line(2,msg);
37 write_str(2,usage);
38 _exit(1);
39}
40
41static unsigned dec_value(unsigned char c) {
42 unsigned r = c-'0';
43 if (r > 9) usage_err(c ? "Bad integer" : "Missing integer value");
44 return r;
45}
46
47static unsigned parse_uint(char const *s) {
48 unsigned acc = dec_value(*s++);
49 if (!acc && *s) usage_err("Bad integer (leading zero)");
50 for (; *s; ++s) {
51 unsigned digit = dec_value(*s);
52 if (acc > ((unsigned) -1)/10)
53 usage_err("Integer out of range");
54 acc *= 10;
55 if (acc > ((unsigned) -1) - digit)
56 usage_err("Integer out of range");
57 acc += digit;
58 }
59 return acc;
60}
61
62int main(int argc, char **argv) {
63 unsigned out_len = 512;
64 /* Rationale: for collision resistance, any hash function needs at
65 * least twice the desired security level in non-redundant output bits
66 * due to the birthday problem. */
67
68 unsigned capacity = 256;
69 /* Rationale: sponge capacity is an upper bound on security level
70 * because the permutation is readily inverted if its full output is
71 * known. Beyond that, its relationship to actual security is not clear
72 * to me (or perhaps anyone); some margin of safety seems prudent. The
73 * EuCrypt default is 256 (bitrate 1344). But note that in the FIPS202
74 * parameters, capacity under 512 is seen only in "SHAKE128" and none
75 * of the "SHA3" fixed-width hashes. See also:
76 * http://fixpoint.welshcomputing.com/keksum-a-keccak-imp/#comments */
77
78 signal(SIGPIPE,SIG_IGN); /* standard unix-hate */
79
80#define SHIFT (--argc, ++argv)
81 if (!argc) goto endopts;
82 for (SHIFT; argc; SHIFT) {
83 char const *arg = *argv;
84 if (arg[0] != '-') goto endopts;
85 switch (arg[1]) {
86 case 0: goto endopts;
87 case 'l': out_len = parse_uint(arg+2); break;
88 case 's': capacity = parse_uint(arg+2); break;
89 case 'h': write_str(1,usage); return 0;
90 case '-': if (!arg[2]) { SHIFT; goto endopts; }
91 /* fallthrough */
92 default: usage_err("Bad option");
93 }
94 }
95endopts:
96 if (out_len&7) usage_err("Length not byte-aligned");
97 if (capacity&7) usage_err("Capacity not byte-aligned");
98 if (!(0 < capacity && capacity < 1600))
99 usage_err("Capacity out of range");
100
101 if (argc) {
102 /* Listing is similar to the GNU (?) format but with no input
103 * mode character (you may know this as the mysterious extra
104 * space): it's always binary. */
105 for (; argc; SHIFT) {
106 int fd = chkp(*argv, open(*argv, O_RDONLY));
107 chkp("dup2", dup2(fd,0));
108 chkp("close", close(fd));
109 sponge(capacity,out_len);
110 write_str(1," ");
111 write_line(1,*argv);
112 }
113 }
114 else {
115 sponge(capacity,out_len);
116 newline(1);
117 }
118 return 0;
119}