From 525ae3f897bf79fd78f3e693bd65056efc8f9109 Mon Sep 17 00:00:00 2001 From: Michael Munday Date: Mon, 25 Apr 2016 17:58:34 -0400 Subject: [PATCH] crypto/sha256: add s390x assembly implementation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Renames block to blockGeneric so that it can be called when the assembly feature check fails. This means making block a var on platforms without an assembly implementation (similar to the sha1 package). Also adds a test to check that the fallback path works correctly when the feature check fails. name old speed new speed delta Hash8Bytes 6.42MB/s ± 1% 27.14MB/s ± 0% +323.01% (p=0.000 n=10+10) Hash1K 53.9MB/s ± 0% 511.1MB/s ± 0% +847.57% (p=0.000 n=10+9) Hash8K 57.1MB/s ± 1% 609.7MB/s ± 0% +967.04% (p=0.000 n=10+10) Change-Id: If962b2a5c9160b3a0b76ccee53b2fd809468ed3d Reviewed-on: https://go-review.googlesource.com/22460 Run-TryBot: Michael Munday TryBot-Result: Gobot Gobot Reviewed-by: Bill O'Farrell Reviewed-by: Brad Fitzpatrick --- src/crypto/sha256/fallback_test.go | 35 ++++++++++++++++++++++++ src/crypto/sha256/sha256_test.go | 13 +++++++++ src/crypto/sha256/sha256block.go | 4 +-- src/crypto/sha256/sha256block_decl.go | 2 +- src/crypto/sha256/sha256block_generic.go | 9 ++++++ src/crypto/sha256/sha256block_s390x.go | 12 ++++++++ src/crypto/sha256/sha256block_s390x.s | 34 +++++++++++++++++++++++ 7 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/crypto/sha256/fallback_test.go create mode 100644 src/crypto/sha256/sha256block_generic.go create mode 100644 src/crypto/sha256/sha256block_s390x.go create mode 100644 src/crypto/sha256/sha256block_s390x.s diff --git a/src/crypto/sha256/fallback_test.go b/src/crypto/sha256/fallback_test.go new file mode 100644 index 0000000000..5917a4862a --- /dev/null +++ b/src/crypto/sha256/fallback_test.go @@ -0,0 +1,35 @@ +// Copyright 2016 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 s390x + +package sha256 + +import ( + "fmt" + "io" + "testing" +) + +// Tests the fallback code path in case the optimized asm +// implementation cannot be used. +// See also TestBlockGeneric. +func TestGenericPath(t *testing.T) { + if useAsm == false { + t.Skipf("assembly implementation unavailable") + } + useAsm = false + defer func() { useAsm = true }() + c := New() + in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ" + gold := "e93d84ec2b22383123be9f713697fb25" + + "338c86e2f7d8d1ddc2d89d332dd9d76c" + if _, err := io.WriteString(c, in); err != nil { + t.Fatalf("could not write to c: %v", err) + } + out := fmt.Sprintf("%x", c.Sum(nil)) + if out != gold { + t.Fatalf("mismatch: got %s, wanted %s", out, gold) + } +} diff --git a/src/crypto/sha256/sha256_test.go b/src/crypto/sha256/sha256_test.go index 9ac8a96dfc..279cf5ad40 100644 --- a/src/crypto/sha256/sha256_test.go +++ b/src/crypto/sha256/sha256_test.go @@ -7,6 +7,7 @@ package sha256 import ( + "crypto/rand" "fmt" "io" "testing" @@ -150,6 +151,18 @@ func TestBlockSize(t *testing.T) { } } +// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) 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/crypto/sha256/sha256block.go b/src/crypto/sha256/sha256block.go index ca5efd156a..d43bbf0245 100644 --- a/src/crypto/sha256/sha256block.go +++ b/src/crypto/sha256/sha256block.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !386,!amd64 - // SHA256 block step. // In its own file so that a faster assembly or C version // can be substituted easily. @@ -77,7 +75,7 @@ var _K = []uint32{ 0xc67178f2, } -func block(dig *digest, p []byte) { +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 { diff --git a/src/crypto/sha256/sha256block_decl.go b/src/crypto/sha256/sha256block_decl.go index 35fe34b98a..e6caff9a74 100644 --- a/src/crypto/sha256/sha256block_decl.go +++ b/src/crypto/sha256/sha256block_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 386 amd64 +// +build 386 amd64 s390x package sha256 diff --git a/src/crypto/sha256/sha256block_generic.go b/src/crypto/sha256/sha256block_generic.go new file mode 100644 index 0000000000..1a01969b0d --- /dev/null +++ b/src/crypto/sha256/sha256block_generic.go @@ -0,0 +1,9 @@ +// Copyright 2016 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,!386,!s390x + +package sha256 + +var block = blockGeneric diff --git a/src/crypto/sha256/sha256block_s390x.go b/src/crypto/sha256/sha256block_s390x.go new file mode 100644 index 0000000000..b7beefef0c --- /dev/null +++ b/src/crypto/sha256/sha256block_s390x.go @@ -0,0 +1,12 @@ +// Copyright 2016 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. + +package sha256 + +// featureCheck reports whether the CPU supports the +// SHA256 compute intermediate message digest (KIMD) +// function code. +func featureCheck() bool + +var useAsm = featureCheck() diff --git a/src/crypto/sha256/sha256block_s390x.s b/src/crypto/sha256/sha256block_s390x.s new file mode 100644 index 0000000000..ee35991f50 --- /dev/null +++ b/src/crypto/sha256/sha256block_s390x.s @@ -0,0 +1,34 @@ +// Copyright 2016 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 "textflag.h" + +// func featureCheck() bool +TEXT ·featureCheck(SB),NOSPLIT,$16-1 + LA tmp-16(SP), R1 + XOR R0, R0 // query function code is 0 + WORD $0xB93E0006 // KIMD (R6 is ignored) + MOVBZ tmp-16(SP), R4 // get the first byte + AND $0x20, R4 // bit 2 (big endian) for SHA256 + CMPBEQ R4, $0, nosha256 + MOVB $1, ret+0(FP) + RET +nosha256: + MOVB $0, ret+0(FP) + RET + +// func block(dig *digest, p []byte) +TEXT ·block(SB),NOSPLIT,$0-32 + MOVBZ ·useAsm(SB), R4 + LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) + CMPBNE R4, $1, generic + MOVBZ $2, R0 // SHA256 function code +loop: + WORD $0xB93E0002 // KIMD R2 + BVS loop // continue if interrupted +done: + XOR R0, R0 // restore R0 + RET +generic: + BR ·blockGeneric(SB) -- 2.48.1