summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/sha1
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/crypto/sha1')
-rw-r--r--src/pkg/crypto/sha1/example_test.go9
-rw-r--r--src/pkg/crypto/sha1/sha1.go10
-rw-r--r--src/pkg/crypto/sha1/sha1_test.go27
-rw-r--r--src/pkg/crypto/sha1/sha1block.go10
-rw-r--r--src/pkg/crypto/sha1/sha1block_386.s10
-rw-r--r--src/pkg/crypto/sha1/sha1block_amd64.s10
-rw-r--r--src/pkg/crypto/sha1/sha1block_amd64p32.s216
-rw-r--r--src/pkg/crypto/sha1/sha1block_arm.s217
-rw-r--r--src/pkg/crypto/sha1/sha1block_decl.go2
-rw-r--r--src/pkg/crypto/sha1/sha1block_generic.go9
10 files changed, 491 insertions, 29 deletions
diff --git a/src/pkg/crypto/sha1/example_test.go b/src/pkg/crypto/sha1/example_test.go
index 25fe5f308..42aec8afa 100644
--- a/src/pkg/crypto/sha1/example_test.go
+++ b/src/pkg/crypto/sha1/example_test.go
@@ -12,7 +12,14 @@ import (
func ExampleNew() {
h := sha1.New()
- io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
+ io.WriteString(h, "His money is twice tainted:")
+ io.WriteString(h, " 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))
// Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
}
+
+func ExampleSum() {
+ data := []byte("This page intentionally left blank.")
+ fmt.Printf("% x", sha1.Sum(data))
+ // Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96
+}
diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go
index 8eb3f7a79..9f1a96e36 100644
--- a/src/pkg/crypto/sha1/sha1.go
+++ b/src/pkg/crypto/sha1/sha1.go
@@ -62,16 +62,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
- n := len(p)
- if n > chunk-d.nx {
- n = chunk - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
+ n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
- block(d, d.x[0:])
+ block(d, d.x[:])
d.nx = 0
}
p = p[n:]
diff --git a/src/pkg/crypto/sha1/sha1_test.go b/src/pkg/crypto/sha1/sha1_test.go
index c3868d702..4a629518b 100644
--- a/src/pkg/crypto/sha1/sha1_test.go
+++ b/src/pkg/crypto/sha1/sha1_test.go
@@ -7,6 +7,7 @@
package sha1
import (
+ "crypto/rand"
"fmt"
"io"
"testing"
@@ -76,6 +77,32 @@ func TestGolden(t *testing.T) {
}
}
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+ }
+}
+
+// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+func TestBlockGeneric(t *testing.T) {
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*20) // arbitrary factor
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Error("block and blockGeneric resulted in different states")
+ }
+}
+
var bench = New()
var buf = make([]byte, 8192)
diff --git a/src/pkg/crypto/sha1/sha1block.go b/src/pkg/crypto/sha1/sha1block.go
index 92224fc0e..fde3c981c 100644
--- a/src/pkg/crypto/sha1/sha1block.go
+++ b/src/pkg/crypto/sha1/sha1block.go
@@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!386
-
-// SHA1 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
package sha1
const (
@@ -17,7 +11,9 @@ const (
_K3 = 0xCA62C1D6
)
-func block(dig *digest, p []byte) {
+// blockGeneric is a portable, pure Go version of the SHA1 block step.
+// It's used by sha1block_generic.go and tests.
+func blockGeneric(dig *digest, p []byte) {
var w [16]uint32
h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
diff --git a/src/pkg/crypto/sha1/sha1block_386.s b/src/pkg/crypto/sha1/sha1block_386.s
index 890b3ae81..688851c31 100644
--- a/src/pkg/crypto/sha1/sha1block_386.s
+++ b/src/pkg/crypto/sha1/sha1block_386.s
@@ -46,12 +46,10 @@
ADDL DI, e
#define FUNC1(a, b, c, d, e) \
- MOVL b, SI; \
- ANDL c, SI; \
- MOVL b, DI; \
- NOTL DI; \
- ANDL d, DI; \
- ORL SI, DI
+ MOVL d, DI; \
+ XORL c, DI; \
+ ANDL b, DI; \
+ XORL d, DI
#define FUNC2(a, b, c, d, e) \
MOVL b, DI; \
diff --git a/src/pkg/crypto/sha1/sha1block_amd64.s b/src/pkg/crypto/sha1/sha1block_amd64.s
index 0bb6c204c..8ffb9d5d6 100644
--- a/src/pkg/crypto/sha1/sha1block_amd64.s
+++ b/src/pkg/crypto/sha1/sha1block_amd64.s
@@ -34,12 +34,10 @@
MOVL R10, (((index)&0xf)*4)(SP)
#define FUNC1(a, b, c, d, e) \
- MOVL b, R8; \
- ANDL c, R8; \
- MOVL b, R9; \
- NOTL R9; \
- ANDL d, R9; \
- ORL R8, R9
+ MOVL d, R9; \
+ XORL c, R9; \
+ ANDL b, R9; \
+ XORL d, R9
#define FUNC2(a, b, c, d, e) \
MOVL b, R9; \
diff --git a/src/pkg/crypto/sha1/sha1block_amd64p32.s b/src/pkg/crypto/sha1/sha1block_amd64p32.s
new file mode 100644
index 000000000..3c589d94f
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_amd64p32.s
@@ -0,0 +1,216 @@
+// 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.
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+//
+// amd64p32 version.
+// To ensure safety for Native Client, avoids use of BP and R15
+// as well as two-register addressing modes.
+
+#define LOAD(index) \
+ MOVL (index*4)(SI), R10; \
+ BSWAPL R10; \
+ MOVL R10, (index*4)(SP)
+
+#define SHUFFLE(index) \
+ MOVL (((index)&0xf)*4)(SP), R10; \
+ XORL (((index-3)&0xf)*4)(SP), R10; \
+ XORL (((index-8)&0xf)*4)(SP), R10; \
+ XORL (((index-14)&0xf)*4)(SP), R10; \
+ ROLL $1, R10; \
+ MOVL R10, (((index)&0xf)*4)(SP)
+
+#define FUNC1(a, b, c, d, e) \
+ MOVL d, R9; \
+ XORL c, R9; \
+ ANDL b, R9; \
+ XORL d, R9
+
+#define FUNC2(a, b, c, d, e) \
+ MOVL b, R9; \
+ XORL c, R9; \
+ XORL d, R9
+
+#define FUNC3(a, b, c, d, e) \
+ MOVL b, R8; \
+ ORL c, R8; \
+ ANDL d, R8; \
+ MOVL b, R9; \
+ ANDL c, R9; \
+ ORL R8, R9
+
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+ ROLL $30, b; \
+ ADDL R9, e; \
+ MOVL a, R8; \
+ ROLL $5, R8; \
+ LEAL const(e)(R10*1), e; \
+ ADDL R8, e
+
+#define ROUND1(a, b, c, d, e, index) \
+ LOAD(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC2(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC3(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC4(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0xCA62C1D6)
+
+TEXT ·block(SB),NOSPLIT,$64-32
+ MOVL dig+0(FP), R14
+ MOVL p_base+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(R14), AX
+ MOVL (1*4)(R14), BX
+ MOVL (2*4)(R14), CX
+ MOVL (3*4)(R14), DX
+ MOVL (4*4)(R14), R13
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+#define BP R13 /* keep diff from sha1block_amd64.s small */
+ ROUND1(AX, BX, CX, DX, BP, 0)
+ ROUND1(BP, AX, BX, CX, DX, 1)
+ ROUND1(DX, BP, AX, BX, CX, 2)
+ ROUND1(CX, DX, BP, AX, BX, 3)
+ ROUND1(BX, CX, DX, BP, AX, 4)
+ ROUND1(AX, BX, CX, DX, BP, 5)
+ ROUND1(BP, AX, BX, CX, DX, 6)
+ ROUND1(DX, BP, AX, BX, CX, 7)
+ ROUND1(CX, DX, BP, AX, BX, 8)
+ ROUND1(BX, CX, DX, BP, AX, 9)
+ ROUND1(AX, BX, CX, DX, BP, 10)
+ ROUND1(BP, AX, BX, CX, DX, 11)
+ ROUND1(DX, BP, AX, BX, CX, 12)
+ ROUND1(CX, DX, BP, AX, BX, 13)
+ ROUND1(BX, CX, DX, BP, AX, 14)
+ ROUND1(AX, BX, CX, DX, BP, 15)
+
+ ROUND1x(BP, AX, BX, CX, DX, 16)
+ ROUND1x(DX, BP, AX, BX, CX, 17)
+ ROUND1x(CX, DX, BP, AX, BX, 18)
+ ROUND1x(BX, CX, DX, BP, AX, 19)
+
+ ROUND2(AX, BX, CX, DX, BP, 20)
+ ROUND2(BP, AX, BX, CX, DX, 21)
+ ROUND2(DX, BP, AX, BX, CX, 22)
+ ROUND2(CX, DX, BP, AX, BX, 23)
+ ROUND2(BX, CX, DX, BP, AX, 24)
+ ROUND2(AX, BX, CX, DX, BP, 25)
+ ROUND2(BP, AX, BX, CX, DX, 26)
+ ROUND2(DX, BP, AX, BX, CX, 27)
+ ROUND2(CX, DX, BP, AX, BX, 28)
+ ROUND2(BX, CX, DX, BP, AX, 29)
+ ROUND2(AX, BX, CX, DX, BP, 30)
+ ROUND2(BP, AX, BX, CX, DX, 31)
+ ROUND2(DX, BP, AX, BX, CX, 32)
+ ROUND2(CX, DX, BP, AX, BX, 33)
+ ROUND2(BX, CX, DX, BP, AX, 34)
+ ROUND2(AX, BX, CX, DX, BP, 35)
+ ROUND2(BP, AX, BX, CX, DX, 36)
+ ROUND2(DX, BP, AX, BX, CX, 37)
+ ROUND2(CX, DX, BP, AX, BX, 38)
+ ROUND2(BX, CX, DX, BP, AX, 39)
+
+ ROUND3(AX, BX, CX, DX, BP, 40)
+ ROUND3(BP, AX, BX, CX, DX, 41)
+ ROUND3(DX, BP, AX, BX, CX, 42)
+ ROUND3(CX, DX, BP, AX, BX, 43)
+ ROUND3(BX, CX, DX, BP, AX, 44)
+ ROUND3(AX, BX, CX, DX, BP, 45)
+ ROUND3(BP, AX, BX, CX, DX, 46)
+ ROUND3(DX, BP, AX, BX, CX, 47)
+ ROUND3(CX, DX, BP, AX, BX, 48)
+ ROUND3(BX, CX, DX, BP, AX, 49)
+ ROUND3(AX, BX, CX, DX, BP, 50)
+ ROUND3(BP, AX, BX, CX, DX, 51)
+ ROUND3(DX, BP, AX, BX, CX, 52)
+ ROUND3(CX, DX, BP, AX, BX, 53)
+ ROUND3(BX, CX, DX, BP, AX, 54)
+ ROUND3(AX, BX, CX, DX, BP, 55)
+ ROUND3(BP, AX, BX, CX, DX, 56)
+ ROUND3(DX, BP, AX, BX, CX, 57)
+ ROUND3(CX, DX, BP, AX, BX, 58)
+ ROUND3(BX, CX, DX, BP, AX, 59)
+
+ ROUND4(AX, BX, CX, DX, BP, 60)
+ ROUND4(BP, AX, BX, CX, DX, 61)
+ ROUND4(DX, BP, AX, BX, CX, 62)
+ ROUND4(CX, DX, BP, AX, BX, 63)
+ ROUND4(BX, CX, DX, BP, AX, 64)
+ ROUND4(AX, BX, CX, DX, BP, 65)
+ ROUND4(BP, AX, BX, CX, DX, 66)
+ ROUND4(DX, BP, AX, BX, CX, 67)
+ ROUND4(CX, DX, BP, AX, BX, 68)
+ ROUND4(BX, CX, DX, BP, AX, 69)
+ ROUND4(AX, BX, CX, DX, BP, 70)
+ ROUND4(BP, AX, BX, CX, DX, 71)
+ ROUND4(DX, BP, AX, BX, CX, 72)
+ ROUND4(CX, DX, BP, AX, BX, 73)
+ ROUND4(BX, CX, DX, BP, AX, 74)
+ ROUND4(AX, BX, CX, DX, BP, 75)
+ ROUND4(BP, AX, BX, CX, DX, 76)
+ ROUND4(DX, BP, AX, BX, CX, 77)
+ ROUND4(CX, DX, BP, AX, BX, 78)
+ ROUND4(BX, CX, DX, BP, AX, 79)
+#undef BP
+
+ ADDL (0*4)(R14), AX
+ ADDL (1*4)(R14), BX
+ ADDL (2*4)(R14), CX
+ ADDL (3*4)(R14), DX
+ ADDL (4*4)(R14), R13
+
+ MOVL AX, (0*4)(R14)
+ MOVL BX, (1*4)(R14)
+ MOVL CX, (2*4)(R14)
+ MOVL DX, (3*4)(R14)
+ MOVL R13, (4*4)(R14)
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ RET
diff --git a/src/pkg/crypto/sha1/sha1block_arm.s b/src/pkg/crypto/sha1/sha1block_arm.s
new file mode 100644
index 000000000..5917e8b24
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_arm.s
@@ -0,0 +1,217 @@
+// Copyright 2014 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.
+//
+// ARM version of md5block.go
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+// Register definitions
+data = 0 // Pointer to incoming data
+const = 1 // Current constant for SHA round
+a = 2 // SHA1 accumulator
+b = 3 // SHA1 accumulator
+c = 4 // SHA1 accumulator
+d = 5 // SHA1 accumulator
+e = 6 // SHA1 accumulator
+t0 = 7 // Temporary
+t1 = 8 // Temporary
+// r9, r10 are forbidden
+// r11 is OK provided you check the assembler that no synthetic instructions use it
+t2 = 11 // Temporary
+ctr = 12 // loop counter
+w = 14 // point to w buffer
+
+// func block(dig *digest, p []byte)
+// 0(FP) is *digest
+// 4(FP) is p.array (struct Slice)
+// 8(FP) is p.len
+//12(FP) is p.cap
+//
+// Stack frame
+p_end = -4 // -4(SP) pointer to the end of data
+p_data = p_end - 4 // -8(SP) current data pointer
+w_buf = p_data - 4*80 // -328(SP) 80 words temporary buffer w uint32[80]
+saved = w_buf - 4*5 // -348(SP) saved sha1 registers a,b,c,d,e - these must be last
+// Total size +4 for saved LR is 352
+
+ // w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3]
+ // e += w[i]
+#define LOAD(e) \
+ MOVBU 2(R(data)), R(t0) ; \
+ MOVBU 3(R(data)), R(t1) ; \
+ MOVBU 1(R(data)), R(t2) ; \
+ ORR R(t0)<<8, R(t1), R(t0) ; \
+ MOVBU.P 4(R(data)), R(t1) ; \
+ ORR R(t2)<<16, R(t0), R(t0) ; \
+ ORR R(t1)<<24, R(t0), R(t0) ; \
+ MOVW.P R(t0), 4(R(w)) ; \
+ ADD R(t0), R(e), R(e)
+
+ // tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+ // w[i&0xf] = tmp<<1 | tmp>>(32-1)
+ // e += w[i&0xf]
+#define SHUFFLE(e) \
+ MOVW (-16*4)(R(w)), R(t0) ; \
+ MOVW (-14*4)(R(w)), R(t1) ; \
+ MOVW (-8*4)(R(w)), R(t2) ; \
+ EOR R(t0), R(t1), R(t0) ; \
+ MOVW (-3*4)(R(w)), R(t1) ; \
+ EOR R(t2), R(t0), R(t0) ; \
+ EOR R(t0), R(t1), R(t0) ; \
+ MOVW R(t0)@>(32-1), R(t0) ; \
+ MOVW.P R(t0), 4(R(w)) ; \
+ ADD R(t0), R(e), R(e)
+
+ // t1 = (b & c) | ((~b) & d)
+#define FUNC1(a, b, c, d, e) \
+ MVN R(b), R(t1) ; \
+ AND R(b), R(c), R(t0) ; \
+ AND R(d), R(t1), R(t1) ; \
+ ORR R(t0), R(t1), R(t1)
+
+ // t1 = b ^ c ^ d
+#define FUNC2(a, b, c, d, e) \
+ EOR R(b), R(c), R(t1) ; \
+ EOR R(d), R(t1), R(t1)
+
+ // t1 = (b & c) | (b & d) | (c & d) =
+ // t1 = (b & c) | ((b | c) & d)
+#define FUNC3(a, b, c, d, e) \
+ ORR R(b), R(c), R(t0) ; \
+ AND R(b), R(c), R(t1) ; \
+ AND R(d), R(t0), R(t0) ; \
+ ORR R(t0), R(t1), R(t1)
+
+#define FUNC4 FUNC2
+
+ // a5 := a<<5 | a>>(32-5)
+ // b = b<<30 | b>>(32-30)
+ // e = a5 + t1 + e + const
+#define MIX(a, b, c, d, e) \
+ ADD R(t1), R(e), R(e) ; \
+ MOVW R(b)@>(32-30), R(b) ; \
+ ADD R(a)@>(32-5), R(e), R(e) ; \
+ ADD R(const), R(e), R(e)
+
+#define ROUND1(a, b, c, d, e) \
+ LOAD(e) ; \
+ FUNC1(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND1x(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC1(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND2(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC2(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND3(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC3(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+#define ROUND4(a, b, c, d, e) \
+ SHUFFLE(e) ; \
+ FUNC4(a, b, c, d, e) ; \
+ MIX(a, b, c, d, e)
+
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB), 0, $352-16
+ MOVW p+4(FP), R(data) // pointer to the data
+ MOVW p_len+8(FP), R(t0) // number of bytes
+ ADD R(data), R(t0)
+ MOVW R(t0), p_end(SP) // pointer to end of data
+
+ // Load up initial SHA1 accumulator
+ MOVW dig+0(FP), R(t0)
+ MOVM.IA (R(t0)), [R(a),R(b),R(c),R(d),R(e)]
+
+loop:
+ // Save registers at SP+4 onwards
+ MOVM.IB [R(a),R(b),R(c),R(d),R(e)], (R13)
+
+ MOVW $w_buf(SP), R(w)
+ MOVW $0x5A827999, R(const)
+ MOVW $3, R(ctr)
+loop1: ROUND1(a, b, c, d, e)
+ ROUND1(e, a, b, c, d)
+ ROUND1(d, e, a, b, c)
+ ROUND1(c, d, e, a, b)
+ ROUND1(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop1
+
+ ROUND1(a, b, c, d, e)
+ ROUND1x(e, a, b, c, d)
+ ROUND1x(d, e, a, b, c)
+ ROUND1x(c, d, e, a, b)
+ ROUND1x(b, c, d, e, a)
+
+ MOVW $0x6ED9EBA1, R(const)
+ MOVW $4, R(ctr)
+loop2: ROUND2(a, b, c, d, e)
+ ROUND2(e, a, b, c, d)
+ ROUND2(d, e, a, b, c)
+ ROUND2(c, d, e, a, b)
+ ROUND2(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop2
+
+ MOVW $0x8F1BBCDC, R(const)
+ MOVW $4, R(ctr)
+loop3: ROUND3(a, b, c, d, e)
+ ROUND3(e, a, b, c, d)
+ ROUND3(d, e, a, b, c)
+ ROUND3(c, d, e, a, b)
+ ROUND3(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop3
+
+ MOVW $0xCA62C1D6, R(const)
+ MOVW $4, R(ctr)
+loop4: ROUND4(a, b, c, d, e)
+ ROUND4(e, a, b, c, d)
+ ROUND4(d, e, a, b, c)
+ ROUND4(c, d, e, a, b)
+ ROUND4(b, c, d, e, a)
+ SUB.S $1, R(ctr)
+ BNE loop4
+
+ // Accumulate - restoring registers from SP+4
+ MOVM.IB (R13), [R(t0),R(t1),R(t2),R(ctr),R(w)]
+ ADD R(t0), R(a)
+ ADD R(t1), R(b)
+ ADD R(t2), R(c)
+ ADD R(ctr), R(d)
+ ADD R(w), R(e)
+
+ MOVW p_end(SP), R(t0)
+ CMP R(t0), R(data)
+ BLO loop
+
+ // Save final SHA1 accumulator
+ MOVW dig+0(FP), R(t0)
+ MOVM.IA [R(a),R(b),R(c),R(d),R(e)], (R(t0))
+
+ RET
diff --git a/src/pkg/crypto/sha1/sha1block_decl.go b/src/pkg/crypto/sha1/sha1block_decl.go
index 4cb157fff..24e521af1 100644
--- a/src/pkg/crypto/sha1/sha1block_decl.go
+++ b/src/pkg/crypto/sha1/sha1block_decl.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.
-// +build amd64 386
+// +build amd64 amd64p32 arm 386
package sha1
diff --git a/src/pkg/crypto/sha1/sha1block_generic.go b/src/pkg/crypto/sha1/sha1block_generic.go
new file mode 100644
index 000000000..696e26b62
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_generic.go
@@ -0,0 +1,9 @@
+// Copyright 2014 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.
+
+// +build !amd64,!amd64p32,!386,!arm
+
+package sha1
+
+var block = blockGeneric