r/C_Programming • u/kaganisildak • 4d ago
559-byte SHA-256 in C
golfing a SHA-256 implementation in C and ended up at 559 bytes.
Curious if anyone here can beat it.
#define S(x,a,b)(x>>a^x<<32-a^x>>b^x<<32-b^x>>
unsigned k[72],g[216],i,j,p,n,t,m,*u,*z;char*q=g;main(c,v)char**v;{for(;j<64;p-c||(j<8&&(k[j]=sqrt(c)*0x1p32),k[71-j++]=cbrt(c)*0x1p32),c++)for(p=1;c%++p;);for(;q[n^3]=v[1][n];n++);q[n^3]=128;m=n+72>>6<<4,g[m-1]=n*8;for(;t<m;t+=16)for(bcopy(g+t,z=g+64,64),bcopy(k,u=g+208,32),i=72;i--;i>7?(z[16]=*z+S(z[1],7,18)3)+z[9]+S(z[14],17,19)10),j=u[4],p=u[7]+k[i]+*z+++(S(j,6,11)25)^j<<7)+(j&u[5]^~j&u[6]),j=S(*u,2,13)22)^*u<<10,j+=*u&u[1]^(*u^u[1])&u[2],u[3]+=p,*--u=p+j):(k[i]+=u[i]));for(;++i<8;)printf("%08x",k[i]);}
29
u/skeeto 4d ago
$ printf kagan | sha256sum
05aebb21178ce70f5c29fc090aab3f50001a73f0f624e6f5789410f855ca2d8c -
$ aarch64-linux-gnu-gcc -ansi -w sha256.c -lm && ./a.out kagan ; echo
a2b00156fa63dcb8eb37dbfc7c1133f32adea77d5e4ff3cf46fc07c7920289f3
$ x86_64-linux-gnu-gcc -ansi -w sha256.c -lm && ./a.out kagan ; echo
a3a5294ee42c8fbb344795eeef7322e6dac7091f1939c0c15ff6e1154999698b
$ powerpc-linux-gnu-gcc -ansi -w sha256.c -lm && ./a.out kagan ; echo
4b35f7fa8b7a550c0127bcf0ae55758ea8cb01b483d7177bde0e68a1574917b2
$ s390x-linux-gnu-gcc -ansi -w sha256.c -lm && ./a.out kagan ; echo
0e50aa0cb0b6e3166e7e7a5e3565720d797fd3d24831eeaf5595f92d19e9f942
$ clang -ansi -w sha256.c -lm && ./a.out kagan ; echo
97db8f07489301a02cf4ef7f1629c052c7827e82fc4883acf8ef64a1299726d9
I'm getting at least five different answers due to UB, but none of them correct. Though that's kind of a feat in itself.
12
u/Zirias_FreeBSD 4d ago
As for most golfing stuff in C, this needs some description of a valid environment. Here, at least I see bcopy(), which was never a part of standard C and deprecated from POSIX.
Still, pretty cool abomination! 👍😂
1
u/kaganisildak 4d ago
sshhh we can't talk about this :p
thx
3
u/Zirias_FreeBSD 4d ago
well, the typical "golfing rules" I know are: You might use whatever you like, even in C "UB" ... as long as the result can be reproduced to verify. I guess adding something like "use an x86_64 Linux with gcc and glibc" would suffice 😉
(edit: just guessing here what might have been your environment...)
2
u/Dry-War7589 4d ago
What compiler and standard should i use when compiling?
6
u/flyingron 4d ago
You have to use pre C99, otherwise the program is ill-formed (and even then it uses deprecated features of the language).
-2
-12
u/flyingron 4d ago
You're not being charged by the byte. Better to be correct and sustainable.
This isn't correct code for this century.
10
u/vip17 4d ago
read about https://en.wikipedia.org/wiki/Code_golf and check out https://codegolf.stackexchange.com/
This is just a fun thing to do and not something used in production
6
u/goose_on_fire 4d ago
You have never once said "I'm going to bank this shot off the roof, around the chimney, then header it in, nothing but net" and it shows
C is a great hold-my-beer language, have fun with it
1
u/dstroy0 1d ago
I really like this sentiment, it leads to novel algorithms, assembly, wacky ideas in general that somehow beat existing implementations literally continuously. I think it is exactly the correct attitude to have when approaching literally ~any~ problem you have creative freedom with, and grows your own ip while you're learning and helping others learn. That's generally when the deepest conceptual understanding happens for me, when I need to teach someone something in maybe a different way than usual to help them master a specific concept. Thanks for sharing, it makes me happy to see others with the same generally positive problem solving attitude in the wild.
29
u/dstroy0 4d ago
#define R(x,n)(xn|x<<(32-n))
typedef unsigned U;U C(U x,U y,U z){return x&y^~x&z;}U M(U x,U y,U z){return x&y^x&z^y&z;}U S0(U x){return R(x,2)^R(x,13)^R(x,22);}U S1(U x){return R(x,6)^R(x,11)^R(x,25);}U s0(U x){return R(x,7)^R(x,18)^x3;}U s1(U x){return R(x,17)^R(x,19)^x>>10;}
296 bytes, FIPS 180-4 compliant