ref: fbc01b056541c245dce94569d3564fd8812ec72b
parent: 75658ff682f476ca448dc4734a1b6da0c1c4132a
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Dec 2 19:06:14 EST 2016
Add sha3 implementation.
--- a/lib/crypto/bld.sub
+++ b/lib/crypto/bld.sub
@@ -6,6 +6,7 @@
sha1.myr
sha256.myr
sha512.myr
+ sha3.myr
# ciphers
chacha20.myr
--- /dev/null
+++ b/lib/crypto/sha3.myr
@@ -1,0 +1,340 @@
+use std
+
+pkg crypto =
+ type keccak224 = struct
+ x : uint64[25]
+ tail : byte[144]
+ msglen : std.size
+ ;;
+
+ type keccak256 = struct
+ x : uint64[25]
+ tail : byte[136]
+ msglen : std.size
+ ;;
+
+ type keccak384 = struct
+ x : uint64[25]
+ tail : byte[104]
+ msglen : std.size
+ ;;
+
+ type keccak512 = struct
+ x : uint64[25]
+ tail : byte[72]
+ msglen : std.size
+ ;;
+
+ const keccak224 : (data : byte[:] -> byte[28])
+ const keccak224init : (st : keccak224# -> void)
+ const keccak224add : (st : keccak224#, data : byte[:] -> void)
+ const keccak224fin : (st : keccak224# -> byte[28])
+
+ const keccak256 : (data : byte[:] -> byte[32])
+ const keccak256init : (st : keccak256# -> void)
+ const keccak256add : (st : keccak256#, data : byte[:] -> void)
+ const keccak256fin : (st : keccak256# -> byte[32])
+
+ const keccak384 : (data : byte[:] -> byte[48])
+ const keccak384init : (st : keccak384# -> void)
+ const keccak384add : (st : keccak384#, data : byte[:] -> void)
+ const keccak384fin : (st : keccak384# -> byte[48])
+
+ const keccak512 : (data : byte[:] -> byte[64])
+ const keccak512init : (st : keccak512# -> void)
+ const keccak512add : (st : keccak512#, data : byte[:] -> void)
+ const keccak512fin : (st : keccak512# -> byte[64])
+;;
+
+const Nrounds = 24
+
+const keccak224 = {data
+ var st
+
+ keccak224init(&st)
+ keccak224add(&st, data)
+ -> keccak224fin(&st)
+}
+
+const keccak224init = {st;
+ std.slfill(st.x[:], 0)
+ st.msglen = 0
+}
+
+const keccak224add = {st, data
+ st.msglen += keccak(st.x[:], data, 144, st.tail[:], st.msglen)
+}
+
+const keccak224fin = {st
+ var ret : byte[28]
+
+ fin(st.x[:], 144, st.tail[:], st.msglen)
+ std.putle64(ret[ 0: 8], st.x[0])
+ std.putle64(ret[ 8:16], st.x[1])
+ std.putle64(ret[16:24], st.x[2])
+ std.putle32(ret[24:28], st.x[3])
+ -> ret
+}
+
+const keccak256 = {data
+ var st
+
+ keccak256init(&st)
+ keccak256add(&st, data)
+ -> keccak256fin(&st)
+}
+
+const keccak256init = {st
+ std.slfill(st.x[:], 0)
+ st.msglen = 0
+}
+
+const keccak256add = {st, data
+ st.msglen += keccak(st.x[:], data, 136, st.tail[:], st.msglen)
+}
+
+const keccak256fin = {st
+ var ret : byte[32]
+
+ fin(st.x[:], 136, st.tail[:], st.msglen)
+ std.putle64(ret[ 0: 8], st.x[0])
+ std.putle64(ret[ 8:16], st.x[1])
+ std.putle64(ret[16:24], st.x[2])
+ std.putle64(ret[24:32], st.x[3])
+ -> ret
+}
+
+const keccak384 = {data
+ var st
+
+ keccak384init(&st)
+ keccak384add(&st, data)
+ -> keccak384fin(&st)
+}
+
+const keccak384init = {st
+ std.slfill(st.x[:], 0)
+ st.msglen = 0
+}
+
+const keccak384add = {st, data
+ st.msglen += keccak(st.x[:], data, 104, st.tail[:], st.msglen)
+}
+
+const keccak384fin = {st
+ var ret : byte[48]
+
+ fin(st.x[:], 104, st.tail[:], st.msglen)
+ std.putle64(ret[ 0: 8], st.x[0])
+ std.putle64(ret[ 8:16], st.x[1])
+ std.putle64(ret[16:24], st.x[2])
+ std.putle64(ret[24:32], st.x[3])
+ std.putle64(ret[32:40], st.x[4])
+ std.putle64(ret[40:48], st.x[5])
+ -> ret
+}
+
+const keccak512init = {st
+ std.slfill(st.x[:], 0)
+ st.msglen = 0
+}
+const keccak512 = {data
+ var st
+
+ keccak512init(&st)
+ keccak512add(&st, data)
+ -> keccak512fin(&st)
+}
+
+const keccak512add = {st, data
+ st.msglen += keccak(st.x[:], data, 72, st.tail[:], st.msglen)
+}
+
+const keccak512fin = {st
+ var ret : byte[64]
+
+ fin(st.x[:], 72, st.tail[:], st.msglen)
+ std.putle64(ret[ 0: 8], st.x[0])
+ std.putle64(ret[ 8:16], st.x[1])
+ std.putle64(ret[16:24], st.x[2])
+ std.putle64(ret[24:32], st.x[3])
+ std.putle64(ret[32:40], st.x[4])
+ std.putle64(ret[40:48], st.x[5])
+ std.putle64(ret[48:56], st.x[6])
+ std.putle64(ret[56:64], st.x[7])
+ -> ret
+}
+
+const fin = {x, blocksz, tail, msgsz
+ var ntail
+
+ ntail = msgsz % blocksz
+ std.slfill(tail[ntail:], 0)
+ tail[ntail] |= 0x01 /* wat */
+ tail[tail.len - 1] |= 0x80
+ addblock(x, tail)
+ keccakf(x)
+}
+
+const keccak = {x, data, blocksz, tail, msglen
+ var n, ntail, len
+
+ len = data.len
+ /* handle tail of last block */
+ ntail = msglen % blocksz
+ if ntail > 0
+ n = std.min(blocksz - ntail, data.len)
+ std.slcp(tail[ntail:ntail + n], data[:n])
+ data = data[n:]
+ if n + ntail < blocksz
+ -> n + ntail
+ ;;
+ addblock(x, tail)
+ keccakf(x)
+ ;;
+ while data.len >= blocksz
+ addblock(x, data)
+ keccakf(x)
+ data = data[blocksz:]
+ ;;
+ std.slcp(tail[:data.len], data)
+ -> len
+}
+
+const keccakf = {x : uint64[:]
+ var bc0, bc1, bc2, bc3, bc4
+ var t0, t1, t2, t3, t4
+
+ for var round = 0; round < Nrounds; round++
+ /* theta(x) */
+ bc0 = x[0] ^ x[5] ^ x[10] ^ x[15] ^ x[20]
+ bc1 = x[1] ^ x[6] ^ x[11] ^ x[16] ^ x[21]
+ bc2 = x[2] ^ x[7] ^ x[12] ^ x[17] ^ x[22]
+ bc3 = x[3] ^ x[8] ^ x[13] ^ x[18] ^ x[23]
+ bc4 = x[4] ^ x[9] ^ x[14] ^ x[19] ^ x[24]
+
+ t0 = bc4 ^ ((bc1 << 1) | (bc1 >> 63))
+ t1 = bc0 ^ ((bc2 << 1) | (bc2 >> 63))
+ t2 = bc1 ^ ((bc3 << 1) | (bc3 >> 63))
+ t3 = bc2 ^ ((bc4 << 1) | (bc4 >> 63))
+ t4 = bc3 ^ ((bc0 << 1) | (bc0 >> 63))
+
+ x[ 0] ^= t0
+ x[ 5] ^= t0
+ x[10] ^= t0
+ x[15] ^= t0
+ x[20] ^= t0
+
+ x[ 1] ^= t1
+ x[ 6] ^= t1
+ x[11] ^= t1
+ x[16] ^= t1
+ x[21] ^= t1
+
+ x[ 2] ^= t2
+ x[ 7] ^= t2
+ x[12] ^= t2
+ x[17] ^= t2
+ x[22] ^= t2
+
+ x[ 3] ^= t3
+ x[ 8] ^= t3
+ x[13] ^= t3
+ x[18] ^= t3
+ x[23] ^= t3
+
+ x[ 4] ^= t4
+ x[ 9] ^= t4
+ x[14] ^= t4
+ x[19] ^= t4
+ x[24] ^= t4
+
+ /* rho(x) */
+
+ t0 = x[1]
+ t1 = x[10]; x[10] = ((t0 << 1) | (t0 >> 63)); t0 = t1
+ t1 = x[ 7]; x[ 7] = ((t0 << 3) | (t0 >> 61)); t0 = t1
+ t1 = x[11]; x[11] = ((t0 << 6) | (t0 >> 58)); t0 = t1
+ t1 = x[17]; x[17] = ((t0 << 10) | (t0 >> 54)); t0 = t1
+ t1 = x[18]; x[18] = ((t0 << 15) | (t0 >> 49)); t0 = t1
+ t1 = x[ 3]; x[ 3] = ((t0 << 21) | (t0 >> 43)); t0 = t1
+ t1 = x[ 5]; x[ 5] = ((t0 << 28) | (t0 >> 36)); t0 = t1
+ t1 = x[16]; x[16] = ((t0 << 36) | (t0 >> 28)); t0 = t1
+ t1 = x[ 8]; x[ 8] = ((t0 << 45) | (t0 >> 19)); t0 = t1
+ t1 = x[21]; x[21] = ((t0 << 55) | (t0 >> 9)); t0 = t1
+ t1 = x[24]; x[24] = ((t0 << 2) | (t0 >> 62)); t0 = t1
+ t1 = x[ 4]; x[ 4] = ((t0 << 14) | (t0 >> 50)); t0 = t1
+ t1 = x[15]; x[15] = ((t0 << 27) | (t0 >> 37)); t0 = t1
+ t1 = x[23]; x[23] = ((t0 << 41) | (t0 >> 23)); t0 = t1
+ t1 = x[19]; x[19] = ((t0 << 56) | (t0 >> 8)); t0 = t1
+ t1 = x[13]; x[13] = ((t0 << 8) | (t0 >> 56)); t0 = t1
+ t1 = x[12]; x[12] = ((t0 << 25) | (t0 >> 39)); t0 = t1
+ t1 = x[ 2]; x[ 2] = ((t0 << 43) | (t0 >> 21)); t0 = t1
+ t1 = x[20]; x[20] = ((t0 << 62) | (t0 >> 2)); t0 = t1
+ t1 = x[14]; x[14] = ((t0 << 18) | (t0 >> 46)); t0 = t1
+ t1 = x[22]; x[22] = ((t0 << 39) | (t0 >> 25)); t0 = t1
+ t1 = x[ 9]; x[ 9] = ((t0 << 61) | (t0 >> 3)); t0 = t1
+ t1 = x[ 6]; x[ 6] = ((t0 << 20) | (t0 >> 44)); t0 = t1
+ t1 = x[ 1]; x[ 1] = ((t0 << 44) | (t0 >> 20)); t0 = t1
+
+ /* chi */
+ for var i = 0; i < 25; i += 5
+ bc0 = x[i+0]
+ bc1 = x[i+1]
+ bc2 = x[i+2]
+ bc3 = x[i+3]
+ bc4 = x[i+4]
+ x[i+0] ^= ~bc1 & bc2
+ x[i+1] ^= ~bc2 & bc3
+ x[i+2] ^= ~bc3 & bc4
+ x[i+3] ^= ~bc4 & bc0
+ x[i+4] ^= ~bc0 & bc1
+ ;;
+
+
+ /* iota */
+ x[0] ^= rconst[round]
+ ;;
+}
+
+const addblock = {x, buf
+ x[0] ^= std.getle64(buf[ 0: 8])
+ x[1] ^= std.getle64(buf[ 8:16])
+ x[2] ^= std.getle64(buf[16:24])
+ x[3] ^= std.getle64(buf[24:32])
+ x[4] ^= std.getle64(buf[32:40])
+ x[5] ^= std.getle64(buf[40:48])
+ x[6] ^= std.getle64(buf[48:56])
+ x[7] ^= std.getle64(buf[56:64])
+ x[8] ^= std.getle64(buf[64:72])
+ if buf.len <= 72
+ -> void
+ ;;
+ x[ 9] ^= std.getle64(buf[72:80]);
+ x[10] ^= std.getle64(buf[80:88]);
+ x[11] ^= std.getle64(buf[88:96]);
+ x[12] ^= std.getle64(buf[96:104]);
+ if buf.len <= 104
+ -> void
+ ;;
+ x[13] ^= std.getle64(buf[104:112]);
+ x[14] ^= std.getle64(buf[112:120]);
+ x[15] ^= std.getle64(buf[120:128]);
+ x[16] ^= std.getle64(buf[128:136]);
+ if buf.len <= 136
+ -> void
+ ;;
+ x[17] ^= std.getle64(buf[136:144]);
+}
+
+const rconst = [
+ 0x0000000000000001ul, 0x0000000000008082ul, 0x800000000000808aul,
+ 0x8000000080008000ul, 0x000000000000808bul, 0x0000000080000001ul,
+ 0x8000000080008081ul, 0x8000000000008009ul, 0x000000000000008aul,
+ 0x0000000000000088ul, 0x0000000080008009ul, 0x000000008000000aul,
+ 0x000000008000808bul, 0x800000000000008bul, 0x8000000000008089ul,
+ 0x8000000000008003ul, 0x8000000000008002ul, 0x8000000000000080ul,
+ 0x000000000000800aul, 0x800000008000000aul, 0x8000000080008081ul,
+ 0x8000000000008080ul, 0x0000000080000001ul, 0x8000000080008008ul
+]
+
--- /dev/null
+++ b/lib/crypto/test/sha3.myr
@@ -1,0 +1,117 @@
+use std
+use crypto
+use testr
+
+const main = {
+ testr.run([
+ [.name="keccak224empty", .fn={ctx
+ var ret
+
+ ret = crypto.keccak224("")
+ testr.check(ctx, \
+ std.sleq(\
+ ret[:], \
+ "\xf7\x18\x37\x50\x2b\xa8\xe1\x08\x37\xbd\xd8\xd3\x65\xad" \
+ "\xb8\x55\x91\x89\x56\x02\xfc\x55\x2b\x48\xb7\x39\x0a\xbd"), \
+ "invalid hash result {r}", ret[:])
+ }],
+ [.name="keccak256empty", .fn={ctx
+ var ret
+
+ ret = crypto.keccak256("")
+ testr.check(ctx, \
+ std.sleq(\
+ ret[:], \
+ "\xC5\xD2\x46\x01\x86\xF7\x23\x3C\x92\x7E\x7D\xB2\xDC\xC7\x03\xC0" \
+ "\xE5\x00\xB6\x53\xCA\x82\x27\x3B\x7B\xFA\xD8\x04\x5D\x85\xA4\x70"), \
+ "invalid hash result {r}", ret[:])
+ }],
+ [.name="keccak384empty", .fn={ctx
+ var ret
+
+ ret = crypto.keccak384("")
+ testr.check(ctx, \
+ std.sleq(\
+ ret[:], \
+ "\x2C\x23\x14\x6A\x63\xA2\x9A\xCF" \
+ "\x99\xE7\x3B\x88\xF8\xC2\x4E\xAA" \
+ "\x7D\xC6\x0A\xA7\x71\x78\x0C\xCC" \
+ "\x00\x6A\xFB\xFA\x8F\xE2\x47\x9B" \
+ "\x2D\xD2\xB2\x13\x62\x33\x74\x41" \
+ "\xAC\x12\xB5\x15\x91\x19\x57\xFF"), \
+ "invalid hash result {r}", ret[:])
+ }],
+ [.name="keccak512empty", .fn={ctx
+ var ret
+
+ ret = crypto.keccak512("")
+ testr.check(ctx, \
+ std.sleq(\
+ ret[:], \
+ "\x0E\xAB\x42\xDE\x4C\x3C\xEB\x92" \
+ "\x35\xFC\x91\xAC\xFF\xE7\x46\xB2" \
+ "\x9C\x29\xA8\xC3\x66\xB7\xC6\x0E" \
+ "\x4E\x67\xC4\x66\xF3\x6A\x43\x04" \
+ "\xC0\x0F\xA9\xCA\xF9\xD8\x79\x76" \
+ "\xBA\x46\x9B\xCB\xE0\x67\x13\xB4" \
+ "\x35\xF0\x91\xEF\x27\x69\xFB\x16" \
+ "\x0C\xDA\xB3\x3D\x36\x70\x68\x0E"), \
+ "invalid hash result {r}", ret[:])
+ }],
+
+ [.name="keccak224smoke", .fn={ctx
+ var ret
+
+ ret = crypto.keccak224("Keccak-224 Test Hash")
+ testr.check(ctx, \
+ std.sleq(\
+ ret[:], \
+ "\x30\x04\x5B\x34\x94\x6E\x1B\x2E\x09\x16\x13\x36\x2F\xD2" \
+ "\x2A\xA0\x8E\x2B\xEA\xFE\xC5\xE8\xDA\xEE\x42\xC2\xE6\x65"), \
+ "invalid hash result {r}", ret[:])
+ }],
+ [.name="keccak256smoke", .fn={ctx
+ var ret
+
+ ret = crypto.keccak256("Keccak-256 Test Hash")
+ testr.check(ctx, \
+ std.sleq(\
+ ret[:], \
+ "\xA8\xD7\x1B\x07\xF4\xAF\x26\xA4\xFF\x21\x02\x7F\x62\xFF\x60\x26" \
+ "\x7F\xF9\x55\xC9\x63\xF0\x42\xC4\x6D\xA5\x2E\xE3\xCF\xAF\x3D\x3C"), \
+ "invalid hash result {r}", ret[:])
+ }],
+ [.name="keccak384smoke", .fn={ctx
+ var ret
+
+ ret = crypto.keccak384("Keccak-384 Test Hash")
+ testr.check(ctx, \
+ std.sleq(\
+ ret[:], \
+ "\xE2\x13\xFD\x74\xAF\x0C\x5F\xF9" \
+ "\x1B\x42\x3C\x8B\xCE\xEC\xD7\x01" \
+ "\xF8\xDD\x64\xEC\x18\xFD\x6F\x92" \
+ "\x60\xFC\x9E\xC1\xED\xBD\x22\x30" \
+ "\xA6\x90\x86\x65\xBC\xD9\xFB\xF4" \
+ "\x1A\x99\xA1\x8A\x7D\x9E\x44\x6E"), \
+ "invalid hash result {r}", ret[:])
+ }],
+ [.name="keccak512smoke", .fn={ctx
+ var ret
+
+ ret = crypto.keccak512("Keccak-512 Test Hash")
+ testr.check(ctx, \
+ std.sleq(\
+ ret[:], \
+ "\x96\xEE\x47\x18\xDC\xBA\x3C\x74" \
+ "\x61\x9B\xA1\xFA\x7F\x57\xDF\xE7" \
+ "\x76\x9D\x3F\x66\x98\xA8\xB3\x3F" \
+ "\xA1\x01\x83\x89\x70\xA1\x31\xE6" \
+ "\x21\xCC\xFD\x05\xFE\xFF\xBC\x11" \
+ "\x80\xF2\x63\xC2\x7F\x1A\xDA\xB4" \
+ "\x60\x95\xD6\xF1\x25\x33\x14\x72" \
+ "\x4B\x5C\xBF\x78\x28\x65\x8E\x6A"), \
+ "invalid hash result {r}", ret[:])
+ }],
+ ][:])
+}