166 lines
3.4 KiB
Go
166 lines
3.4 KiB
Go
package hash
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"testing"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func Test_Sum(t *testing.T) {
|
|
var (
|
|
data = []byte("Hello world")
|
|
sum = Sum(data)
|
|
hash = []byte{0, 0, 0, 0, 1, 79, 16, 173, 134, 90, 176, 77, 114, 165, 253, 114, 0, 0, 0, 0, 0, 148,
|
|
172, 222, 98, 248, 15, 99, 205, 129, 66, 91, 0, 0, 0, 0, 0, 138, 173, 39, 228, 231, 239, 123,
|
|
170, 96, 186, 61, 0, 0, 0, 0, 0, 90, 69, 237, 131, 90, 161, 73, 38, 164, 185, 55}
|
|
)
|
|
|
|
require.Equal(t, hash, sum.Bytes())
|
|
}
|
|
|
|
func Test_Validate(t *testing.T) {
|
|
var (
|
|
data = []byte("Hello world")
|
|
hash = Sum(data)
|
|
pieces = splitData(data, 2)
|
|
ln = len(pieces)
|
|
hashes = make([]Hash, 0, ln)
|
|
)
|
|
|
|
for i := 0; i < ln; i++ {
|
|
hashes = append(hashes, Sum(pieces[i]))
|
|
}
|
|
|
|
require.True(t, hash.Validate(hashes))
|
|
}
|
|
|
|
func Test_Concat(t *testing.T) {
|
|
var (
|
|
data = []byte("Hello world")
|
|
hash = Sum(data)
|
|
pieces = splitData(data, 2)
|
|
ln = len(pieces)
|
|
hashes = make([]Hash, 0, ln)
|
|
)
|
|
|
|
for i := 0; i < ln; i++ {
|
|
hashes = append(hashes, Sum(pieces[i]))
|
|
}
|
|
|
|
res, err := Concat(hashes)
|
|
require.NoError(t, err)
|
|
require.Equal(t, hash, res)
|
|
}
|
|
|
|
func Test_HashChunks(t *testing.T) {
|
|
var (
|
|
chars = []byte("+")
|
|
size = 1400
|
|
data = bytes.Repeat(chars, size)
|
|
hash = Sum(data)
|
|
count = 150
|
|
)
|
|
|
|
hashes, err := dataHashes(data, count)
|
|
require.NoError(t, err)
|
|
require.Len(t, hashes, count)
|
|
|
|
require.True(t, hash.Validate(hashes))
|
|
|
|
// 100 / 150 = 0
|
|
hashes, err = dataHashes(data[:100], count)
|
|
require.Error(t, err)
|
|
require.Nil(t, hashes)
|
|
}
|
|
|
|
func TestXOR(t *testing.T) {
|
|
var (
|
|
dl = 10
|
|
data = make([]byte, dl)
|
|
)
|
|
|
|
_, err := rand.Read(data)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("XOR with <nil> salt", func(t *testing.T) {
|
|
res := SaltXOR(data, nil)
|
|
require.Equal(t, res, data)
|
|
})
|
|
|
|
t.Run("XOR with empty salt", func(t *testing.T) {
|
|
xorWithSalt(t, data, 0)
|
|
})
|
|
|
|
t.Run("XOR with salt same data size", func(t *testing.T) {
|
|
xorWithSalt(t, data, dl)
|
|
})
|
|
|
|
t.Run("XOR with salt shorter than data aliquot", func(t *testing.T) {
|
|
xorWithSalt(t, data, dl/2)
|
|
})
|
|
|
|
t.Run("XOR with salt shorter than data aliquant", func(t *testing.T) {
|
|
xorWithSalt(t, data, dl/3/+1)
|
|
})
|
|
|
|
t.Run("XOR with salt longer than data aliquot", func(t *testing.T) {
|
|
xorWithSalt(t, data, dl*2)
|
|
})
|
|
|
|
t.Run("XOR with salt longer than data aliquant", func(t *testing.T) {
|
|
xorWithSalt(t, data, dl*2-1)
|
|
})
|
|
}
|
|
|
|
func xorWithSalt(t *testing.T, data []byte, saltSize int) {
|
|
var (
|
|
direct, reverse []byte
|
|
salt = make([]byte, saltSize)
|
|
)
|
|
|
|
_, err := rand.Read(salt)
|
|
require.NoError(t, err)
|
|
|
|
direct = SaltXOR(data, salt)
|
|
require.Len(t, direct, len(data))
|
|
|
|
reverse = SaltXOR(direct, salt)
|
|
require.Len(t, reverse, len(data))
|
|
|
|
require.Equal(t, reverse, data)
|
|
}
|
|
|
|
func splitData(buf []byte, lim int) [][]byte {
|
|
var piece []byte
|
|
pieces := make([][]byte, 0, len(buf)/lim+1)
|
|
for len(buf) >= lim {
|
|
piece, buf = buf[:lim], buf[lim:]
|
|
pieces = append(pieces, piece)
|
|
}
|
|
if len(buf) > 0 {
|
|
pieces = append(pieces, buf)
|
|
}
|
|
return pieces
|
|
}
|
|
|
|
func dataHashes(data []byte, count int) ([]Hash, error) {
|
|
var (
|
|
ln = len(data)
|
|
mis = ln / count
|
|
off = (count - 1) * mis
|
|
hashes = make([]Hash, 0, count)
|
|
)
|
|
if mis == 0 {
|
|
return nil, errors.Errorf("could not split %d bytes to %d pieces", ln, count)
|
|
}
|
|
|
|
pieces := splitData(data[:off], mis)
|
|
pieces = append(pieces, data[off:])
|
|
for i := 0; i < count; i++ {
|
|
hashes = append(hashes, Sum(pieces[i]))
|
|
}
|
|
return hashes, nil
|
|
}
|