shithub: mc

Download patch

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[:])
+		}],
+	][:])
+}