Skip to content

Commit 7304bf6

Browse files
refactored hash.go. Now exposes only two hashing methods. (#58)
1 parent cbd1e15 commit 7304bf6

File tree

5 files changed

+60
-63
lines changed

5 files changed

+60
-63
lines changed

hash.go

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
package poly
22

33
import (
4-
"crypto"
54
_ "crypto/md5"
65
_ "crypto/sha1"
76
_ "crypto/sha256"
87
_ "crypto/sha512"
98
"encoding/hex"
10-
"errors"
9+
"hash"
1110
"io"
1211
"strings"
1312

1413
_ "golang.org/x/crypto/blake2b"
1514
_ "golang.org/x/crypto/blake2s"
1615
_ "golang.org/x/crypto/ripemd160"
1716
_ "golang.org/x/crypto/sha3"
18-
"lukechampine.com/blake3"
1917
)
2018

2119
// Where each hash function comes from.
@@ -89,48 +87,31 @@ func BoothLeastRotation(sequence string) int {
8987
return leastRotationIndex
9088
}
9189

92-
//RotateSequence rotates circular sequences to deterministic point.
90+
// RotateSequence rotates circular sequences to deterministic point.
9391
func RotateSequence(sequence string) string {
9492
rotationIndex := BoothLeastRotation(sequence)
9593
concatenatedSequence := sequence + sequence
9694
sequence = concatenatedSequence[rotationIndex : rotationIndex+len(sequence)]
9795
return sequence
9896
}
9997

100-
// GenericSequenceHash takes an AnnotatedSequence and a hash function and hashes it.
101-
// from https://stackoverflow.com/questions/32620290/how-to-dynamically-switch-between-hash-algorithms-in-golang <- this had a bug I had to fix! - Tim
102-
func GenericSequenceHash(annotatedSequence AnnotatedSequence, hash crypto.Hash) (string, error) {
103-
if !hash.Available() {
104-
return "", errors.New("hash unavailable")
105-
}
98+
// Hash is a method wrapper for hashing AnnotatedSequence structs.
99+
func (annotatedSequence AnnotatedSequence) Hash(hash hash.Hash) string {
106100
if annotatedSequence.Meta.Locus.Circular {
107101
annotatedSequence.Sequence.Sequence = RotateSequence(annotatedSequence.Sequence.Sequence)
108102
}
109-
h := hash.New()
110-
io.WriteString(h, strings.ToUpper(annotatedSequence.Sequence.Sequence))
111-
return hex.EncodeToString(h.Sum(nil)), nil
112-
}
113-
114-
// Hash is a method wrapper for hashing annotatedSequence structs.
115-
func (annotatedSequence AnnotatedSequence) Hash(hash crypto.Hash) string {
116-
seqHash, _ := GenericSequenceHash(annotatedSequence, hash)
103+
seqHash, _ := hashSequence(annotatedSequence.Sequence.Sequence, hash)
117104
return seqHash
118105
}
119106

120-
// Blake3SequenceHash Blake3 function doesn't use standard golang hash interface
121-
// so we couldn't use it with the generic sequence hash.
122-
func Blake3SequenceHash(annotatedSequence AnnotatedSequence) string {
123-
124-
if annotatedSequence.Meta.Locus.Circular {
125-
annotatedSequence.Sequence.Sequence = RotateSequence(annotatedSequence.Sequence.Sequence)
126-
}
127-
128-
b := blake3.Sum256([]byte(strings.ToUpper(annotatedSequence.Sequence.Sequence)))
129-
return hex.EncodeToString(b[:])
107+
// Hash is a method wrapper for hashing sequences contained in Feature structs.
108+
func (feature Feature) Hash(hash hash.Hash) string {
109+
seqHash, _ := hashSequence(feature.GetSequence(), hash)
110+
return seqHash
130111
}
131112

132-
// Blake3Hash is a method wrapper for hashing annotatedSequence structs with Blake3.
133-
func (annotatedSequence AnnotatedSequence) Blake3Hash() string {
134-
seqHash := Blake3SequenceHash(annotatedSequence)
135-
return seqHash
113+
// hashSequence takes a string and a hashing function and returns a hashed string.
114+
func hashSequence(sequence string, hash hash.Hash) (string, error) {
115+
io.WriteString(hash, strings.ToUpper(sequence))
116+
return hex.EncodeToString(hash.Sum(nil)), nil
136117
}

hash_test.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,25 @@ import (
66
"testing"
77

88
"github.com/sergi/go-diff/diffmatchpatch"
9+
"lukechampine.com/blake3"
910
)
1011

11-
func TestBlake3HashRegression(t *testing.T) {
12+
func TestHashRegression(t *testing.T) {
1213
puc19GbkBlake3Hash := "4b0616d1b3fc632e42d78521deb38b44fba95cca9fde159e01cd567fa996ceb9"
1314
puc19 := ReadGbk("data/puc19.gbk")
14-
if got := puc19.Blake3Hash(); got != puc19GbkBlake3Hash {
15-
t.Errorf("TestBlake3HashRegression has failed. Blake3 has returned %q, want %q", got, puc19GbkBlake3Hash)
15+
if got := puc19.Hash(blake3.New(32, nil)); got != puc19GbkBlake3Hash {
16+
t.Errorf("TestHashRegression has failed. Blake3 sequence hash has returned %q, want %q", got, puc19GbkBlake3Hash)
17+
}
18+
19+
// testing feature hash method
20+
ampRHash := "e2bc8192c23919ce4e2b2b03f7af644ab8b714865a429408c57d30fa57557a85"
21+
for _, feature := range puc19.Features {
22+
if feature.Attributes["label"] == "AmpR" {
23+
hash := feature.Hash(blake3.New(32, nil))
24+
if hash != ampRHash {
25+
t.Errorf("TestHashRegression has failed. Blake3 feature sequence hash has returned %q, want %q", hash, ampRHash)
26+
}
27+
}
1628
}
1729
}
1830

io.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,17 @@ type Feature struct {
112112
GbkLocationString string `json:"gbk_location_string"`
113113
Sequence string `json:"sequence"`
114114
SequenceLocation Location `json:"sequence_location"`
115+
SequenceHash string `json:"sequence_hash"`
116+
SequenceHashFunction string `json:"hash_function"`
115117
ParentAnnotatedSequence *AnnotatedSequence `json:"-"`
116118
}
117119

118120
// Sequence holds raw sequence information in an AnnotatedSequence struct.
119121
type Sequence struct {
120-
Description string `json:"description"`
121-
Hash string `json:"hash"`
122-
HashFunction string `json:"hash_function"`
123-
Sequence string `json:"sequence"`
122+
Description string `json:"description"`
123+
SequenceHash string `json:"sequence_hash"`
124+
SequenceHashFunction string `json:"hash_function"`
125+
Sequence string `json:"sequence"`
124126
// ParentAnnotatedSequence *AnnotatedSequence
125127
}
126128

poly/commands.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
"github.com/TimothyStiles/poly"
1717
"github.com/urfave/cli/v2"
18+
"lukechampine.com/blake3"
1819
)
1920

2021
/******************************************************************************
@@ -188,8 +189,8 @@ func hashCommand(c *cli.Context) error {
188189

189190
// handler for outputting JSON to stdout
190191
if c.String("o") == "json" {
191-
annotatedSequence.Sequence.Hash = sequenceHash // adding hash to JSON
192-
annotatedSequence.Sequence.HashFunction = strings.ToUpper(c.String("f")) // adding hash type to JSON
192+
annotatedSequence.Sequence.SequenceHash = sequenceHash // adding hash to JSON
193+
annotatedSequence.Sequence.SequenceHashFunction = strings.ToUpper(c.String("f")) // adding hash type to JSON
193194
output, _ := json.MarshalIndent(annotatedSequence, "", " ")
194195
fmt.Fprint(c.App.Writer, string(output))
195196
}
@@ -240,8 +241,8 @@ func hashCommand(c *cli.Context) error {
240241

241242
// handler for outputting JSON.
242243
if strings.ToLower(c.String("o")) == "json" {
243-
annotatedSequence.Sequence.Hash = sequenceHash
244-
annotatedSequence.Sequence.HashFunction = strings.ToUpper(c.String("f"))
244+
annotatedSequence.Sequence.SequenceHash = sequenceHash
245+
annotatedSequence.Sequence.SequenceHashFunction = strings.ToUpper(c.String("f"))
245246

246247
if c.Bool("--log") == true {
247248
output, _ := json.MarshalIndent(annotatedSequence, "", " ")
@@ -436,45 +437,46 @@ func flagSwitchHash(c *cli.Context, annotatedSequence poly.AnnotatedSequence) st
436437
var hashString string
437438
switch strings.ToUpper(c.String("f")) {
438439
case "MD5":
439-
hashString = annotatedSequence.Hash(crypto.MD5)
440+
hashString = annotatedSequence.Hash(crypto.MD5.New())
440441
case "SHA1":
441-
hashString = annotatedSequence.Hash(crypto.SHA1)
442+
hashString = annotatedSequence.Hash(crypto.SHA1.New())
442443
case "SHA244":
443-
hashString = annotatedSequence.Hash(crypto.SHA224)
444+
hashString = annotatedSequence.Hash(crypto.SHA224.New())
444445
case "SHA256":
445-
hashString = annotatedSequence.Hash(crypto.SHA256)
446+
hashString = annotatedSequence.Hash(crypto.SHA256.New())
446447
case "SHA384":
447-
hashString = annotatedSequence.Hash(crypto.SHA384)
448+
hashString = annotatedSequence.Hash(crypto.SHA384.New())
448449
case "SHA512":
449-
hashString = annotatedSequence.Hash(crypto.SHA512)
450+
hashString = annotatedSequence.Hash(crypto.SHA512.New())
450451
case "RIPEMD160":
451-
hashString = annotatedSequence.Hash(crypto.RIPEMD160)
452+
hashString = annotatedSequence.Hash(crypto.RIPEMD160.New())
452453
case "SHA3_224":
453-
hashString = annotatedSequence.Hash(crypto.SHA3_224)
454+
hashString = annotatedSequence.Hash(crypto.SHA3_224.New())
454455
case "SHA3_256":
455-
hashString = annotatedSequence.Hash(crypto.SHA3_256)
456+
hashString = annotatedSequence.Hash(crypto.SHA3_256.New())
456457
case "SHA3_384":
457-
hashString = annotatedSequence.Hash(crypto.SHA3_384)
458+
hashString = annotatedSequence.Hash(crypto.SHA3_384.New())
458459
case "SHA3_512":
459-
hashString = annotatedSequence.Hash(crypto.SHA3_512)
460+
hashString = annotatedSequence.Hash(crypto.SHA3_512.New())
460461
case "SHA512_224":
461-
hashString = annotatedSequence.Hash(crypto.SHA512_224)
462+
hashString = annotatedSequence.Hash(crypto.SHA512_224.New())
462463
case "SHA512_256":
463-
hashString = annotatedSequence.Hash(crypto.SHA512_256)
464+
hashString = annotatedSequence.Hash(crypto.SHA512_256.New())
464465
case "BLAKE2s_256":
465-
hashString = annotatedSequence.Hash(crypto.BLAKE2s_256)
466+
hashString = annotatedSequence.Hash(crypto.BLAKE2s_256.New())
466467
case "BLAKE2b_256":
467-
hashString = annotatedSequence.Hash(crypto.BLAKE2b_256)
468+
hashString = annotatedSequence.Hash(crypto.BLAKE2b_256.New())
468469
case "BLAKE2b_384":
469-
hashString = annotatedSequence.Hash(crypto.BLAKE2b_384)
470+
hashString = annotatedSequence.Hash(crypto.BLAKE2b_384.New())
470471
case "BLAKE2b_512":
471-
hashString = annotatedSequence.Hash(crypto.BLAKE2b_512)
472+
hashString = annotatedSequence.Hash(crypto.BLAKE2b_512.New())
472473
case "BLAKE3":
473-
hashString = annotatedSequence.Blake3Hash()
474+
hashString = annotatedSequence.Hash(blake3.New(32, nil))
475+
// hashString = annotatedSequence.Blake3Hash()
474476
case "NO":
475477
hashString = poly.RotateSequence(annotatedSequence.Sequence.Sequence)
476478
default:
477-
hashString = annotatedSequence.Blake3Hash()
479+
hashString = annotatedSequence.Hash(blake3.New(32, nil))
478480
break
479481
}
480482
return hashString

poly/commands_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func TestHashJSON(t *testing.T) {
170170
t.Fatalf("Run error: %s", err)
171171
}
172172

173-
hashOutputString := poly.ReadJSON("../data/puc19.json").Sequence.Hash
173+
hashOutputString := poly.ReadJSON("../data/puc19.json").Sequence.SequenceHash
174174
os.Remove("../data/puc19.json")
175175

176176
if hashOutputString != puc19GbkBlake3Hash {

0 commit comments

Comments
 (0)