// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package shavite
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"gitlab.com/nitya-sattva/go-x11/aesr"
|
|
"gitlab.com/nitya-sattva/go-x11/hash"
|
|
)
|
|
|
|
// HashSize holds the size of a hash in bytes.
|
|
const HashSize = int(64)
|
|
|
|
// BlockSize holds the size of a block in bytes.
|
|
const BlockSize = uintptr(128)
|
|
|
|
////////////////
|
|
|
|
type digest struct {
|
|
ptr uintptr
|
|
|
|
h [16]uint32
|
|
c [4]uint32
|
|
|
|
b [BlockSize]byte
|
|
}
|
|
|
|
// New returns a new digest to compute a SHAVITE512 hash.
|
|
func New() hash.Digest {
|
|
ref := &digest{}
|
|
ref.Reset()
|
|
return ref
|
|
}
|
|
|
|
////////////////
|
|
|
|
// Reset resets the digest to its initial state.
|
|
func (ref *digest) Reset() {
|
|
ref.ptr = 0
|
|
copy(ref.h[:], kInit[:])
|
|
ref.c[0], ref.c[1] = 0, 0
|
|
ref.c[2], ref.c[3] = 0, 0
|
|
}
|
|
|
|
// Sum appends the current hash to dst and returns the result
|
|
// as a slice. It does not change the underlying hash state.
|
|
func (ref *digest) Sum(dst []byte) []byte {
|
|
dgt := *ref
|
|
hsh := [64]byte{}
|
|
dgt.Close(hsh[:], 0, 0)
|
|
return append(dst, hsh[:]...)
|
|
}
|
|
|
|
// Write more data to the running hash, never returns an error.
|
|
func (ref *digest) Write(src []byte) (int, error) {
|
|
sln := uintptr(len(src))
|
|
fln := len(src)
|
|
ptr := ref.ptr
|
|
|
|
for sln > 0 {
|
|
cln := BlockSize - ptr
|
|
|
|
if cln > sln {
|
|
cln = sln
|
|
}
|
|
sln -= cln
|
|
|
|
copy(ref.b[ptr:], src[:cln])
|
|
src = src[cln:]
|
|
ptr += cln
|
|
|
|
if ptr == BlockSize {
|
|
ref.c[0] += 1024
|
|
if ref.c[0] == 0 {
|
|
ref.c[1] += 1
|
|
if ref.c[1] == 0 {
|
|
ref.c[2] += 1
|
|
if ref.c[2] == 0 {
|
|
ref.c[3] += 1
|
|
}
|
|
}
|
|
}
|
|
|
|
ref.compress()
|
|
ptr = 0
|
|
}
|
|
}
|
|
|
|
ref.ptr = ptr
|
|
return fln, nil
|
|
}
|
|
|
|
// Close the digest by writing the last bits and storing the hash
|
|
// in dst. This prepares the digest for reuse by calling reset. A call
|
|
// to Close with a dst that is smaller then HashSize will return an error.
|
|
func (ref *digest) Close(dst []byte, bits uint8, bcnt uint8) error {
|
|
if ln := len(dst); HashSize > ln {
|
|
return fmt.Errorf("Shavite Close: dst min length: %d, got %d", HashSize, ln)
|
|
}
|
|
|
|
var cnt [4]uint32
|
|
|
|
ptr := ref.ptr
|
|
buf := ref.b[:]
|
|
|
|
ref.c[0] += uint32(ptr<<3) + uint32(bcnt)
|
|
cnt[0] = ref.c[0]
|
|
cnt[1] = ref.c[1]
|
|
cnt[2] = ref.c[2]
|
|
cnt[3] = ref.c[3]
|
|
|
|
z := uint8(0x80) >> bcnt
|
|
z = uint8((bits & -z) | z)
|
|
|
|
if (ptr == 0) && (bcnt == 0) {
|
|
buf[0] = 0x80
|
|
memset(buf[1:110], 0)
|
|
ref.c[0], ref.c[1] = 0, 0
|
|
ref.c[2], ref.c[3] = 0, 0
|
|
} else if ptr < 110 {
|
|
buf[ptr] = z
|
|
ptr += 1
|
|
memset(buf[ptr:(ptr+(110-ptr))], 0)
|
|
} else {
|
|
buf[ptr] = z
|
|
ptr += 1
|
|
memset(buf[ptr:(ptr+(128-ptr))], 0)
|
|
|
|
ref.compress()
|
|
memset(buf[:], 0)
|
|
ref.c[0], ref.c[1] = 0, 0
|
|
ref.c[2], ref.c[3] = 0, 0
|
|
}
|
|
|
|
encUInt32le(buf[110:], cnt[0])
|
|
encUInt32le(buf[114:], cnt[1])
|
|
encUInt32le(buf[118:], cnt[2])
|
|
encUInt32le(buf[122:], cnt[3])
|
|
|
|
buf[126] = 0
|
|
buf[127] = 2
|
|
|
|
ref.compress()
|
|
|
|
for u := uintptr(0); u < 16; u++ {
|
|
encUInt32le(dst[(u<<2):], ref.h[u])
|
|
}
|
|
|
|
ref.Reset()
|
|
return nil
|
|
}
|
|
|
|
// Size returns the number of bytes required to store the hash.
|
|
func (*digest) Size() int {
|
|
return HashSize
|
|
}
|
|
|
|
// BlockSize returns the block size of the hash.
|
|
func (*digest) BlockSize() int {
|
|
return int(BlockSize)
|
|
}
|
|
|
|
////////////////
|
|
|
|
func memset(dst []byte, src byte) {
|
|
for i := range dst {
|
|
dst[i] = src
|
|
}
|
|
}
|
|
|
|
func decUInt32le(src []byte) uint32 {
|
|
return (uint32(src[0]) |
|
|
uint32(src[1])<<8 |
|
|
uint32(src[2])<<16 |
|
|
uint32(src[3])<<24)
|
|
}
|
|
|
|
func encUInt32le(dst []uint8, src uint32) {
|
|
dst[0] = uint8(src)
|
|
dst[1] = uint8(src >> 8)
|
|
dst[2] = uint8(src >> 16)
|
|
dst[3] = uint8(src >> 24)
|
|
}
|
|
|
|
func (ref *digest) compress() {
|
|
var p0, p1, p2, p3, p4, p5, p6, p7 uint32
|
|
var p8, p9, pA, pB, pC, pD, pE, pF uint32
|
|
var t0, t1, t2, t3 uint32
|
|
var rk [448]uint32
|
|
|
|
for i := uintptr(0); i < 32; i++ {
|
|
rk[i] = decUInt32le(ref.b[(i * 4):])
|
|
//rk[i] = decUInt32be(ref.b[(i * 4):])
|
|
}
|
|
|
|
idx := uintptr(32)
|
|
for idx < 448 {
|
|
for s := uintptr(0); s < 4; s++ {
|
|
t0 = rk[idx-31]
|
|
t1 = rk[idx-30]
|
|
t2 = rk[idx-29]
|
|
t3 = rk[idx-32]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
rk[idx+0] = t0 ^ rk[idx-4]
|
|
rk[idx+1] = t1 ^ rk[idx-3]
|
|
rk[idx+2] = t2 ^ rk[idx-2]
|
|
rk[idx+3] = t3 ^ rk[idx-1]
|
|
if idx == 32 {
|
|
rk[32] ^= ref.c[0]
|
|
rk[33] ^= ref.c[1]
|
|
rk[34] ^= ref.c[2]
|
|
rk[35] ^= uint32(^ref.c[3])
|
|
} else if idx == 440 {
|
|
rk[440] ^= ref.c[1]
|
|
rk[441] ^= ref.c[0]
|
|
rk[442] ^= ref.c[3]
|
|
rk[443] ^= uint32(^ref.c[2])
|
|
}
|
|
idx += 4
|
|
|
|
t0 = rk[idx-31]
|
|
t1 = rk[idx-30]
|
|
t2 = rk[idx-29]
|
|
t3 = rk[idx-32]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
rk[idx+0] = t0 ^ rk[idx-4]
|
|
rk[idx+1] = t1 ^ rk[idx-3]
|
|
rk[idx+2] = t2 ^ rk[idx-2]
|
|
rk[idx+3] = t3 ^ rk[idx-1]
|
|
if idx == 164 {
|
|
rk[164] ^= ref.c[3]
|
|
rk[165] ^= ref.c[2]
|
|
rk[166] ^= ref.c[1]
|
|
rk[167] ^= uint32(^ref.c[0])
|
|
} else if idx == 316 {
|
|
rk[316] ^= ref.c[2]
|
|
rk[317] ^= ref.c[3]
|
|
rk[318] ^= ref.c[0]
|
|
rk[319] ^= uint32(^ref.c[1])
|
|
}
|
|
idx += 4
|
|
}
|
|
|
|
if idx != 448 {
|
|
for s := uintptr(0); s < 8; s++ {
|
|
rk[idx+0] = rk[idx-32] ^ rk[idx-7]
|
|
rk[idx+1] = rk[idx-31] ^ rk[idx-6]
|
|
rk[idx+2] = rk[idx-30] ^ rk[idx-5]
|
|
rk[idx+3] = rk[idx-29] ^ rk[idx-4]
|
|
idx += 4
|
|
}
|
|
}
|
|
}
|
|
|
|
p0 = ref.h[0x0]
|
|
p1 = ref.h[0x1]
|
|
p2 = ref.h[0x2]
|
|
p3 = ref.h[0x3]
|
|
p4 = ref.h[0x4]
|
|
p5 = ref.h[0x5]
|
|
p6 = ref.h[0x6]
|
|
p7 = ref.h[0x7]
|
|
p8 = ref.h[0x8]
|
|
p9 = ref.h[0x9]
|
|
pA = ref.h[0xA]
|
|
pB = ref.h[0xB]
|
|
pC = ref.h[0xC]
|
|
pD = ref.h[0xD]
|
|
pE = ref.h[0xE]
|
|
pF = ref.h[0xF]
|
|
|
|
idx = 0
|
|
for r := uint32(0); r < 14; r++ {
|
|
t0 = p4 ^ rk[idx+0]
|
|
t1 = p5 ^ rk[idx+1]
|
|
t2 = p6 ^ rk[idx+2]
|
|
t3 = p7 ^ rk[idx+3]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
t0 ^= rk[idx+4]
|
|
t1 ^= rk[idx+5]
|
|
t2 ^= rk[idx+6]
|
|
t3 ^= rk[idx+7]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
t0 ^= rk[idx+8]
|
|
t1 ^= rk[idx+9]
|
|
t2 ^= rk[idx+10]
|
|
t3 ^= rk[idx+11]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
t0 ^= rk[idx+12]
|
|
t1 ^= rk[idx+13]
|
|
t2 ^= rk[idx+14]
|
|
t3 ^= rk[idx+15]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
p0 ^= t0
|
|
p1 ^= t1
|
|
p2 ^= t2
|
|
p3 ^= t3
|
|
|
|
idx += 16
|
|
|
|
t0 = pC ^ rk[idx+0]
|
|
t1 = pD ^ rk[idx+1]
|
|
t2 = pE ^ rk[idx+2]
|
|
t3 = pF ^ rk[idx+3]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
t0 ^= rk[idx+4]
|
|
t1 ^= rk[idx+5]
|
|
t2 ^= rk[idx+6]
|
|
t3 ^= rk[idx+7]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
t0 ^= rk[idx+8]
|
|
t1 ^= rk[idx+9]
|
|
t2 ^= rk[idx+10]
|
|
t3 ^= rk[idx+11]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
t0 ^= rk[idx+12]
|
|
t1 ^= rk[idx+13]
|
|
t2 ^= rk[idx+14]
|
|
t3 ^= rk[idx+15]
|
|
t0, t1, t2, t3 = aesr.Round32sle(t0, t1, t2, t3)
|
|
p8 ^= t0
|
|
p9 ^= t1
|
|
pA ^= t2
|
|
pB ^= t3
|
|
|
|
idx += 16
|
|
|
|
t0 = pC
|
|
pC = p8
|
|
p8 = p4
|
|
p4 = p0
|
|
p0 = t0
|
|
|
|
t0 = pD
|
|
pD = p9
|
|
p9 = p5
|
|
p5 = p1
|
|
p1 = t0
|
|
|
|
t0 = pE
|
|
pE = pA
|
|
pA = p6
|
|
p6 = p2
|
|
p2 = t0
|
|
|
|
t0 = pF
|
|
pF = pB
|
|
pB = p7
|
|
p7 = p3
|
|
p3 = t0
|
|
}
|
|
|
|
ref.h[0x0] ^= p0
|
|
ref.h[0x1] ^= p1
|
|
ref.h[0x2] ^= p2
|
|
ref.h[0x3] ^= p3
|
|
ref.h[0x4] ^= p4
|
|
ref.h[0x5] ^= p5
|
|
ref.h[0x6] ^= p6
|
|
ref.h[0x7] ^= p7
|
|
ref.h[0x8] ^= p8
|
|
ref.h[0x9] ^= p9
|
|
ref.h[0xA] ^= pA
|
|
ref.h[0xB] ^= pB
|
|
ref.h[0xC] ^= pC
|
|
ref.h[0xD] ^= pD
|
|
ref.h[0xE] ^= pE
|
|
ref.h[0xF] ^= pF
|
|
}
|
|
|
|
////////////////
|
|
|
|
var kInit = [16]uint32{
|
|
uint32(0x72FCCDD8), uint32(0x79CA4727),
|
|
uint32(0x128A077B), uint32(0x40D55AEC),
|
|
uint32(0xD1901A06), uint32(0x430AE307),
|
|
uint32(0xB29F5CD1), uint32(0xDF07FBFC),
|
|
uint32(0x8E45D73D), uint32(0x681AB538),
|
|
uint32(0xBDE86578), uint32(0xDD577E47),
|
|
uint32(0xE275EADE), uint32(0x502D9FCD),
|
|
uint32(0xB9357178), uint32(0x022A4B9A),
|
|
}
|