diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f312d18..941db47 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.14', '1.19', '1.20' ] + go: [ '1.20', '1.21' ] name: Go ${{ matrix.go }} test steps: - name: Set up Go 1.x @@ -30,4 +30,4 @@ jobs: run: go build -v ./... - name: Test - run: go test -v ./... \ No newline at end of file + run: go test -v ./... diff --git a/go.mod b/go.mod index be2b16f..de9cf1c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prysmaticlabs/gohashtree -go 1.17 +go 1.20 require ( github.com/klauspost/cpuid/v2 v2.0.9 diff --git a/hash.go b/hash.go index 9223c27..b9675e4 100644 --- a/hash.go +++ b/hash.go @@ -25,12 +25,13 @@ package gohashtree import ( "fmt" - "reflect" "unsafe" ) func _hash(digests *byte, p [][32]byte, count uint32) +// Hash hashes the chunks two at the time and outputs the digests on the first +// argument. It does check for lengths on the inputs. func Hash(digests [][32]byte, chunks [][32]byte) error { if len(chunks) == 0 { return nil @@ -50,8 +51,13 @@ func Hash(digests [][32]byte, chunks [][32]byte) error { return nil } +// HashChunks is the same as Hash, but does not do error checking on the lengths of the slices func HashChunks(digests [][32]byte, chunks [][32]byte) { - _hash(&digests[0][0], chunks, uint32(len(chunks)/2)) + if supportedCPU { + _hash(&digests[0][0], chunks, uint32(len(chunks)/2)) + } else { + sha256_1_generic(digests, chunks) + } } func HashByteSlice(digests []byte, chunks []byte) error { @@ -69,18 +75,14 @@ func HashByteSlice(digests []byte, chunks []byte) error { } // We use an unsafe pointer to cast []byte to [][32]byte. The length and // capacity of the slice need to be divided accordingly by 32. - header := *(*reflect.SliceHeader)(unsafe.Pointer(&chunks)) - header.Len <<= 5 - header.Cap <<= 5 - chunkedChunks := *(*[][32]byte)(unsafe.Pointer(&header)) + sizeChunks := (len(chunks) >> 5) + chunkedChunks := unsafe.Slice((*[32]byte)(unsafe.Pointer(&chunks[0])), sizeChunks) + sizeDigests := (len(digests) >> 5) + chunkedDigest := unsafe.Slice((*[32]byte)(unsafe.Pointer(&digests[0])), sizeDigests) if supportedCPU { - _hash(&digests[0], chunkedChunks, uint32(len(chunks)/64)) + Hash(chunkedDigest, chunkedChunks) } else { - headerDigest := *(*reflect.SliceHeader)(unsafe.Pointer(&digests)) - headerDigest.Len <<= 5 - headerDigest.Cap <<= 5 - chunkedDigest := *(*[][32]byte)(unsafe.Pointer(&headerDigest)) sha256_1_generic(chunkedDigest, chunkedChunks) } return nil