Skip to content

Commit 3d0415b

Browse files
author
Tommy TIAN
authored
Modify default hash function (#15)
* Modify default hash functions. Signed-off-by: txaty <[email protected]> * Add unit tests. Signed-off-by: txaty <[email protected]>
1 parent 1b07bc8 commit 3d0415b

File tree

6 files changed

+136
-11
lines changed

6 files changed

+136
-11
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
# Test binary, built with `go test -c`
1111
*.test
1212

13+
# coverage files
14+
coverage.*
15+
1316
# Output of the go coverage tool, specifically when used with LiteIDE
1417
*.out
1518
*.html

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ func NewHashFunc(data []byte) ([]byte, error) {
5656
}
5757
```
5858

59+
*Important Notice*: please make sure the hash function used by paralleled algorithms is concurrent-safe.
60+
5961
## Example
6062

6163
### Proof generation and verification of all blocks

default_hash.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// MIT License
2+
//
3+
// Copyright (c) 2022 Tommy TIAN
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
package merkletree
24+
25+
import (
26+
"crypto/sha256"
27+
)
28+
29+
var sha256Digest = sha256.New()
30+
31+
// defaultHashFunc is used when no user hash function is specified.
32+
// It implements SHA256 hash function.
33+
func defaultHashFunc(data []byte) ([]byte, error) {
34+
defer sha256Digest.Reset()
35+
_, err := sha256Digest.Write(data)
36+
if err != nil {
37+
return nil, err
38+
}
39+
return sha256Digest.Sum(nil), nil
40+
41+
}
42+
43+
// defaultHashFuncParal is used by parallel algorithms when no user hash function is specified.
44+
// It implements SHA256 hash function.
45+
// When implementing hash functions for paralleled algorithms, please make sure it is concurrent safe.
46+
func defaultHashFuncParal(data []byte) ([]byte, error) {
47+
digest := sha256.New()
48+
_, err := digest.Write(data)
49+
if err != nil {
50+
return nil, err
51+
}
52+
return digest.Sum(nil), nil
53+
}

default_hash_test.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package merkletree
2+
3+
import (
4+
"crypto/sha256"
5+
"errors"
6+
"hash"
7+
"reflect"
8+
"testing"
9+
)
10+
11+
type mockHash struct {
12+
}
13+
14+
func NewMock() hash.Hash {
15+
return &mockHash{}
16+
}
17+
18+
func (m *mockHash) Reset() {
19+
}
20+
21+
func (m *mockHash) BlockSize() int {
22+
return 0
23+
}
24+
25+
func (m *mockHash) Size() int {
26+
return 0
27+
}
28+
29+
func (m *mockHash) Sum(in []byte) []byte {
30+
return in
31+
}
32+
33+
func (m *mockHash) Write([]byte) (nn int, err error) {
34+
return 0, errors.New("mockHash.Write error")
35+
}
36+
37+
func Test_defaultHashFunc(t *testing.T) {
38+
sha256Digest = NewMock()
39+
defer func() {
40+
sha256Digest = sha256.New()
41+
}()
42+
type args struct {
43+
data []byte
44+
}
45+
tests := []struct {
46+
name string
47+
args args
48+
want []byte
49+
wantErr bool
50+
}{
51+
{
52+
name: "test_write_err",
53+
args: args{
54+
data: []byte{},
55+
},
56+
want: nil,
57+
wantErr: true,
58+
},
59+
}
60+
for _, tt := range tests {
61+
t.Run(tt.name, func(t *testing.T) {
62+
got, err := defaultHashFunc(tt.args.data)
63+
if (err != nil) != tt.wantErr {
64+
t.Errorf("defaultHashFunc() error = %v, wantErr %v", err, tt.wantErr)
65+
return
66+
}
67+
if !reflect.DeepEqual(got, tt.want) {
68+
t.Errorf("defaultHashFunc() got = %v, want %v", got, tt.want)
69+
}
70+
})
71+
}
72+
}

merkle_tree.go

+5-10
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ package merkletree
2525
import (
2626
"bytes"
2727
"crypto/rand"
28-
"crypto/sha256"
2928
"errors"
3029
"math"
3130
"runtime"
@@ -109,7 +108,11 @@ func New(config *Config, blocks []DataBlock) (m *MerkleTree, err error) {
109108
config = new(Config)
110109
}
111110
if config.HashFunc == nil {
112-
config.HashFunc = defaultHashFunc
111+
if config.RunInParallel {
112+
config.HashFunc = defaultHashFuncParal
113+
} else {
114+
config.HashFunc = defaultHashFunc
115+
}
113116
}
114117
// If the configuration mode is not set, then set it to ModeProofGen by default.
115118
if config.Mode == 0 {
@@ -389,14 +392,6 @@ func getDummyHash() ([]byte, error) {
389392
return dummyBytes, nil
390393
}
391394

392-
// defaultHashFunc is used when no user hash function is specified.
393-
// It implements SHA256 hash function.
394-
func defaultHashFunc(data []byte) ([]byte, error) {
395-
sha256Func := sha256.New()
396-
sha256Func.Write(data)
397-
return sha256Func.Sum(nil), nil
398-
}
399-
400395
func (m *MerkleTree) leafGen(blocks []DataBlock) ([][]byte, error) {
401396
var (
402397
lenLeaves = len(blocks)

merkle_tree_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import (
3434
"github.com/agiledragon/gomonkey/v2"
3535
)
3636

37-
const benchSize = 100000
37+
const benchSize = 10000
3838

3939
type mockDataBlock struct {
4040
data []byte

0 commit comments

Comments
 (0)