Skip to content

Commit a41c647

Browse files
patapenka-alexeybigbes
authored andcommitted
hasher: implementation for sha1/sha256
This patch adds implementation of hasher types and interfaces for sha1 and sha256 algorithms. Closes #TNTP-4170
1 parent 6961faf commit a41c647

File tree

4 files changed

+201
-0
lines changed

4 files changed

+201
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
coverage.out
2+
/vendor/
3+

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,15 @@ coveralls-deps:
3434
@echo "Installing coveralls"
3535
@go get github.com/mattn/goveralls
3636
@go install github.com/mattn/goveralls
37+
38+
.PHONY: lint-deps
39+
lint-deps:
40+
@echo "Installing lint deps"
41+
@go install github.com/golangci/golangci-lint/v2/cmd/[email protected]
42+
43+
.PHONY: lint
44+
lint: lint-deps
45+
@echo "Running go-linter"
46+
@go mod tidy
47+
@go mod vendor
48+
@golangci-lint run --config=./.golangci.yml --modules-download-mode vendor --verbose

hasher/hasher.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Package hasher provides types and interfaces for hash calculating.
2+
package hasher
3+
4+
import (
5+
"crypto/sha1" //nolint:gosec
6+
"crypto/sha256"
7+
"errors"
8+
"fmt"
9+
"hash"
10+
)
11+
12+
// ErrDataIsNil is returned if the passed data is nil.
13+
var ErrDataIsNil = errors.New("data is nil")
14+
15+
// Hasher is the interface that storage hashers must implement.
16+
// It provides low-level operations for hash calculating.
17+
type Hasher interface {
18+
Name() string
19+
Hash(data []byte) ([]byte, error)
20+
}
21+
22+
type sha256Hasher struct {
23+
hash hash.Hash
24+
}
25+
26+
// NewSHA256Hasher creates a new sha256Hasher instance.
27+
func NewSHA256Hasher() Hasher {
28+
return &sha256Hasher{
29+
hash: sha256.New(),
30+
}
31+
}
32+
33+
// Name implements Hasher interface.
34+
func (h *sha256Hasher) Name() string {
35+
return "sha256"
36+
}
37+
38+
// Hash implements Hasher interface.
39+
func (h *sha256Hasher) Hash(data []byte) ([]byte, error) {
40+
if data == nil {
41+
return nil, ErrDataIsNil
42+
}
43+
44+
n, err := h.hash.Write(data)
45+
if n < len(data) || err != nil {
46+
return nil, fmt.Errorf("failed to write data: %w", err)
47+
}
48+
49+
return h.hash.Sum(nil), nil
50+
}
51+
52+
type sha1Hasher struct {
53+
hash hash.Hash
54+
}
55+
56+
// NewSHA1Hasher creates a new NewSHA1Hasher instance.
57+
func NewSHA1Hasher() Hasher {
58+
return &sha1Hasher{
59+
hash: sha1.New(), //nolint:gosec
60+
}
61+
}
62+
63+
// Name implements Hasher interface.
64+
func (h *sha1Hasher) Name() string {
65+
return "sha1"
66+
}
67+
68+
// Hash implements Hasher interface.
69+
func (h *sha1Hasher) Hash(data []byte) ([]byte, error) {
70+
if data == nil {
71+
return nil, ErrDataIsNil
72+
}
73+
74+
n, err := h.hash.Write(data)
75+
if n < len(data) || err != nil {
76+
return nil, fmt.Errorf("failed to write data: %w", err)
77+
}
78+
79+
return h.hash.Sum(nil), nil
80+
}

hasher/hasher_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package hasher_test
2+
3+
import (
4+
"encoding/hex"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/tarantool/go-storage/hasher"
9+
)
10+
11+
func TestSHA1Hasher(t *testing.T) {
12+
t.Parallel()
13+
14+
tests := []struct {
15+
name string
16+
in []byte
17+
out string
18+
}{
19+
{"empty", []byte(""), "da39a3ee5e6b4b0d3255bfef95601890afd80709"},
20+
{"abc", []byte("abc"), "a9993e364706816aba3e25717850c26c9cd0d89d"},
21+
}
22+
23+
for _, test := range tests {
24+
t.Run(test.name, func(t *testing.T) {
25+
t.Parallel()
26+
27+
h := hasher.NewSHA1Hasher()
28+
29+
result, _ := h.Hash(test.in)
30+
31+
assert.Equal(t, test.out, hex.EncodeToString(result))
32+
})
33+
}
34+
}
35+
36+
func TestSHA1Hasher_negative(t *testing.T) {
37+
t.Parallel()
38+
39+
tests := []struct {
40+
name string
41+
in []byte
42+
expectedErrorText string
43+
}{
44+
{"nil", nil, "data is nil"},
45+
}
46+
47+
for _, test := range tests {
48+
t.Run(test.name, func(t *testing.T) {
49+
t.Parallel()
50+
51+
h := hasher.NewSHA1Hasher()
52+
53+
_, err := h.Hash(test.in)
54+
55+
assert.Contains(t, err.Error(), test.expectedErrorText)
56+
})
57+
}
58+
}
59+
60+
func TestSHA256Hasher(t *testing.T) {
61+
t.Parallel()
62+
63+
tests := []struct {
64+
name string
65+
in []byte
66+
out string
67+
}{
68+
{"empty", []byte(""), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
69+
{"abc", []byte("abc"), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"},
70+
}
71+
72+
for _, test := range tests {
73+
t.Run(test.name, func(t *testing.T) {
74+
t.Parallel()
75+
76+
h := hasher.NewSHA256Hasher()
77+
78+
result, _ := h.Hash(test.in)
79+
80+
assert.Equal(t, test.out, hex.EncodeToString(result))
81+
})
82+
}
83+
}
84+
85+
func TestSHA256Hasher_negative(t *testing.T) {
86+
t.Parallel()
87+
88+
tests := []struct {
89+
name string
90+
in []byte
91+
expectedErrorText string
92+
}{
93+
{"nil", nil, "data is nil"},
94+
}
95+
96+
for _, test := range tests {
97+
t.Run(test.name, func(t *testing.T) {
98+
t.Parallel()
99+
100+
h := hasher.NewSHA256Hasher()
101+
102+
_, err := h.Hash(test.in)
103+
104+
assert.Contains(t, err.Error(), test.expectedErrorText)
105+
})
106+
}
107+
}

0 commit comments

Comments
 (0)