123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- /*
- * Minio Cloud Storage, (C) 2016 Minio, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package sha256
- import (
- "crypto/sha256"
- "encoding/binary"
- "hash"
- "runtime"
- )
- // Size - The size of a SHA256 checksum in bytes.
- const Size = 32
- // BlockSize - The blocksize of SHA256 in bytes.
- const BlockSize = 64
- const (
- chunk = BlockSize
- init0 = 0x6A09E667
- init1 = 0xBB67AE85
- init2 = 0x3C6EF372
- init3 = 0xA54FF53A
- init4 = 0x510E527F
- init5 = 0x9B05688C
- init6 = 0x1F83D9AB
- init7 = 0x5BE0CD19
- )
- // digest represents the partial evaluation of a checksum.
- type digest struct {
- h [8]uint32
- x [chunk]byte
- nx int
- len uint64
- }
- // Reset digest back to default
- func (d *digest) Reset() {
- d.h[0] = init0
- d.h[1] = init1
- d.h[2] = init2
- d.h[3] = init3
- d.h[4] = init4
- d.h[5] = init5
- d.h[6] = init6
- d.h[7] = init7
- d.nx = 0
- d.len = 0
- }
- type blockfuncType int
- const (
- blockfuncGeneric blockfuncType = iota
- blockfuncAvx512 blockfuncType = iota
- blockfuncAvx2 blockfuncType = iota
- blockfuncAvx blockfuncType = iota
- blockfuncSsse blockfuncType = iota
- blockfuncSha blockfuncType = iota
- blockfuncArm blockfuncType = iota
- )
- var blockfunc blockfuncType
- func init() {
- is386bit := runtime.GOARCH == "386"
- isARM := runtime.GOARCH == "arm"
- switch {
- case is386bit || isARM:
- blockfunc = blockfuncGeneric
- case sha && ssse3 && sse41:
- blockfunc = blockfuncSha
- case avx2:
- blockfunc = blockfuncAvx2
- case avx:
- blockfunc = blockfuncAvx
- case ssse3:
- blockfunc = blockfuncSsse
- case armSha:
- blockfunc = blockfuncArm
- default:
- blockfunc = blockfuncGeneric
- }
- }
- // New returns a new hash.Hash computing the SHA256 checksum.
- func New() hash.Hash {
- if blockfunc != blockfuncGeneric {
- d := new(digest)
- d.Reset()
- return d
- }
- // Fallback to the standard golang implementation
- // if no features were found.
- return sha256.New()
- }
- // Sum256 - single caller sha256 helper
- func Sum256(data []byte) (result [Size]byte) {
- var d digest
- d.Reset()
- d.Write(data)
- result = d.checkSum()
- return
- }
- // Return size of checksum
- func (d *digest) Size() int { return Size }
- // Return blocksize of checksum
- func (d *digest) BlockSize() int { return BlockSize }
- // Write to digest
- func (d *digest) Write(p []byte) (nn int, err error) {
- nn = len(p)
- d.len += uint64(nn)
- if d.nx > 0 {
- n := copy(d.x[d.nx:], p)
- d.nx += n
- if d.nx == chunk {
- block(d, d.x[:])
- d.nx = 0
- }
- p = p[n:]
- }
- if len(p) >= chunk {
- n := len(p) &^ (chunk - 1)
- block(d, p[:n])
- p = p[n:]
- }
- if len(p) > 0 {
- d.nx = copy(d.x[:], p)
- }
- return
- }
- // Return sha256 sum in bytes
- func (d *digest) Sum(in []byte) []byte {
- // Make a copy of d0 so that caller can keep writing and summing.
- d0 := *d
- hash := d0.checkSum()
- return append(in, hash[:]...)
- }
- // Intermediate checksum function
- func (d *digest) checkSum() (digest [Size]byte) {
- n := d.nx
- var k [64]byte
- copy(k[:], d.x[:n])
- k[n] = 0x80
- if n >= 56 {
- block(d, k[:])
- // clear block buffer - go compiles this to optimal 1x xorps + 4x movups
- // unfortunately expressing this more succinctly results in much worse code
- k[0] = 0
- k[1] = 0
- k[2] = 0
- k[3] = 0
- k[4] = 0
- k[5] = 0
- k[6] = 0
- k[7] = 0
- k[8] = 0
- k[9] = 0
- k[10] = 0
- k[11] = 0
- k[12] = 0
- k[13] = 0
- k[14] = 0
- k[15] = 0
- k[16] = 0
- k[17] = 0
- k[18] = 0
- k[19] = 0
- k[20] = 0
- k[21] = 0
- k[22] = 0
- k[23] = 0
- k[24] = 0
- k[25] = 0
- k[26] = 0
- k[27] = 0
- k[28] = 0
- k[29] = 0
- k[30] = 0
- k[31] = 0
- k[32] = 0
- k[33] = 0
- k[34] = 0
- k[35] = 0
- k[36] = 0
- k[37] = 0
- k[38] = 0
- k[39] = 0
- k[40] = 0
- k[41] = 0
- k[42] = 0
- k[43] = 0
- k[44] = 0
- k[45] = 0
- k[46] = 0
- k[47] = 0
- k[48] = 0
- k[49] = 0
- k[50] = 0
- k[51] = 0
- k[52] = 0
- k[53] = 0
- k[54] = 0
- k[55] = 0
- k[56] = 0
- k[57] = 0
- k[58] = 0
- k[59] = 0
- k[60] = 0
- k[61] = 0
- k[62] = 0
- k[63] = 0
- }
- binary.BigEndian.PutUint64(k[56:64], uint64(d.len)<<3)
- block(d, k[:])
- {
- const i = 0
- binary.BigEndian.PutUint32(digest[i*4:i*4+4], d.h[i])
- }
- {
- const i = 1
- binary.BigEndian.PutUint32(digest[i*4:i*4+4], d.h[i])
- }
- {
- const i = 2
- binary.BigEndian.PutUint32(digest[i*4:i*4+4], d.h[i])
- }
- {
- const i = 3
- binary.BigEndian.PutUint32(digest[i*4:i*4+4], d.h[i])
- }
- {
- const i = 4
- binary.BigEndian.PutUint32(digest[i*4:i*4+4], d.h[i])
- }
- {
- const i = 5
- binary.BigEndian.PutUint32(digest[i*4:i*4+4], d.h[i])
- }
- {
- const i = 6
- binary.BigEndian.PutUint32(digest[i*4:i*4+4], d.h[i])
- }
- {
- const i = 7
- binary.BigEndian.PutUint32(digest[i*4:i*4+4], d.h[i])
- }
- return
- }
- func block(dig *digest, p []byte) {
- if blockfunc == blockfuncSha {
- blockShaGo(dig, p)
- } else if blockfunc == blockfuncAvx2 {
- blockAvx2Go(dig, p)
- } else if blockfunc == blockfuncAvx {
- blockAvxGo(dig, p)
- } else if blockfunc == blockfuncSsse {
- blockSsseGo(dig, p)
- } else if blockfunc == blockfuncArm {
- blockArmGo(dig, p)
- } else if blockfunc == blockfuncGeneric {
- blockGeneric(dig, p)
- }
- }
- func blockGeneric(dig *digest, p []byte) {
- var w [64]uint32
- h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
- for len(p) >= chunk {
- // Can interlace the computation of w with the
- // rounds below if needed for speed.
- for i := 0; i < 16; i++ {
- j := i * 4
- w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
- }
- for i := 16; i < 64; i++ {
- v1 := w[i-2]
- t1 := (v1>>17 | v1<<(32-17)) ^ (v1>>19 | v1<<(32-19)) ^ (v1 >> 10)
- v2 := w[i-15]
- t2 := (v2>>7 | v2<<(32-7)) ^ (v2>>18 | v2<<(32-18)) ^ (v2 >> 3)
- w[i] = t1 + w[i-7] + t2 + w[i-16]
- }
- a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
- for i := 0; i < 64; i++ {
- t1 := h + ((e>>6 | e<<(32-6)) ^ (e>>11 | e<<(32-11)) ^ (e>>25 | e<<(32-25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
- t2 := ((a>>2 | a<<(32-2)) ^ (a>>13 | a<<(32-13)) ^ (a>>22 | a<<(32-22))) + ((a & b) ^ (a & c) ^ (b & c))
- h = g
- g = f
- f = e
- e = d + t1
- d = c
- c = b
- b = a
- a = t1 + t2
- }
- h0 += a
- h1 += b
- h2 += c
- h3 += d
- h4 += e
- h5 += f
- h6 += g
- h7 += h
- p = p[chunk:]
- }
- dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
- }
- var _K = []uint32{
- 0x428a2f98,
- 0x71374491,
- 0xb5c0fbcf,
- 0xe9b5dba5,
- 0x3956c25b,
- 0x59f111f1,
- 0x923f82a4,
- 0xab1c5ed5,
- 0xd807aa98,
- 0x12835b01,
- 0x243185be,
- 0x550c7dc3,
- 0x72be5d74,
- 0x80deb1fe,
- 0x9bdc06a7,
- 0xc19bf174,
- 0xe49b69c1,
- 0xefbe4786,
- 0x0fc19dc6,
- 0x240ca1cc,
- 0x2de92c6f,
- 0x4a7484aa,
- 0x5cb0a9dc,
- 0x76f988da,
- 0x983e5152,
- 0xa831c66d,
- 0xb00327c8,
- 0xbf597fc7,
- 0xc6e00bf3,
- 0xd5a79147,
- 0x06ca6351,
- 0x14292967,
- 0x27b70a85,
- 0x2e1b2138,
- 0x4d2c6dfc,
- 0x53380d13,
- 0x650a7354,
- 0x766a0abb,
- 0x81c2c92e,
- 0x92722c85,
- 0xa2bfe8a1,
- 0xa81a664b,
- 0xc24b8b70,
- 0xc76c51a3,
- 0xd192e819,
- 0xd6990624,
- 0xf40e3585,
- 0x106aa070,
- 0x19a4c116,
- 0x1e376c08,
- 0x2748774c,
- 0x34b0bcb5,
- 0x391c0cb3,
- 0x4ed8aa4a,
- 0x5b9cca4f,
- 0x682e6ff3,
- 0x748f82ee,
- 0x78a5636f,
- 0x84c87814,
- 0x8cc70208,
- 0x90befffa,
- 0xa4506ceb,
- 0xbef9a3f7,
- 0xc67178f2,
- }
|