]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/crypto/sha256/sha256.go
[dev.boringcrypto] all: merge master (nearly Go 1.10 beta 1) into dev.boringcrypto
[gostls13.git] / src / crypto / sha256 / sha256.go
index f386f832067865052e6d55df7469de20e28461db..a5bb144f0e2f7b4e9d87ed73131474fe92dd415f 100644 (file)
@@ -9,6 +9,7 @@ package sha256
 import (
        "crypto"
        "crypto/internal/boring"
+       "errors"
        "hash"
 )
 
@@ -55,6 +56,91 @@ type digest struct {
        is224 bool // mark if this digest is SHA-224
 }
 
+const (
+       magic224      = "sha\x02"
+       magic256      = "sha\x03"
+       marshaledSize = len(magic256) + 8*4 + chunk + 8
+)
+
+func (d *digest) MarshalBinary() ([]byte, error) {
+       b := make([]byte, 0, marshaledSize)
+       if d.is224 {
+               b = append(b, magic224...)
+       } else {
+               b = append(b, magic256...)
+       }
+       b = appendUint32(b, d.h[0])
+       b = appendUint32(b, d.h[1])
+       b = appendUint32(b, d.h[2])
+       b = appendUint32(b, d.h[3])
+       b = appendUint32(b, d.h[4])
+       b = appendUint32(b, d.h[5])
+       b = appendUint32(b, d.h[6])
+       b = appendUint32(b, d.h[7])
+       b = append(b, d.x[:]...)
+       b = appendUint64(b, d.len)
+       return b, nil
+}
+
+func (d *digest) UnmarshalBinary(b []byte) error {
+       if len(b) < len(magic224) || (d.is224 && string(b[:len(magic224)]) != magic224) || (!d.is224 && string(b[:len(magic256)]) != magic256) {
+               return errors.New("crypto/sha256: invalid hash state identifier")
+       }
+       if len(b) != marshaledSize {
+               return errors.New("crypto/sha256: invalid hash state size")
+       }
+       b = b[len(magic224):]
+       b, d.h[0] = consumeUint32(b)
+       b, d.h[1] = consumeUint32(b)
+       b, d.h[2] = consumeUint32(b)
+       b, d.h[3] = consumeUint32(b)
+       b, d.h[4] = consumeUint32(b)
+       b, d.h[5] = consumeUint32(b)
+       b, d.h[6] = consumeUint32(b)
+       b, d.h[7] = consumeUint32(b)
+       b = b[copy(d.x[:], b):]
+       b, d.len = consumeUint64(b)
+       d.nx = int(d.len) % chunk
+       return nil
+}
+
+func appendUint64(b []byte, x uint64) []byte {
+       a := [8]byte{
+               byte(x >> 56),
+               byte(x >> 48),
+               byte(x >> 40),
+               byte(x >> 32),
+               byte(x >> 24),
+               byte(x >> 16),
+               byte(x >> 8),
+               byte(x),
+       }
+       return append(b, a[:]...)
+}
+
+func appendUint32(b []byte, x uint32) []byte {
+       a := [4]byte{
+               byte(x >> 24),
+               byte(x >> 16),
+               byte(x >> 8),
+               byte(x),
+       }
+       return append(b, a[:]...)
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+       _ = b[7]
+       x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+               uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+       return b[8:], x
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+       _ = b[3]
+       x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+       return b[4:], x
+}
+
 func (d *digest) Reset() {
        if !d.is224 {
                d.h[0] = init0
@@ -79,7 +165,10 @@ func (d *digest) Reset() {
        d.len = 0
 }
 
-// New returns a new hash.Hash computing the SHA256 checksum.
+// New returns a new hash.Hash computing the SHA256 checksum. The Hash
+// also implements encoding.BinaryMarshaler and
+// encoding.BinaryUnmarshaler to marshal and unmarshal the internal
+// state of the hash.
 func New() hash.Hash {
        if boring.Enabled {
                return boring.NewSHA256()