Initial commit.
commit
ed04711f60
|
@ -0,0 +1,3 @@
|
|||
package keccak
|
||||
var RC = [24]uint64{0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}
|
||||
var rotc = [5][5]uint{[5]uint{0x0, 0x24, 0x3, 0x29, 0x12}, [5]uint{0x1, 0x2c, 0xa, 0x2d, 0x2}, [5]uint{0x3e, 0x6, 0x2b, 0xf, 0x3d}, [5]uint{0x1c, 0x37, 0x19, 0x15, 0x38}, [5]uint{0x1b, 0x14, 0x27, 0x8, 0xe}}
|
|
@ -0,0 +1,27 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
//Round constants
|
||||
var RC [24]uint64
|
||||
rc := uint8(1)
|
||||
for i := 0; i < 24; i++ {
|
||||
for j := 0; j <= 6; j++ {
|
||||
RC[i] |= uint64(rc&1) << (1<<uint(j) - 1)
|
||||
rc = rc<<1 ^ 0x71&uint8(int8(rc)>>7)
|
||||
}
|
||||
}
|
||||
fmt.Println("package keccak")
|
||||
fmt.Printf("var RC = %#016v\n", RC)
|
||||
|
||||
var rot [5][5]uint
|
||||
x, y := 1, 0
|
||||
for i := 0; i < 24; i++ {
|
||||
rot[x][y] = uint((i+1)*(i+2)/2)%64
|
||||
x, y = y, (2*x+3*y)%5
|
||||
}
|
||||
fmt.Printf("var rotc = %#v\n", rot)
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package keccak
|
||||
|
||||
// roundGeneric implements one round of the keccak-f[1600] permutation.
|
||||
func roundGeneric(a [5][5]uint64) [5][5]uint64 {
|
||||
a = theta(a)
|
||||
a = rho(a)
|
||||
a = pi(a)
|
||||
a = chi(a)
|
||||
// Iota
|
||||
//a[0][0] ^= RC[i]
|
||||
return a
|
||||
}
|
||||
|
||||
// Theta
|
||||
func theta(a [5][5]uint64) [5][5]uint64 {
|
||||
var c [5]uint64
|
||||
for x := range a {
|
||||
c[x] = a[x][0] ^ a[x][1] ^ a[x][2] ^ a[x][3] ^ a[x][4]
|
||||
}
|
||||
for x := range a {
|
||||
x0, x1 := (x+4)%5, (x+1)%5
|
||||
a[x][0] ^= c[x0] ^ rotl(c[x1], 1)
|
||||
a[x][1] ^= c[x0] ^ rotl(c[x1], 1)
|
||||
a[x][2] ^= c[x0] ^ rotl(c[x1], 1)
|
||||
a[x][3] ^= c[x0] ^ rotl(c[x1], 1)
|
||||
a[x][4] ^= c[x0] ^ rotl(c[x1], 1)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Rho
|
||||
func rho(a [5][5]uint64) [5][5]uint64 {
|
||||
for x := range a {
|
||||
for y := range a[0] {
|
||||
a[x][y] = rotl(a[x][y], rotc[x][y])
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Pi
|
||||
func pi(a [5][5]uint64) [5][5]uint64 {
|
||||
var b [5][5]uint64
|
||||
for x := range a {
|
||||
for y := range a[0] {
|
||||
x0 := y
|
||||
y0 := (x*2 + y*3) % 5
|
||||
b[x0][y0] = a[x][y]
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Chi
|
||||
func chi(a [5][5]uint64) [5][5]uint64 {
|
||||
for y := range a[0] {
|
||||
c := [5]uint64{a[0][y], a[1][y], a[2][y], a[3][y], a[4][y]}
|
||||
a[0][y] ^= ^c[1] & c[2]
|
||||
a[1][y] ^= ^c[2] & c[3]
|
||||
a[2][y] ^= ^c[3] & c[4]
|
||||
a[3][y] ^= ^c[4] & c[0]
|
||||
a[4][y] ^= ^c[0] & c[1]
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func rotl(a uint64, r uint) uint64 {
|
||||
return a<<r | a>>(64-r)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package keccak
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var vector = []byte{0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c,
|
||||
0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0,
|
||||
0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b,
|
||||
0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70,
|
||||
}
|
||||
|
||||
func TestKeccak(t *testing.T) {
|
||||
h := New()
|
||||
sum := h.Sum(nil)
|
||||
if !reflect.DeepEqual(sum, vector) {
|
||||
t.Errorf("\"\": want % x, got % x", vector, sum)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark256(b *testing.B) {
|
||||
var tmp [Size]byte
|
||||
h := New()
|
||||
b.SetBytes(BlockSize)
|
||||
for i := 0; i < b.N; i ++ {
|
||||
h.Sum(tmp[:])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package keccak
|
||||
|
||||
import "hash"
|
||||
|
||||
const Size = 256/8
|
||||
|
||||
const BlockSize = 1600/8 - Size*2
|
||||
|
||||
// digest implements hash.Hash
|
||||
type digest struct {
|
||||
a [5][5]uint64
|
||||
buf [BlockSize]byte
|
||||
len int
|
||||
}
|
||||
|
||||
func New() hash.Hash {
|
||||
return &digest{}
|
||||
}
|
||||
|
||||
func (d *digest) Size() int { return Size }
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Reset() {
|
||||
*d = digest{}
|
||||
}
|
||||
|
||||
func (d *digest) Write(b []byte) (int, error) {
|
||||
written := len(b)
|
||||
for len(b) > 0 {
|
||||
n := copy(d.buf[d.len:], b)
|
||||
d.len += n
|
||||
b = b[n:]
|
||||
if d.len == BlockSize {
|
||||
d.flush()
|
||||
}
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
func (d *digest) flush() {
|
||||
b := d.buf[:]
|
||||
loop:
|
||||
for y := range d.a[0] {
|
||||
for x := range d.a {
|
||||
if len(b) == 0 {
|
||||
break loop
|
||||
}
|
||||
d.a[x][y] ^= uint64(b[0]) + uint64(b[1])<<8 + uint64(b[2])<<16 + uint64(b[3])<<24 + uint64(b[4])<<32 + uint64(b[5])<<40 + uint64(b[6])<<48 + uint64(b[7])<<56
|
||||
b = b[8:]
|
||||
}
|
||||
}
|
||||
d.a = keccak(d.a)
|
||||
d.len = 0
|
||||
}
|
||||
|
||||
func keccak(a [5][5]uint64) [5][5]uint64 {
|
||||
for i := 0; i < 24; i++ {
|
||||
a = roundGeneric(a)
|
||||
a[0][0] ^= RC[i]
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (d0 *digest) Sum(b []byte) []byte {
|
||||
d := *d0
|
||||
d.buf[d.len] = 0x01
|
||||
for i := d.len+1; i < BlockSize; i++ {
|
||||
d.buf[i] = 0
|
||||
}
|
||||
d.buf[BlockSize-1] |= 0x80
|
||||
d.flush()
|
||||
|
||||
b = le64enc(b, d.a[0][0])
|
||||
b = le64enc(b, d.a[1][0])
|
||||
b = le64enc(b, d.a[2][0])
|
||||
b = le64enc(b, d.a[3][0])
|
||||
return b
|
||||
}
|
||||
|
||||
func le64enc(b []byte, x uint64) []byte {
|
||||
return append(b, byte(x), byte(x>>8), byte(x>>16), byte(x>>24), byte(x>>32), byte(x>>40), byte(x>>48), byte(x>>56))
|
||||
}
|
||||
|
||||
func (d *digest) writeByte(b byte) {
|
||||
var tmp = [1]byte{b}
|
||||
d.Write(tmp[:])
|
||||
}
|
Loading…
Reference in New Issue