diff --git a/2019/diels-grabsch2/.gitignore b/2019/diels-grabsch2/.gitignore index eb19e2f8d..b7206d379 100644 --- a/2019/diels-grabsch2/.gitignore +++ b/2019/diels-grabsch2/.gitignore @@ -6,3 +6,5 @@ indent.c indent.o prog prog.orig +prog.txt +sha512sum.txt diff --git a/2019/diels-grabsch2/Makefile b/2019/diels-grabsch2/Makefile index fa463d895..7cc3c9864 100644 --- a/2019/diels-grabsch2/Makefile +++ b/2019/diels-grabsch2/Makefile @@ -38,7 +38,7 @@ include ../../var.mk # Common C compiler warnings to silence # -CSILENCE= +CSILENCE= -Wno-strict-prototypes # Common C compiler warning flags # diff --git a/2019/diels-grabsch2/README.md b/2019/diels-grabsch2/README.md index e707864b3..e1ccfebc3 100644 --- a/2019/diels-grabsch2/README.md +++ b/2019/diels-grabsch2/README.md @@ -15,7 +15,7 @@ make ### Try: ```sh -sha512sum prog.c || shasum -a 512 prog.c +./try.sh ``` @@ -52,11 +52,11 @@ No crypto was broken in the making of this program! The trick is that under the hood, this program is a quine! That is, it is aware of its own source code in string representation. But instead of printing that -string, its SHA-512 hash is computed and printed. So two major steps were -needed to obfuscate this program: +string (its own source), its SHA-512 hash is computed and printed. So two major +steps were needed to obfuscate this program: -1. Hide the quine -2. Hide the SHA-512 computation +1. Hide the quine. +2. Hide the SHA-512 computation. Note that both steps were achieved mostly algorithmically. The code is otherwise as short and as clean as possible. The implementation is @@ -110,11 +110,11 @@ the cube roots of the first 80 primes. So the round constants are calculated at runtime, which makes the program shorter and adds another layer of obfuscation. -While this sounds like just iterating primes and executing pow(), this +While this sounds like just iterating primes and executing `pow(3)`, this turned out to be harder than expected. If we were computing SHA-256, it would have been as simple as that, because the round constants would have been 32-bit values. However, SHA-512 needs the cube roots -at 64-bit precision, while double has only 53-bit mantissa precision. +at 64-bit precision, while `double` has only 53-bit mantissa precision. Using higher-precision floating point is no option here, because the program is meant to be portable C99. And implementing arbitrary-precision @@ -145,7 +145,7 @@ around 7, so we need to compute with 3 bits for the integral part and The reason for challenge 3 is that the cube of a 67-bit number is `3*67=201` bits, but fortunately we only need to check if it is close -enough to the actual prime. It won't be exactly e.g. `409.0000...` +enough to the actual prime. It won't be exactly `409.0000...` anyway, but must be accurate enough to distinguish the correct cube root from its neighbours, e.g. the same number with the 64th fractional digit increased. @@ -167,8 +167,8 @@ That's it. Well, I could continue with details about the encoding of the internal state values into the string, how to avoid escaping issues, how to -find short notations for various loops, how to get rid of if(), where -the final "\";\n" is stored, how to eliminate intermediate values and +find short notations for various loops, how to get rid of `if()`, where +the final `"\";\n"` is stored, how to eliminate intermediate values and arrays by reordering of operations, and so on. But those were all minor issues compared to the challenges described above. What's documented here is all you need to know to write your own version of diff --git a/2019/diels-grabsch2/prog.c b/2019/diels-grabsch2/prog.c index ff04c9f4c..85bf2b349 100644 --- a/2019/diels-grabsch2/prog.c +++ b/2019/diels-grabsch2/prog.c @@ -10,6 +10,6 @@ b*c>>32))*a>>21)+(3*a*a*b>>6)+((b>>4)*(b>>4)*b>>46))>>18)+a*a*a)h(m,t((b<<16)|(c ^(~a&c))i(r,b(a,1)^b(a,8)^(a>>7))g(o,0,0,c<8;c++,a*256+w[b*8+c])g(d,0,0,c<13;c++,a*31+w[b*13+c]-96)g(p,0,4,c;c/=2,a|c*m(b,a|c,a) )g(q,0,1ull<<63,c;c/=2,a|c*m(b,p(b),a|c))g(v,b>1,2,c14),c[e]+=c[(e+9)%16]+r(c[ -(e+1)%16])+_(c[(e+14)%16])))j(k,f(8,b[e]=a[e])f(80,n(a,&e,c))f(8,a[e]+=b[e]))int main(void){z a[8],b[8],c[16];f(8,a[e]=d(e))f(16,c[e +(e+1)%16])+_(c[(e+14)%16])))j(k,f(8,b[e]=a[e])f(80,n(a,&e,c))f(8,a[e]+=b[e]))int main(){z a[8],b[8],c[16];f(8,a[e]=d(e))f(16,c[e ]=e-15?o(e):d(8))k(a,b,c);f(16,c[e]=e?e-15?0:11264:1ull<<63)k(a,b,c);f(8,printf("%016llx%s",a[e],e-7?"":"\n"))return!w;}y*w=(y*) "crsmyiajqhwy{unwa|hjoi`hlxhpxrzb~edko~rtr~ileqyjk`znqgsuitvgqnfdfa||wedvnmhozkpokootqzcexeld~oibqzpcsuw{ib{x`m`hsa`jmn}wcfzpb"; diff --git a/2019/diels-grabsch2/try.sh b/2019/diels-grabsch2/try.sh new file mode 100755 index 000000000..29111a969 --- /dev/null +++ b/2019/diels-grabsch2/try.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# +# try.sh - demonstrate IOCCC winner 2019/diels-grabsch2 +# + +# make sure CC is set so that when we do make CC="$CC" it isn't empty. Doing it +# this way allows us to have the user specify a different compiler in an easy +# way. +if [[ -z "$CC" ]]; then + CC="cc" +fi + +make CC="$CC" all >/dev/null || exit 1 + +# clear screen after compilation so that only the entry is shown +clear + +SHA512SUM="$(type -P sha512sum)" +SHASUM="$(type -P shasum)" + +if [[ -z "$SHA512SUM" && -z "$SHASUM" ]]; then + echo "$ ./prog" 1>&2 + ./prog +elif [[ -n "$SHA512SUM" ]]; then + echo "$ $SHA512SUM prog.c" 1>&2 + "$SHA512SUM" prog.c + echo 1>&2 + + echo "$ ./prog" 1>&2 + ./prog + echo 1>&2 + + echo "$ $SHA512SUM prog.c | cut -f 1 -d' ' > sha512sum.txt" 1>&2 + "$SHA512SUM" prog.c | cut -f 1 -d' ' > sha512sum.txt + echo "$ ./prog > prog.txt" 1>&2 + ./prog > prog.txt + echo 1>&2 + + echo "$ diff -s sha512sum.txt prog.txt" 1>&2 + diff -s sha512sum.txt prog.txt + rm -f sha512sum prog.txt + +elif [[ -n "$SHASUM" ]]; then + # Be extra careful and don't use 'else' + echo "$ $SHASUM -a 512 prog.c" 1>&2 + "$SHASUM" -a 512 prog.c + echo 1>&2 + + echo "$ ./prog" 1>&2 + ./prog + echo 1>&2 + + echo "$ $SHASUM -a 512 prog.c | cut -f 1 -d' ' > sha512sum.txt" 1>&2 + "$SHASUM" -a 512 prog.c | cut -f 1 -d' ' > sha512sum.txt + echo "$ ./prog > prog.txt" 1>&2 + ./prog > prog.txt + echo 1>&2 + + echo "$ diff -s sha512sum.txt prog.txt" 1>&2 + diff -s sha512sum.txt prog.txt + rm -f sha512sum prog.txt + + +fi diff --git a/thanks-for-help.md b/thanks-for-help.md index 3f654d7e7..c8ac00172 100644 --- a/thanks-for-help.md +++ b/thanks-for-help.md @@ -4154,10 +4154,11 @@ having tarballs for each individual entry as a convenience. ## [2019/diels-grabsch2](/2019/diels-grabsch2/prog.c) ([README.md](/2019/diels-grabsch2/README.md])) -[Cody](#cody) made the author's statement that the entry compiles cleanly true by fixing -`warning: a function declaration without a prototype is deprecated in all -versions of C` (in main()). Not strictly necessary but if he's making fixes he -might as well. +[Cody](#cody) added the [try.sh](/2019/diels-grabsch2/try.sh) script. This +script will try and show the difference (i.e. the same output) between the +program and the result of `sha512sum` or `shasum -a 512` if either of those +tools can be found but otherwise it'll just run the program itself, showing its +own sha512sum value. ## [2019/dogon](/2019/dogon/prog.c) ([README.md](/2019/dogon/README.md))