aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
authorRuixin Bao <ruixin.bao@ibm.com>2020-09-29 15:55:19 -0400
committerMichael Munday <mike.munday@ibm.com>2020-09-30 15:32:53 +0000
commit54a112d7197ec320527614e7502a3243eab93b6e (patch)
tree4f46ef5b992656eb57975a57712edce3e7d41cdf /src/crypto
parent8b0d00b1645c47076f5b20dc692b2ca6d9bac19b (diff)
downloadgo-54a112d7197ec320527614e7502a3243eab93b6e.tar.gz
go-54a112d7197ec320527614e7502a3243eab93b6e.zip
crypto/ecdsa: use FillBytes on s390x
Originally, zeroExtendAndCopy is used to pad src with leading zeros and copy the padded src into the destination. It is no longer needed after CL 230397 introduced FillBytes. We can simply use that and remove the zeroExtendAndCopy function. It is cleaner and reduces some allocation. In addition, this patch tries to avoid calling hashToInt function in both Sign and Verify function so some allocation is reduced. Benchmarks: name old alloc/op new alloc/op delta SignP256-8 1.60kB ± 0% 1.49kB ± 0% -7.23% (p=0.000 n=20+20) SignP384-8 1.74kB ± 0% 1.59kB ± 0% -8.50% (p=0.000 n=20+18) VerifyP256-8 176B ± 0% 0B -100.00% (p=0.000 n=20+20) KeyGeneration-8 640B ± 0% 640B ± 0% ~ (all equal) name old allocs/op new allocs/op delta SignP256-8 22.0 ± 0% 17.0 ± 0% -22.73% (p=0.000 n=20+20) SignP384-8 22.0 ± 0% 17.0 ± 0% -22.73% (p=0.000 n=20+20) VerifyP256-8 7.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20) KeyGeneration-8 13.0 ± 0% 13.0 ± 0% ~ (all equal) Change-Id: Ic4c95191eded55deb3420d97db501689f3b173c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/232297 Reviewed-by: Michael Munday <mike.munday@ibm.com> Run-TryBot: Michael Munday <mike.munday@ibm.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Filippo Valsorda <filippo@golang.org>
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/ecdsa/ecdsa_s390x.go59
1 files changed, 27 insertions, 32 deletions
diff --git a/src/crypto/ecdsa/ecdsa_s390x.go b/src/crypto/ecdsa/ecdsa_s390x.go
index d8d2c716db..0a1d73e7a4 100644
--- a/src/crypto/ecdsa/ecdsa_s390x.go
+++ b/src/crypto/ecdsa/ecdsa_s390x.go
@@ -41,26 +41,29 @@ func canUseKDSA(c elliptic.Curve) (functionCode uint64, blockSize int, ok bool)
return 0, 0, false // A mismatch
}
-// zeroExtendAndCopy pads src with leading zeros until it has the size given.
-// It then copies the padded src into the dst. Bytes beyond size in dst are
-// not modified.
-func zeroExtendAndCopy(dst, src []byte, size int) {
- nz := size - len(src)
- if nz < 0 {
- panic("src is too long")
- }
- // the compiler should replace this loop with a memclr call
- z := dst[:nz]
- for i := range z {
- z[i] = 0
+func hashToBytes(dst, hash []byte, c elliptic.Curve) {
+ l := len(dst)
+ if n := c.Params().N.BitLen(); n == l*8 {
+ // allocation free path for curves with a length that is a whole number of bytes
+ if len(hash) >= l {
+ // truncate hash
+ copy(dst, hash[:l])
+ return
+ }
+ // pad hash with leading zeros
+ p := l - len(hash)
+ for i := 0; i < p; i++ {
+ dst[i] = 0
+ }
+ copy(dst[p:], hash)
+ return
}
- copy(dst[nz:size], src[:size-nz])
- return
+ // TODO(mundaym): avoid hashToInt call here
+ hashToInt(hash, c).FillBytes(dst)
}
func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) {
if functionCode, blockSize, ok := canUseKDSA(c); ok {
- e := hashToInt(hash, c)
for {
var k *big.Int
k, err = randFieldElement(c, *csprng)
@@ -89,17 +92,12 @@ func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash
// different curves and is set by canUseKDSA function.
var params [4096]byte
- startingOffset := 2 * blockSize // Set the starting location for copying
// Copy content into the parameter block. In the sign case,
// we copy hashed message, private key and random number into
- // the parameter block. Since those are consecutive components in the parameter
- // block, we use a for loop here.
- for i, v := range []*big.Int{e, priv.D, k} {
- startPosition := startingOffset + i*blockSize
- endPosition := startPosition + blockSize
- zeroExtendAndCopy(params[startPosition:endPosition], v.Bytes(), blockSize)
- }
-
+ // the parameter block.
+ hashToBytes(params[2*blockSize:3*blockSize], hash, c)
+ priv.D.FillBytes(params[3*blockSize : 4*blockSize])
+ k.FillBytes(params[4*blockSize : 5*blockSize])
// Convert verify function code into a sign function code by adding 8.
// We also need to set the 'deterministic' bit in the function code, by
// adding 128, in order to stop the instruction using its own random number
@@ -124,7 +122,6 @@ func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash
func verify(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool {
if functionCode, blockSize, ok := canUseKDSA(c); ok {
- e := hashToInt(hash, c)
// The parameter block looks like the following for verify:
// +---------------------+
// | Signature(R) |
@@ -149,13 +146,11 @@ func verify(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool {
// Copy content into the parameter block. In the verify case,
// we copy signature (r), signature(s), hashed message, public key x component,
// and public key y component into the parameter block.
- // Since those are consecutive components in the parameter block, we use a for loop here.
- for i, v := range []*big.Int{r, s, e, pub.X, pub.Y} {
- startPosition := i * blockSize
- endPosition := startPosition + blockSize
- zeroExtendAndCopy(params[startPosition:endPosition], v.Bytes(), blockSize)
- }
-
+ r.FillBytes(params[0*blockSize : 1*blockSize])
+ s.FillBytes(params[1*blockSize : 2*blockSize])
+ hashToBytes(params[2*blockSize:3*blockSize], hash, c)
+ pub.X.FillBytes(params[3*blockSize : 4*blockSize])
+ pub.Y.FillBytes(params[4*blockSize : 5*blockSize])
return kdsa(functionCode, &params) == 0
}
return verifyGeneric(pub, c, hash, r, s)