shithub: mc

ref: a54d7deb4b5cdc397f1e5cf3957edc0b91f5f880
dir: /lib/crypto/sha3.myr/

View raw version
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
]