summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/md5
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/md5')
-rw-r--r--libgo/go/crypto/md5/gen.go195
-rw-r--r--libgo/go/crypto/md5/md5.go100
-rw-r--r--libgo/go/crypto/md5/md5_test.go58
-rw-r--r--libgo/go/crypto/md5/md5block.go347
-rw-r--r--libgo/go/crypto/md5/md5block_decl.go4
-rw-r--r--libgo/go/crypto/md5/md5block_generic.go4
6 files changed, 273 insertions, 435 deletions
diff --git a/libgo/go/crypto/md5/gen.go b/libgo/go/crypto/md5/gen.go
index a815dc29f6a..a11f22059fa 100644
--- a/libgo/go/crypto/md5/gen.go
+++ b/libgo/go/crypto/md5/gen.go
@@ -7,10 +7,7 @@
// This program generates md5block.go
// Invoke as
//
-// go run gen.go [-full] -output md5block.go
-//
-// The -full flag causes the generated code to do a full
-// (16x) unrolling instead of a 4x unrolling.
+// go run gen.go -output md5block.go
package main
@@ -56,13 +53,14 @@ type Data struct {
Table2 []uint32
Table3 []uint32
Table4 []uint32
- Full bool
}
var funcs = template.FuncMap{
"dup": dup,
"relabel": relabel,
"rotate": rotate,
+ "idx": idx,
+ "seq": seq,
}
func dup(count int, x []int) []int {
@@ -74,7 +72,7 @@ func dup(count int, x []int) []int {
}
func relabel(s string) string {
- return strings.NewReplacer("a", data.a, "b", data.b, "c", data.c, "d", data.d).Replace(s)
+ return strings.NewReplacer("arg0", data.a, "arg1", data.b, "arg2", data.c, "arg3", data.d).Replace(s)
}
func rotate() string {
@@ -82,8 +80,27 @@ func rotate() string {
return "" // no output
}
-func init() {
- flag.BoolVar(&data.Full, "full", false, "complete unrolling")
+func idx(round, index int) int {
+ v := 0
+ switch round {
+ case 1:
+ v = index
+ case 2:
+ v = (1 + 5*index) & 15
+ case 3:
+ v = (5 + 3*index) & 15
+ case 4:
+ v = (7 * index) & 15
+ }
+ return v
+}
+
+func seq(i int) []int {
+ s := make([]int, i)
+ for i := range s {
+ s[i] = i
+ }
+ return s
}
var data = Data{
@@ -179,152 +196,64 @@ var program = `// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Code generated by go run gen.go{{if .Full}} -full{{end}} -output md5block.go; DO NOT EDIT.
+// Code generated by go run gen.go -output md5block.go; DO NOT EDIT.
package md5
import (
- "unsafe"
- "runtime"
+ "encoding/binary"
+ "math/bits"
)
-{{if not .Full}}
- var t1 = [...]uint32{
- {{range .Table1}}{{printf "\t%#x,\n" .}}{{end}}
- }
-
- var t2 = [...]uint32{
- {{range .Table2}}{{printf "\t%#x,\n" .}}{{end}}
- }
-
- var t3 = [...]uint32{
- {{range .Table3}}{{printf "\t%#x,\n" .}}{{end}}
- }
-
- var t4 = [...]uint32{
- {{range .Table4}}{{printf "\t%#x,\n" .}}{{end}}
- }
-{{end}}
-
-const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
-
-var littleEndian bool
+func blockGeneric(dig *digest, p []byte) {
+ // load state
+ a, b, c, d := dig.s[0], dig.s[1], dig.s[2], dig.s[3]
-func init() {
- x := uint32(0x04030201)
- y := [4]byte{0x1, 0x2, 0x3, 0x4}
- littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
-}
+ for i := 0; i <= len(p)-BlockSize; i += BlockSize {
+ // eliminate bounds checks on p
+ q := p[i:]
+ q = q[:BlockSize:BlockSize]
-func blockGeneric(dig *digest, p []byte) {
- a := dig.s[0]
- b := dig.s[1]
- c := dig.s[2]
- d := dig.s[3]
- var X *[16]uint32
- var xbuf [16]uint32
- for len(p) >= chunk {
+ // save current state
aa, bb, cc, dd := a, b, c, d
- // This is a constant condition - it is not evaluated on each iteration.
- if x86 {
- // MD5 was designed so that x86 processors can just iterate
- // over the block data directly as uint32s, and we generate
- // less code and run 1.3x faster if we take advantage of that.
- // My apologies.
- X = (*[16]uint32)(unsafe.Pointer(&p[0]))
- } else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
- X = (*[16]uint32)(unsafe.Pointer(&p[0]))
- } else {
- X = &xbuf
- j := 0
- for i := 0; i < 16; i++ {
- X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
- j += 4
- }
- }
+ // load input block
+ {{range $i := seq 16 -}}
+ {{printf "x%x := binary.LittleEndian.Uint32(q[4*%#x:])" $i $i}}
+ {{end}}
- {{if .Full}}
- // Round 1.
- {{range $i, $s := dup 4 .Shift1}}
- {{index $.Table1 $i | printf "a += (((c^d)&b)^d) + X[%d] + %d" $i | relabel}}
- {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
- {{rotate}}
- {{end}}
-
- // Round 2.
- {{range $i, $s := dup 4 .Shift2}}
- {{index $.Table2 $i | printf "a += (((b^c)&d)^c) + X[(1+5*%d)&15] + %d" $i | relabel}}
- {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
- {{rotate}}
- {{end}}
-
- // Round 3.
- {{range $i, $s := dup 4 .Shift3}}
- {{index $.Table3 $i | printf "a += (b^c^d) + X[(5+3*%d)&15] + %d" $i | relabel}}
- {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
- {{rotate}}
- {{end}}
-
- // Round 4.
- {{range $i, $s := dup 4 .Shift4}}
- {{index $.Table4 $i | printf "a += (c^(b|^d)) + X[(7*%d)&15] + %d" $i | relabel}}
- {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
- {{rotate}}
- {{end}}
- {{else}}
- // Round 1.
- for i := uint(0); i < 16; {
- {{range $s := .Shift1}}
- {{printf "a += (((c^d)&b)^d) + X[i&15] + t1[i&15]" | relabel}}
- {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
- i++
- {{rotate}}
- {{end}}
- }
+ // round 1
+ {{range $i, $s := dup 4 .Shift1 -}}
+ {{printf "arg0 = arg1 + bits.RotateLeft32((((arg2^arg3)&arg1)^arg3)+arg0+x%x+%#08x, %d)" (idx 1 $i) (index $.Table1 $i) $s | relabel}}
+ {{rotate -}}
+ {{end}}
- // Round 2.
- for i := uint(0); i < 16; {
- {{range $s := .Shift2}}
- {{printf "a += (((b^c)&d)^c) + X[(1+5*i)&15] + t2[i&15]" | relabel}}
- {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
- i++
- {{rotate}}
- {{end}}
- }
+ // round 2
+ {{range $i, $s := dup 4 .Shift2 -}}
+ {{printf "arg0 = arg1 + bits.RotateLeft32((((arg1^arg2)&arg3)^arg2)+arg0+x%x+%#08x, %d)" (idx 2 $i) (index $.Table2 $i) $s | relabel}}
+ {{rotate -}}
+ {{end}}
- // Round 3.
- for i := uint(0); i < 16; {
- {{range $s := .Shift3}}
- {{printf "a += (b^c^d) + X[(5+3*i)&15] + t3[i&15]" | relabel}}
- {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
- i++
- {{rotate}}
- {{end}}
- }
+ // round 3
+ {{range $i, $s := dup 4 .Shift3 -}}
+ {{printf "arg0 = arg1 + bits.RotateLeft32((arg1^arg2^arg3)+arg0+x%x+%#08x, %d)" (idx 3 $i) (index $.Table3 $i) $s | relabel}}
+ {{rotate -}}
+ {{end}}
- // Round 4.
- for i := uint(0); i < 16; {
- {{range $s := .Shift4}}
- {{printf "a += (c^(b|^d)) + X[(7*i)&15] + t4[i&15]" | relabel}}
- {{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}}
- i++
- {{rotate}}
- {{end}}
- }
+ // round 4
+ {{range $i, $s := dup 4 .Shift4 -}}
+ {{printf "arg0 = arg1 + bits.RotateLeft32((arg2^(arg1|^arg3))+arg0+x%x+%#08x, %d)" (idx 4 $i) (index $.Table4 $i) $s | relabel}}
+ {{rotate -}}
{{end}}
+ // add saved state
a += aa
b += bb
c += cc
d += dd
-
- p = p[chunk:]
}
- dig.s[0] = a
- dig.s[1] = b
- dig.s[2] = c
- dig.s[3] = d
+ // save state
+ dig.s[0], dig.s[1], dig.s[2], dig.s[3] = a, b, c, d
}
`
diff --git a/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go
index 88d914d22ce..01157840475 100644
--- a/libgo/go/crypto/md5/md5.go
+++ b/libgo/go/crypto/md5/md5.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:generate go run gen.go -full -output md5block.go
+//go:generate go run gen.go -output md5block.go
// Package md5 implements the MD5 hash algorithm as defined in RFC 1321.
//
@@ -12,6 +12,7 @@ package md5
import (
"crypto"
+ "encoding/binary"
"errors"
"hash"
)
@@ -27,7 +28,6 @@ const Size = 16
const BlockSize = 64
const (
- chunk = 64
init0 = 0x67452301
init1 = 0xEFCDAB89
init2 = 0x98BADCFE
@@ -37,7 +37,7 @@ const (
// digest represents the partial evaluation of a checksum.
type digest struct {
s [4]uint32
- x [chunk]byte
+ x [BlockSize]byte
nx int
len uint64
}
@@ -53,7 +53,7 @@ func (d *digest) Reset() {
const (
magic = "md5\x01"
- marshaledSize = len(magic) + 4*4 + chunk + 8
+ marshaledSize = len(magic) + 4*4 + BlockSize + 8
)
func (d *digest) MarshalBinary() ([]byte, error) {
@@ -83,45 +83,28 @@ func (d *digest) UnmarshalBinary(b []byte) error {
b, d.s[3] = consumeUint32(b)
b = b[copy(d.x[:], b):]
b, d.len = consumeUint64(b)
- d.nx = int(d.len) % chunk
+ d.nx = int(d.len % BlockSize)
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),
- }
+ var a [8]byte
+ binary.BigEndian.PutUint64(a[:], 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),
- }
+ var a [4]byte
+ binary.BigEndian.PutUint32(a[:], 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
+ return b[8:], binary.BigEndian.Uint64(b[0:8])
}
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
+ return b[4:], binary.BigEndian.Uint32(b[0:4])
}
// New returns a new hash.Hash computing the MD5 checksum. The Hash also
@@ -138,20 +121,31 @@ func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) {
+ // Note that we currently call block or blockGeneric
+ // directly (guarded using haveAsm) because this allows
+ // escape analysis to see that p and d don't escape.
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[:])
+ if d.nx == BlockSize {
+ if haveAsm {
+ block(d, d.x[:])
+ } else {
+ blockGeneric(d, d.x[:])
+ }
d.nx = 0
}
p = p[n:]
}
- if len(p) >= chunk {
- n := len(p) &^ (chunk - 1)
- block(d, p[:n])
+ if len(p) >= BlockSize {
+ n := len(p) &^ (BlockSize - 1)
+ if haveAsm {
+ block(d, p[:n])
+ } else {
+ blockGeneric(d, p[:n])
+ }
p = p[n:]
}
if len(p) > 0 {
@@ -168,35 +162,27 @@ func (d *digest) Sum(in []byte) []byte {
}
func (d *digest) checkSum() [Size]byte {
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
- len := d.len
- var tmp [64]byte
- tmp[0] = 0x80
- if len%64 < 56 {
- d.Write(tmp[0 : 56-len%64])
- } else {
- d.Write(tmp[0 : 64+56-len%64])
- }
-
- // Length in bits.
- len <<= 3
- for i := uint(0); i < 8; i++ {
- tmp[i] = byte(len >> (8 * i))
- }
- d.Write(tmp[0:8])
-
+ // Append 0x80 to the end of the message and then append zeros
+ // until the length is a multiple of 56 bytes. Finally append
+ // 8 bytes representing the message length in bits.
+ //
+ // 1 byte end marker :: 0-63 padding bytes :: 8 byte length
+ tmp := [1 + 63 + 8]byte{0x80}
+ pad := (55 - d.len) % 64 // calculate number of padding bytes
+ binary.LittleEndian.PutUint64(tmp[1+pad:], d.len<<3) // append length in bits
+ d.Write(tmp[:1+pad+8])
+
+ // The previous write ensures that a whole number of
+ // blocks (i.e. a multiple of 64 bytes) have been hashed.
if d.nx != 0 {
panic("d.nx != 0")
}
var digest [Size]byte
- for i, s := range d.s {
- digest[i*4] = byte(s)
- digest[i*4+1] = byte(s >> 8)
- digest[i*4+2] = byte(s >> 16)
- digest[i*4+3] = byte(s >> 24)
- }
-
+ binary.LittleEndian.PutUint32(digest[0:], d.s[0])
+ binary.LittleEndian.PutUint32(digest[4:], d.s[1])
+ binary.LittleEndian.PutUint32(digest[8:], d.s[2])
+ binary.LittleEndian.PutUint32(digest[12:], d.s[3])
return digest
}
diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go
index 64a62e47305..34c7f541c57 100644
--- a/libgo/go/crypto/md5/md5_test.go
+++ b/libgo/go/crypto/md5/md5_test.go
@@ -9,6 +9,7 @@ import (
"crypto/rand"
"encoding"
"fmt"
+ "hash"
"io"
"testing"
"unsafe"
@@ -153,6 +154,63 @@ func TestBlockGeneric(t *testing.T) {
}
}
+// Tests for unmarshaling hashes that have hashed a large amount of data
+// The initial hash generation is omitted from the test, because it takes a long time.
+// The test contains some already-generated states, and their expected sums
+// Tests a problem that is outlined in Github issue #29541
+// The problem is triggered when an amount of data has been hashed for which
+// the data length has a 1 in the 32nd bit. When casted to int, this changes
+// the sign of the value, and causes the modulus operation to return a
+// different result.
+type unmarshalTest struct {
+ state string
+ sum string
+}
+
+var largeUnmarshalTests = []unmarshalTest{
+ // Data length: 7_102_415_735
+ unmarshalTest{
+ state: "md5\x01\xa5\xf7\xf0=\xd6S\x85\xd9M\n}\xc3\u0601\x89\xe7@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xa7VCw",
+ sum: "cddefcf74ffec709a0b45a6a987564d5",
+ },
+ // Data length: 6_565_544_823
+ unmarshalTest{
+ state: "md5\x01{\xda\x1a\xc7\xc9'?\x83EX\xe0\x88q\xfeG\x18@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x87VCw",
+ sum: "fd9f41874ab240698e7bc9c3ae70c8e4",
+ },
+}
+
+func safeSum(h hash.Hash) (sum []byte, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("sum panic: %v", r)
+ }
+ }()
+
+ return h.Sum(nil), nil
+}
+
+func TestLargeHashes(t *testing.T) {
+ for i, test := range largeUnmarshalTests {
+
+ h := New()
+ if err := h.(encoding.BinaryUnmarshaler).UnmarshalBinary([]byte(test.state)); err != nil {
+ t.Errorf("test %d could not unmarshal: %v", i, err)
+ continue
+ }
+
+ sum, err := safeSum(h)
+ if err != nil {
+ t.Errorf("test %d could not sum: %v", i, err)
+ continue
+ }
+
+ if fmt.Sprintf("%x", sum) != test.sum {
+ t.Errorf("test %d sum mismatch: expect %s got %x", i, test.sum, sum)
+ }
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192+1)
var sum = make([]byte, bench.Size())
diff --git a/libgo/go/crypto/md5/md5block.go b/libgo/go/crypto/md5/md5block.go
index 8ac32ffeb78..4ff289e860f 100644
--- a/libgo/go/crypto/md5/md5block.go
+++ b/libgo/go/crypto/md5/md5block.go
@@ -2,263 +2,124 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Code generated by go run gen.go -full -output md5block.go; DO NOT EDIT.
+// Code generated by go run gen.go -output md5block.go; DO NOT EDIT.
package md5
import (
- "runtime"
- "unsafe"
+ "encoding/binary"
+ "math/bits"
)
-const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
-
-var littleEndian bool
-
-func init() {
- x := uint32(0x04030201)
- y := [4]byte{0x1, 0x2, 0x3, 0x4}
- littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
-}
-
func blockGeneric(dig *digest, p []byte) {
- a := dig.s[0]
- b := dig.s[1]
- c := dig.s[2]
- d := dig.s[3]
- var X *[16]uint32
- var xbuf [16]uint32
- for len(p) >= chunk {
- aa, bb, cc, dd := a, b, c, d
-
- // This is a constant condition - it is not evaluated on each iteration.
- if x86 {
- // MD5 was designed so that x86 processors can just iterate
- // over the block data directly as uint32s, and we generate
- // less code and run 1.3x faster if we take advantage of that.
- // My apologies.
- X = (*[16]uint32)(unsafe.Pointer(&p[0]))
- } else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
- X = (*[16]uint32)(unsafe.Pointer(&p[0]))
- } else {
- X = &xbuf
- j := 0
- for i := 0; i < 16; i++ {
- X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
- j += 4
- }
- }
-
- // Round 1.
-
- a += (((c ^ d) & b) ^ d) + X[0] + 3614090360
- a = a<<7 | a>>(32-7) + b
-
- d += (((b ^ c) & a) ^ c) + X[1] + 3905402710
- d = d<<12 | d>>(32-12) + a
-
- c += (((a ^ b) & d) ^ b) + X[2] + 606105819
- c = c<<17 | c>>(32-17) + d
-
- b += (((d ^ a) & c) ^ a) + X[3] + 3250441966
- b = b<<22 | b>>(32-22) + c
-
- a += (((c ^ d) & b) ^ d) + X[4] + 4118548399
- a = a<<7 | a>>(32-7) + b
-
- d += (((b ^ c) & a) ^ c) + X[5] + 1200080426
- d = d<<12 | d>>(32-12) + a
-
- c += (((a ^ b) & d) ^ b) + X[6] + 2821735955
- c = c<<17 | c>>(32-17) + d
-
- b += (((d ^ a) & c) ^ a) + X[7] + 4249261313
- b = b<<22 | b>>(32-22) + c
-
- a += (((c ^ d) & b) ^ d) + X[8] + 1770035416
- a = a<<7 | a>>(32-7) + b
-
- d += (((b ^ c) & a) ^ c) + X[9] + 2336552879
- d = d<<12 | d>>(32-12) + a
-
- c += (((a ^ b) & d) ^ b) + X[10] + 4294925233
- c = c<<17 | c>>(32-17) + d
-
- b += (((d ^ a) & c) ^ a) + X[11] + 2304563134
- b = b<<22 | b>>(32-22) + c
-
- a += (((c ^ d) & b) ^ d) + X[12] + 1804603682
- a = a<<7 | a>>(32-7) + b
-
- d += (((b ^ c) & a) ^ c) + X[13] + 4254626195
- d = d<<12 | d>>(32-12) + a
-
- c += (((a ^ b) & d) ^ b) + X[14] + 2792965006
- c = c<<17 | c>>(32-17) + d
-
- b += (((d ^ a) & c) ^ a) + X[15] + 1236535329
- b = b<<22 | b>>(32-22) + c
-
- // Round 2.
-
- a += (((b ^ c) & d) ^ c) + X[(1+5*0)&15] + 4129170786
- a = a<<5 | a>>(32-5) + b
-
- d += (((a ^ b) & c) ^ b) + X[(1+5*1)&15] + 3225465664
- d = d<<9 | d>>(32-9) + a
-
- c += (((d ^ a) & b) ^ a) + X[(1+5*2)&15] + 643717713
- c = c<<14 | c>>(32-14) + d
-
- b += (((c ^ d) & a) ^ d) + X[(1+5*3)&15] + 3921069994
- b = b<<20 | b>>(32-20) + c
-
- a += (((b ^ c) & d) ^ c) + X[(1+5*4)&15] + 3593408605
- a = a<<5 | a>>(32-5) + b
-
- d += (((a ^ b) & c) ^ b) + X[(1+5*5)&15] + 38016083
- d = d<<9 | d>>(32-9) + a
-
- c += (((d ^ a) & b) ^ a) + X[(1+5*6)&15] + 3634488961
- c = c<<14 | c>>(32-14) + d
-
- b += (((c ^ d) & a) ^ d) + X[(1+5*7)&15] + 3889429448
- b = b<<20 | b>>(32-20) + c
-
- a += (((b ^ c) & d) ^ c) + X[(1+5*8)&15] + 568446438
- a = a<<5 | a>>(32-5) + b
-
- d += (((a ^ b) & c) ^ b) + X[(1+5*9)&15] + 3275163606
- d = d<<9 | d>>(32-9) + a
-
- c += (((d ^ a) & b) ^ a) + X[(1+5*10)&15] + 4107603335
- c = c<<14 | c>>(32-14) + d
-
- b += (((c ^ d) & a) ^ d) + X[(1+5*11)&15] + 1163531501
- b = b<<20 | b>>(32-20) + c
-
- a += (((b ^ c) & d) ^ c) + X[(1+5*12)&15] + 2850285829
- a = a<<5 | a>>(32-5) + b
+ // load state
+ a, b, c, d := dig.s[0], dig.s[1], dig.s[2], dig.s[3]
- d += (((a ^ b) & c) ^ b) + X[(1+5*13)&15] + 4243563512
- d = d<<9 | d>>(32-9) + a
+ for i := 0; i <= len(p)-BlockSize; i += BlockSize {
+ // eliminate bounds checks on p
+ q := p[i:]
+ q = q[:BlockSize:BlockSize]
- c += (((d ^ a) & b) ^ a) + X[(1+5*14)&15] + 1735328473
- c = c<<14 | c>>(32-14) + d
-
- b += (((c ^ d) & a) ^ d) + X[(1+5*15)&15] + 2368359562
- b = b<<20 | b>>(32-20) + c
-
- // Round 3.
-
- a += (b ^ c ^ d) + X[(5+3*0)&15] + 4294588738
- a = a<<4 | a>>(32-4) + b
-
- d += (a ^ b ^ c) + X[(5+3*1)&15] + 2272392833
- d = d<<11 | d>>(32-11) + a
-
- c += (d ^ a ^ b) + X[(5+3*2)&15] + 1839030562
- c = c<<16 | c>>(32-16) + d
-
- b += (c ^ d ^ a) + X[(5+3*3)&15] + 4259657740
- b = b<<23 | b>>(32-23) + c
-
- a += (b ^ c ^ d) + X[(5+3*4)&15] + 2763975236
- a = a<<4 | a>>(32-4) + b
-
- d += (a ^ b ^ c) + X[(5+3*5)&15] + 1272893353
- d = d<<11 | d>>(32-11) + a
-
- c += (d ^ a ^ b) + X[(5+3*6)&15] + 4139469664
- c = c<<16 | c>>(32-16) + d
-
- b += (c ^ d ^ a) + X[(5+3*7)&15] + 3200236656
- b = b<<23 | b>>(32-23) + c
-
- a += (b ^ c ^ d) + X[(5+3*8)&15] + 681279174
- a = a<<4 | a>>(32-4) + b
-
- d += (a ^ b ^ c) + X[(5+3*9)&15] + 3936430074
- d = d<<11 | d>>(32-11) + a
-
- c += (d ^ a ^ b) + X[(5+3*10)&15] + 3572445317
- c = c<<16 | c>>(32-16) + d
-
- b += (c ^ d ^ a) + X[(5+3*11)&15] + 76029189
- b = b<<23 | b>>(32-23) + c
-
- a += (b ^ c ^ d) + X[(5+3*12)&15] + 3654602809
- a = a<<4 | a>>(32-4) + b
-
- d += (a ^ b ^ c) + X[(5+3*13)&15] + 3873151461
- d = d<<11 | d>>(32-11) + a
-
- c += (d ^ a ^ b) + X[(5+3*14)&15] + 530742520
- c = c<<16 | c>>(32-16) + d
-
- b += (c ^ d ^ a) + X[(5+3*15)&15] + 3299628645
- b = b<<23 | b>>(32-23) + c
-
- // Round 4.
-
- a += (c ^ (b | ^d)) + X[(7*0)&15] + 4096336452
- a = a<<6 | a>>(32-6) + b
-
- d += (b ^ (a | ^c)) + X[(7*1)&15] + 1126891415
- d = d<<10 | d>>(32-10) + a
-
- c += (a ^ (d | ^b)) + X[(7*2)&15] + 2878612391
- c = c<<15 | c>>(32-15) + d
-
- b += (d ^ (c | ^a)) + X[(7*3)&15] + 4237533241
- b = b<<21 | b>>(32-21) + c
-
- a += (c ^ (b | ^d)) + X[(7*4)&15] + 1700485571
- a = a<<6 | a>>(32-6) + b
-
- d += (b ^ (a | ^c)) + X[(7*5)&15] + 2399980690
- d = d<<10 | d>>(32-10) + a
-
- c += (a ^ (d | ^b)) + X[(7*6)&15] + 4293915773
- c = c<<15 | c>>(32-15) + d
-
- b += (d ^ (c | ^a)) + X[(7*7)&15] + 2240044497
- b = b<<21 | b>>(32-21) + c
-
- a += (c ^ (b | ^d)) + X[(7*8)&15] + 1873313359
- a = a<<6 | a>>(32-6) + b
-
- d += (b ^ (a | ^c)) + X[(7*9)&15] + 4264355552
- d = d<<10 | d>>(32-10) + a
-
- c += (a ^ (d | ^b)) + X[(7*10)&15] + 2734768916
- c = c<<15 | c>>(32-15) + d
-
- b += (d ^ (c | ^a)) + X[(7*11)&15] + 1309151649
- b = b<<21 | b>>(32-21) + c
-
- a += (c ^ (b | ^d)) + X[(7*12)&15] + 4149444226
- a = a<<6 | a>>(32-6) + b
-
- d += (b ^ (a | ^c)) + X[(7*13)&15] + 3174756917
- d = d<<10 | d>>(32-10) + a
-
- c += (a ^ (d | ^b)) + X[(7*14)&15] + 718787259
- c = c<<15 | c>>(32-15) + d
-
- b += (d ^ (c | ^a)) + X[(7*15)&15] + 3951481745
- b = b<<21 | b>>(32-21) + c
+ // save current state
+ aa, bb, cc, dd := a, b, c, d
+ // load input block
+ x0 := binary.LittleEndian.Uint32(q[4*0x0:])
+ x1 := binary.LittleEndian.Uint32(q[4*0x1:])
+ x2 := binary.LittleEndian.Uint32(q[4*0x2:])
+ x3 := binary.LittleEndian.Uint32(q[4*0x3:])
+ x4 := binary.LittleEndian.Uint32(q[4*0x4:])
+ x5 := binary.LittleEndian.Uint32(q[4*0x5:])
+ x6 := binary.LittleEndian.Uint32(q[4*0x6:])
+ x7 := binary.LittleEndian.Uint32(q[4*0x7:])
+ x8 := binary.LittleEndian.Uint32(q[4*0x8:])
+ x9 := binary.LittleEndian.Uint32(q[4*0x9:])
+ xa := binary.LittleEndian.Uint32(q[4*0xa:])
+ xb := binary.LittleEndian.Uint32(q[4*0xb:])
+ xc := binary.LittleEndian.Uint32(q[4*0xc:])
+ xd := binary.LittleEndian.Uint32(q[4*0xd:])
+ xe := binary.LittleEndian.Uint32(q[4*0xe:])
+ xf := binary.LittleEndian.Uint32(q[4*0xf:])
+
+ // round 1
+ a = b + bits.RotateLeft32((((c^d)&b)^d)+a+x0+0xd76aa478, 7)
+ d = a + bits.RotateLeft32((((b^c)&a)^c)+d+x1+0xe8c7b756, 12)
+ c = d + bits.RotateLeft32((((a^b)&d)^b)+c+x2+0x242070db, 17)
+ b = c + bits.RotateLeft32((((d^a)&c)^a)+b+x3+0xc1bdceee, 22)
+ a = b + bits.RotateLeft32((((c^d)&b)^d)+a+x4+0xf57c0faf, 7)
+ d = a + bits.RotateLeft32((((b^c)&a)^c)+d+x5+0x4787c62a, 12)
+ c = d + bits.RotateLeft32((((a^b)&d)^b)+c+x6+0xa8304613, 17)
+ b = c + bits.RotateLeft32((((d^a)&c)^a)+b+x7+0xfd469501, 22)
+ a = b + bits.RotateLeft32((((c^d)&b)^d)+a+x8+0x698098d8, 7)
+ d = a + bits.RotateLeft32((((b^c)&a)^c)+d+x9+0x8b44f7af, 12)
+ c = d + bits.RotateLeft32((((a^b)&d)^b)+c+xa+0xffff5bb1, 17)
+ b = c + bits.RotateLeft32((((d^a)&c)^a)+b+xb+0x895cd7be, 22)
+ a = b + bits.RotateLeft32((((c^d)&b)^d)+a+xc+0x6b901122, 7)
+ d = a + bits.RotateLeft32((((b^c)&a)^c)+d+xd+0xfd987193, 12)
+ c = d + bits.RotateLeft32((((a^b)&d)^b)+c+xe+0xa679438e, 17)
+ b = c + bits.RotateLeft32((((d^a)&c)^a)+b+xf+0x49b40821, 22)
+
+ // round 2
+ a = b + bits.RotateLeft32((((b^c)&d)^c)+a+x1+0xf61e2562, 5)
+ d = a + bits.RotateLeft32((((a^b)&c)^b)+d+x6+0xc040b340, 9)
+ c = d + bits.RotateLeft32((((d^a)&b)^a)+c+xb+0x265e5a51, 14)
+ b = c + bits.RotateLeft32((((c^d)&a)^d)+b+x0+0xe9b6c7aa, 20)
+ a = b + bits.RotateLeft32((((b^c)&d)^c)+a+x5+0xd62f105d, 5)
+ d = a + bits.RotateLeft32((((a^b)&c)^b)+d+xa+0x02441453, 9)
+ c = d + bits.RotateLeft32((((d^a)&b)^a)+c+xf+0xd8a1e681, 14)
+ b = c + bits.RotateLeft32((((c^d)&a)^d)+b+x4+0xe7d3fbc8, 20)
+ a = b + bits.RotateLeft32((((b^c)&d)^c)+a+x9+0x21e1cde6, 5)
+ d = a + bits.RotateLeft32((((a^b)&c)^b)+d+xe+0xc33707d6, 9)
+ c = d + bits.RotateLeft32((((d^a)&b)^a)+c+x3+0xf4d50d87, 14)
+ b = c + bits.RotateLeft32((((c^d)&a)^d)+b+x8+0x455a14ed, 20)
+ a = b + bits.RotateLeft32((((b^c)&d)^c)+a+xd+0xa9e3e905, 5)
+ d = a + bits.RotateLeft32((((a^b)&c)^b)+d+x2+0xfcefa3f8, 9)
+ c = d + bits.RotateLeft32((((d^a)&b)^a)+c+x7+0x676f02d9, 14)
+ b = c + bits.RotateLeft32((((c^d)&a)^d)+b+xc+0x8d2a4c8a, 20)
+
+ // round 3
+ a = b + bits.RotateLeft32((b^c^d)+a+x5+0xfffa3942, 4)
+ d = a + bits.RotateLeft32((a^b^c)+d+x8+0x8771f681, 11)
+ c = d + bits.RotateLeft32((d^a^b)+c+xb+0x6d9d6122, 16)
+ b = c + bits.RotateLeft32((c^d^a)+b+xe+0xfde5380c, 23)
+ a = b + bits.RotateLeft32((b^c^d)+a+x1+0xa4beea44, 4)
+ d = a + bits.RotateLeft32((a^b^c)+d+x4+0x4bdecfa9, 11)
+ c = d + bits.RotateLeft32((d^a^b)+c+x7+0xf6bb4b60, 16)
+ b = c + bits.RotateLeft32((c^d^a)+b+xa+0xbebfbc70, 23)
+ a = b + bits.RotateLeft32((b^c^d)+a+xd+0x289b7ec6, 4)
+ d = a + bits.RotateLeft32((a^b^c)+d+x0+0xeaa127fa, 11)
+ c = d + bits.RotateLeft32((d^a^b)+c+x3+0xd4ef3085, 16)
+ b = c + bits.RotateLeft32((c^d^a)+b+x6+0x04881d05, 23)
+ a = b + bits.RotateLeft32((b^c^d)+a+x9+0xd9d4d039, 4)
+ d = a + bits.RotateLeft32((a^b^c)+d+xc+0xe6db99e5, 11)
+ c = d + bits.RotateLeft32((d^a^b)+c+xf+0x1fa27cf8, 16)
+ b = c + bits.RotateLeft32((c^d^a)+b+x2+0xc4ac5665, 23)
+
+ // round 4
+ a = b + bits.RotateLeft32((c^(b|^d))+a+x0+0xf4292244, 6)
+ d = a + bits.RotateLeft32((b^(a|^c))+d+x7+0x432aff97, 10)
+ c = d + bits.RotateLeft32((a^(d|^b))+c+xe+0xab9423a7, 15)
+ b = c + bits.RotateLeft32((d^(c|^a))+b+x5+0xfc93a039, 21)
+ a = b + bits.RotateLeft32((c^(b|^d))+a+xc+0x655b59c3, 6)
+ d = a + bits.RotateLeft32((b^(a|^c))+d+x3+0x8f0ccc92, 10)
+ c = d + bits.RotateLeft32((a^(d|^b))+c+xa+0xffeff47d, 15)
+ b = c + bits.RotateLeft32((d^(c|^a))+b+x1+0x85845dd1, 21)
+ a = b + bits.RotateLeft32((c^(b|^d))+a+x8+0x6fa87e4f, 6)
+ d = a + bits.RotateLeft32((b^(a|^c))+d+xf+0xfe2ce6e0, 10)
+ c = d + bits.RotateLeft32((a^(d|^b))+c+x6+0xa3014314, 15)
+ b = c + bits.RotateLeft32((d^(c|^a))+b+xd+0x4e0811a1, 21)
+ a = b + bits.RotateLeft32((c^(b|^d))+a+x4+0xf7537e82, 6)
+ d = a + bits.RotateLeft32((b^(a|^c))+d+xb+0xbd3af235, 10)
+ c = d + bits.RotateLeft32((a^(d|^b))+c+x2+0x2ad7d2bb, 15)
+ b = c + bits.RotateLeft32((d^(c|^a))+b+x9+0xeb86d391, 21)
+
+ // add saved state
a += aa
b += bb
c += cc
d += dd
-
- p = p[chunk:]
}
- dig.s[0] = a
- dig.s[1] = b
- dig.s[2] = c
- dig.s[3] = d
+ // save state
+ dig.s[0], dig.s[1], dig.s[2], dig.s[3] = a, b, c, d
}
diff --git a/libgo/go/crypto/md5/md5block_decl.go b/libgo/go/crypto/md5/md5block_decl.go
index 5f9d7aba487..761398f38e9 100644
--- a/libgo/go/crypto/md5/md5block_decl.go
+++ b/libgo/go/crypto/md5/md5block_decl.go
@@ -3,10 +3,12 @@
// license that can be found in the LICENSE file.
// +build ignore
-// -build amd64 amd64p32 386 arm ppc64le s390x arm64
+// +build amd64 amd64p32 386 arm ppc64le ppc64 s390x arm64
package md5
+const haveAsm = true
+
//go:noescape
func block(dig *digest, p []byte)
diff --git a/libgo/go/crypto/md5/md5block_generic.go b/libgo/go/crypto/md5/md5block_generic.go
index c580bc6d094..69c4456a4bd 100644
--- a/libgo/go/crypto/md5/md5block_generic.go
+++ b/libgo/go/crypto/md5/md5block_generic.go
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// -build !amd64,!amd64p32,!386,!arm,!ppc64le,!s390x,!arm64
+// -build !amd64,!amd64p32,!386,!arm,!ppc64le,!ppc64,!s390x,!arm64
package md5
+const haveAsm = false
+
var block = blockGeneric