// Copyright 2017-2018 DERO Project. All rights reserved.
|
|
// Use of this source code in any form is governed by RESEARCH license.
|
|
// license can be found in the LICENSE file.
|
|
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
|
|
//
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
// TODO keccak is available in 3 of our packages we need to merge them when the alpha version is out
|
|
// Package keccak implements the Keccak (SHA-3) hash algorithm.
|
|
// http://keccak.noekeon.org / FIPS 202 draft.
|
|
package cryptonight
|
|
|
|
// import "fmt"
|
|
import "hash"
|
|
|
|
const (
|
|
domainNone = 1
|
|
domainSHA3 = 0x06
|
|
domainSHAKE = 0x1f
|
|
)
|
|
|
|
const rounds = 24
|
|
|
|
var roundConstants = []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,
|
|
}
|
|
|
|
type keccak struct {
|
|
S [25]uint64
|
|
size int
|
|
blockSize int
|
|
buf []byte
|
|
domain byte
|
|
}
|
|
|
|
func newKeccak(capacity, output int, domain byte) hash.Hash {
|
|
var h keccak
|
|
h.size = output / 8
|
|
h.blockSize = (200 - capacity/8)
|
|
h.domain = domain
|
|
return &h
|
|
}
|
|
|
|
func New224() hash.Hash {
|
|
return newKeccak(224*2, 224, domainNone)
|
|
}
|
|
|
|
func New256() hash.Hash {
|
|
return newKeccak(256*2, 256, domainNone)
|
|
}
|
|
|
|
func New384() hash.Hash {
|
|
return newKeccak(384*2, 384, domainNone)
|
|
}
|
|
|
|
func New512() hash.Hash {
|
|
return newKeccak(512*2, 512, domainNone)
|
|
}
|
|
|
|
func (k *keccak) Write(b []byte) (int, error) {
|
|
n := len(b)
|
|
|
|
if len(k.buf) > 0 {
|
|
x := k.blockSize - len(k.buf)
|
|
if x > len(b) {
|
|
x = len(b)
|
|
}
|
|
k.buf = append(k.buf, b[:x]...)
|
|
b = b[x:]
|
|
|
|
if len(k.buf) < k.blockSize {
|
|
return n, nil
|
|
}
|
|
|
|
k.absorb(k.buf)
|
|
k.buf = nil
|
|
}
|
|
|
|
for len(b) >= k.blockSize {
|
|
k.absorb(b[:k.blockSize])
|
|
b = b[k.blockSize:]
|
|
}
|
|
|
|
k.buf = b
|
|
|
|
return n, nil
|
|
}
|
|
|
|
func (k0 *keccak) Sum(b []byte) []byte {
|
|
k := *k0
|
|
k.final()
|
|
return k.squeeze(b)
|
|
}
|
|
|
|
func (k *keccak) Reset() {
|
|
for i := range k.S {
|
|
k.S[i] = 0
|
|
}
|
|
k.buf = nil
|
|
}
|
|
|
|
func (k *keccak) Size() int {
|
|
return k.size
|
|
}
|
|
|
|
func (k *keccak) BlockSize() int {
|
|
return k.blockSize
|
|
}
|
|
|
|
func (k *keccak) absorb(block []byte) {
|
|
if len(block) != k.blockSize {
|
|
panic("absorb() called with invalid block size")
|
|
}
|
|
|
|
for i := 0; i < k.blockSize/8; i++ {
|
|
k.S[i] ^= uint64le(block[i*8:])
|
|
}
|
|
keccakf(&k.S)
|
|
}
|
|
|
|
func (k *keccak) pad(block []byte) []byte {
|
|
|
|
padded := make([]byte, k.blockSize)
|
|
|
|
copy(padded, k.buf)
|
|
padded[len(k.buf)] = k.domain
|
|
padded[len(padded)-1] |= 0x80
|
|
|
|
return padded
|
|
}
|
|
|
|
func (k *keccak) final() {
|
|
last := k.pad(k.buf)
|
|
k.absorb(last)
|
|
}
|
|
|
|
func (k *keccak) squeeze(b []byte) []byte {
|
|
buf := make([]byte, 8*len(k.S))
|
|
n := k.size
|
|
for {
|
|
for i := range k.S {
|
|
putUint64le(buf[i*8:], k.S[i])
|
|
}
|
|
if n <= k.blockSize {
|
|
b = append(b, buf[:n]...)
|
|
break
|
|
}
|
|
b = append(b, buf[:k.blockSize]...)
|
|
n -= k.blockSize
|
|
keccakf(&k.S)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func keccakf(S *[25]uint64) {
|
|
var bc0, bc1, bc2, bc3, bc4 uint64
|
|
var S0, S1, S2, S3, S4 uint64
|
|
var S5, S6, S7, S8, S9 uint64
|
|
var S10, S11, S12, S13, S14 uint64
|
|
var S15, S16, S17, S18, S19 uint64
|
|
var S20, S21, S22, S23, S24 uint64
|
|
var tmp uint64
|
|
|
|
//S[0]=0x2073692073696854;
|
|
//S[1]=0x1747365742061
|
|
// S[16]=0x8000000000000000;
|
|
|
|
/* for i :=0; i< 25;i++{
|
|
fmt.Printf("%2d %X\n", i, S[i])
|
|
}
|
|
*/
|
|
|
|
S0, S1, S2, S3, S4 = S[0], S[1], S[2], S[3], S[4]
|
|
S5, S6, S7, S8, S9 = S[5], S[6], S[7], S[8], S[9]
|
|
S10, S11, S12, S13, S14 = S[10], S[11], S[12], S[13], S[14]
|
|
S15, S16, S17, S18, S19 = S[15], S[16], S[17], S[18], S[19]
|
|
S20, S21, S22, S23, S24 = S[20], S[21], S[22], S[23], S[24]
|
|
|
|
for r := 0; r < rounds; r++ {
|
|
// theta
|
|
bc0 = S0 ^ S5 ^ S10 ^ S15 ^ S20
|
|
bc1 = S1 ^ S6 ^ S11 ^ S16 ^ S21
|
|
bc2 = S2 ^ S7 ^ S12 ^ S17 ^ S22
|
|
bc3 = S3 ^ S8 ^ S13 ^ S18 ^ S23
|
|
bc4 = S4 ^ S9 ^ S14 ^ S19 ^ S24
|
|
tmp = bc4 ^ (bc1<<1 | bc1>>(64-1))
|
|
S0 ^= tmp
|
|
S5 ^= tmp
|
|
S10 ^= tmp
|
|
S15 ^= tmp
|
|
S20 ^= tmp
|
|
tmp = bc0 ^ (bc2<<1 | bc2>>(64-1))
|
|
S1 ^= tmp
|
|
S6 ^= tmp
|
|
S11 ^= tmp
|
|
S16 ^= tmp
|
|
S21 ^= tmp
|
|
tmp = bc1 ^ (bc3<<1 | bc3>>(64-1))
|
|
S2 ^= tmp
|
|
S7 ^= tmp
|
|
S12 ^= tmp
|
|
S17 ^= tmp
|
|
S22 ^= tmp
|
|
tmp = bc2 ^ (bc4<<1 | bc4>>(64-1))
|
|
S3 ^= tmp
|
|
S8 ^= tmp
|
|
S13 ^= tmp
|
|
S18 ^= tmp
|
|
S23 ^= tmp
|
|
tmp = bc3 ^ (bc0<<1 | bc0>>(64-1))
|
|
S4 ^= tmp
|
|
S9 ^= tmp
|
|
S14 ^= tmp
|
|
S19 ^= tmp
|
|
S24 ^= tmp
|
|
|
|
// rho phi
|
|
tmp = S1
|
|
tmp, S10 = S10, tmp<<1|tmp>>(64-1)
|
|
tmp, S7 = S7, tmp<<3|tmp>>(64-3)
|
|
tmp, S11 = S11, tmp<<6|tmp>>(64-6)
|
|
tmp, S17 = S17, tmp<<10|tmp>>(64-10)
|
|
tmp, S18 = S18, tmp<<15|tmp>>(64-15)
|
|
tmp, S3 = S3, tmp<<21|tmp>>(64-21)
|
|
tmp, S5 = S5, tmp<<28|tmp>>(64-28)
|
|
tmp, S16 = S16, tmp<<36|tmp>>(64-36)
|
|
tmp, S8 = S8, tmp<<45|tmp>>(64-45)
|
|
tmp, S21 = S21, tmp<<55|tmp>>(64-55)
|
|
tmp, S24 = S24, tmp<<2|tmp>>(64-2)
|
|
tmp, S4 = S4, tmp<<14|tmp>>(64-14)
|
|
tmp, S15 = S15, tmp<<27|tmp>>(64-27)
|
|
tmp, S23 = S23, tmp<<41|tmp>>(64-41)
|
|
tmp, S19 = S19, tmp<<56|tmp>>(64-56)
|
|
tmp, S13 = S13, tmp<<8|tmp>>(64-8)
|
|
tmp, S12 = S12, tmp<<25|tmp>>(64-25)
|
|
tmp, S2 = S2, tmp<<43|tmp>>(64-43)
|
|
tmp, S20 = S20, tmp<<62|tmp>>(64-62)
|
|
tmp, S14 = S14, tmp<<18|tmp>>(64-18)
|
|
tmp, S22 = S22, tmp<<39|tmp>>(64-39)
|
|
tmp, S9 = S9, tmp<<61|tmp>>(64-61)
|
|
tmp, S6 = S6, tmp<<20|tmp>>(64-20)
|
|
S1 = tmp<<44 | tmp>>(64-44)
|
|
|
|
// chi
|
|
bc0 = S0
|
|
bc1 = S1
|
|
bc2 = S2
|
|
bc3 = S3
|
|
bc4 = S4
|
|
S0 ^= (^bc1) & bc2
|
|
S1 ^= (^bc2) & bc3
|
|
S2 ^= (^bc3) & bc4
|
|
S3 ^= (^bc4) & bc0
|
|
S4 ^= (^bc0) & bc1
|
|
bc0 = S5
|
|
bc1 = S6
|
|
bc2 = S7
|
|
bc3 = S8
|
|
bc4 = S9
|
|
S5 ^= (^bc1) & bc2
|
|
S6 ^= (^bc2) & bc3
|
|
S7 ^= (^bc3) & bc4
|
|
S8 ^= (^bc4) & bc0
|
|
S9 ^= (^bc0) & bc1
|
|
bc0 = S10
|
|
bc1 = S11
|
|
bc2 = S12
|
|
bc3 = S13
|
|
bc4 = S14
|
|
S10 ^= (^bc1) & bc2
|
|
S11 ^= (^bc2) & bc3
|
|
S12 ^= (^bc3) & bc4
|
|
S13 ^= (^bc4) & bc0
|
|
S14 ^= (^bc0) & bc1
|
|
bc0 = S15
|
|
bc1 = S16
|
|
bc2 = S17
|
|
bc3 = S18
|
|
bc4 = S19
|
|
S15 ^= (^bc1) & bc2
|
|
S16 ^= (^bc2) & bc3
|
|
S17 ^= (^bc3) & bc4
|
|
S18 ^= (^bc4) & bc0
|
|
S19 ^= (^bc0) & bc1
|
|
bc0 = S20
|
|
bc1 = S21
|
|
bc2 = S22
|
|
bc3 = S23
|
|
bc4 = S24
|
|
S20 ^= (^bc1) & bc2
|
|
S21 ^= (^bc2) & bc3
|
|
S22 ^= (^bc3) & bc4
|
|
S23 ^= (^bc4) & bc0
|
|
S24 ^= (^bc0) & bc1
|
|
|
|
// iota
|
|
S0 ^= roundConstants[r]
|
|
}
|
|
|
|
S[0], S[1], S[2], S[3], S[4] = S0, S1, S2, S3, S4
|
|
S[5], S[6], S[7], S[8], S[9] = S5, S6, S7, S8, S9
|
|
S[10], S[11], S[12], S[13], S[14] = S10, S11, S12, S13, S14
|
|
S[15], S[16], S[17], S[18], S[19] = S15, S16, S17, S18, S19
|
|
S[20], S[21], S[22], S[23], S[24] = S20, S21, S22, S23, S24
|
|
|
|
}
|
|
|
|
func uint64le(v []byte) uint64 {
|
|
return uint64(v[0]) |
|
|
uint64(v[1])<<8 |
|
|
uint64(v[2])<<16 |
|
|
uint64(v[3])<<24 |
|
|
uint64(v[4])<<32 |
|
|
uint64(v[5])<<40 |
|
|
uint64(v[6])<<48 |
|
|
uint64(v[7])<<56
|
|
|
|
}
|
|
|
|
func putUint64le(v []byte, x uint64) {
|
|
v[0] = byte(x)
|
|
v[1] = byte(x >> 8)
|
|
v[2] = byte(x >> 16)
|
|
v[3] = byte(x >> 24)
|
|
v[4] = byte(x >> 32)
|
|
v[5] = byte(x >> 40)
|
|
v[6] = byte(x >> 48)
|
|
v[7] = byte(x >> 56)
|
|
}
|